网友发的一个题“之前遇到一个问题,就是canvas中任意四个点,如何让四个点自动串联成一个封闭图形,并计算其面积”。据说是18k的面试题。
讨论半天,都不如实际做一下。
问题分成两步:
第一步、4个点组成多边形;
第二步、求多边形面积;
其实第二步比较简单,因为求多边形面积算法很成熟,网上一搜就有,照着抄就行了。
第一步比较难。应该是要求组成的多边形是简单多边形,即可以是凸多边形,可以是凹多边形,但是边与边之间不能有交叉。我们需要对4个点进行排序来满足要求。
这个问题可能要用到图论的知识,只是我没系统的学过。
自己想到两种方式:
1、随意找3个点,组成一个三角形[p1,p2,p3],然后根据第四个点p4与三角形的关系,把第四个点插入到三角形中。
2、4个点,总共有6条线,可以分为3组互不相邻的线段,判断一组线段是否相交,如果相交,去掉,刚好剩余4条线,即为4变形的4条边。如果3组都不想交,去掉任意一组都可以(刚好对应方法1中第4个点在三角形内的情况)。
用第二种方式做了个demo,效果如下:
参考:http://blog.csdn.net/rickliuxiao/article/details/6259322
http://www.cnblogs.com/void/archive/2011/04/17/2018729.html
代码:
package {
import flash.display.MovieClip;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.text.TextField;
public class Main extends MovieClip {
public var p1:MovieClip;
public var p2:MovieClip;
public var p3:MovieClip;
public var p4:MovieClip;
public var tf:TextField;
private var curSp:Sprite;
public function Main() {
// constructor code
stage?initStage(null):addEventListener(Event.ADDED_TO_STAGE, initStage);
}
private function initStage(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, initStage);
drag(p1);
drag(p2);
drag(p3);
drag(p4);
tf.mouseEnabled = false;
mouseMoveHandler(null);
//画个网格
drawGrid();
}
private function drawGrid():void {
var shape:Shape = new Shape();
this.addChildAt(shape,0);
shape.graphics.lineStyle(0, 0x000000, 0.6);
var i:int = 0;
for (i = 0; i < stage.stageWidth+10;i+=10 ) {
shape.graphics.moveTo(i, 0);
shape.graphics.lineTo(i, stage.stageHeight);
}
for (i = 0; i < stage.stageHeight+10;i+=10 ) {
shape.graphics.moveTo(0,i);
shape.graphics.lineTo(stage.stageWidth,i);
}
}
private function drag(sp:Sprite):void {
sp.buttonMode = true;
sp.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
}
private function mouseDownHandler(e:MouseEvent):void
{
if (curSp) curSp.stopDrag();
curSp = e.currentTarget as Sprite;
curSp.startDrag();
addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
}
private function mouseUpHandler(e:MouseEvent):void
{
curSp.stopDrag();
curSp = null;
removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
}
private function mouseMoveHandler(e:MouseEvent):void
{
var result:Array = [];
if (detectIntersect(p1,p2,p3,p4)) {
result = [p1, p3, p2, p4];
}
else if (detectIntersect(p1,p3,p2,p4)) {
result = [p1, p2, p3, p4];
}
else if (detectIntersect(p1,p4,p2,p3)) {
result = [p1, p2, p4, p3];
}
else {
result = [p1, p2, p3, p4];
}
graphics.clear();
var colors:Array = [0xff0000,0x00ff00,0x0000ff,0xffff00];
graphics.lineStyle(1, 0xff0000, 1.0);
var i:int = 0;
for (i = 0; i <= 4;i++ ) {
var p:Object = result[i%4];
if (i==0) {
graphics.moveTo(p.x, p.y);
}
else {
graphics.lineStyle(1, colors[i-1], 1.0);
graphics.lineTo(p.x, p.y);
}
}
//
var area:Number = 0;
area = mult(result[0], result[1], result[2]) + mult(result[0], result[2], result[3]);
area = area / 2;
if (area<0) {
area = -area;
}
tf.text = "面积:" + area;
}
private function detectIntersect(aa:Object,bb:Object,cc:Object,dd:Object):Boolean {
if (Math.max(aa.x,bb.x)<Math.min(cc.x,dd.x)) {
return false;
}
if (Math.max(aa.y,bb.y)<Math.min(cc.y,dd.y)) {
return false;
}
if (Math.max(cc.x,dd.x)<Math.min(aa.x,bb.x)) {
return false;
}
if (Math.max(cc.y,dd.y)<Math.min(aa.y,bb.y)) {
return false;
}
if (mult(cc,bb,aa)*mult(bb,dd,aa)<0) {
return false;
}
if (mult(aa,dd,cc)*mult(dd,bb,cc)<0) {
return false;
}
return true;
}
/**
* 叉积。
* @param a
* @param b
* @param c
* @return
*/
private function mult(a:Object,b:Object,c:Object):Number {
return (a.x - c.x) * (b.y - c.y) - (b.x - c.x) * (a.y - c.y);
}
}
}
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。