In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Divide Polygon

Get Adobe Flash player
by Kay 16 Feb 2011
/**
 * Copyright Kay ( http://wonderfl.net/user/Kay )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/y3sg
 */

// 多角形をポリゴンで自動分割してみるTest
// >頂点をドラッグすると計算をはじめます
// ・すべての点を繋ぐ線を描画しています
// ・分割候補となる多角形の中に収まる線は太線
// ・いちばん目立つ線が分割線です。
// ?精度誤差回避したくない
package {
    import flash.display.Sprite;
    import flash.display.Shape;
    import flash.events.Event;
    import flash.geom.Point;
    public class SeparatePolygon extends Sprite {
        private const SW:Number=stage.stageWidth;
        private const SH:Number=stage.stageHeight;
        private const NP:int=13;
        private var commands:Vector.<int>=new Vector.<int>(NP+1,true);
        private var datas:Vector.<Number> = new Vector.<Number>((NP+1)*2,true);
        private var vectors:Vector.<Number>;
        private var outlines:Array;
        private var obj:Shape = new Shape();
        public function SeparatePolygon():void {
            //-----------------------------------------------
            // ポイントで囲まれた図形の形を示す
            addChild(obj);

            //-----------------------------------------------
            // コントロールできるポイントをNP点配置する
            var radian:Number=Math.PI*2/NP;
            for (var i:int=0; i < NP; i++) {
                // 外周点とdrawPathで描くための情報を登録
                var point:DraggablePoint = new DraggablePoint();
                point.x=Math.round(SW/2+100*Math.cos(radian*i));// 精度誤差回避
                point.y=Math.round(SH/2+100*Math.sin(radian*i));// 精度誤差回避
                point.name=i.toString();
                point.addEventListener("PointMove", changeHandler);
                datas[i*2+0]=point.x;
                datas[i*2+1]=point.y;
                commands[i]=i==0?1:2;
                addChild(point);
            }
            render();
        }

        private function changeHandler(e:Event):void {
            render(e.target);
        }
        // ポイントを繋ぐ線を描く
        private function render(updatePoint:Object=null):void {
            graphics.clear();

            if (updatePoint) {
                // 移動した点の位置情報を更新
                var point:Object=updatePoint;
                var num:int=point.name;
                point.x=Math.round(point.x);// 精度誤差回避
                point.y=Math.round(point.y);// 精度誤差回避
                datas[num*2+0]=point.x;
                datas[num*2+1]=point.y;
            }

            // ポイント繋いだ図形を描画
            obj.graphics.clear();
            obj.graphics.lineStyle(2,0xccccff,0.5);
            obj.graphics.beginFill(0xccccff,0.5);
            obj.graphics.drawPath(commands,datas);
            obj.graphics.endFill();

            // 外周線と進行角度を配列に格納
            vectors = new Vector.<Number>();
            outlines = new Array();
            for (var o:int = 0; o < NP; o++) {
                var offset:int=o*2;
                var pFrom:Point=new Point(datas[offset+0],datas[offset+1]);
                if (o==NP-1) {
                    offset=-2;
                }
                var pTo:Point=new Point(datas[offset+2],datas[offset+3]);
                outlines.push(new SeparateLine(pFrom,pTo));
                vectors.push(getVector(pFrom,pTo));
            }

            // すべての接続線を描く
            var separateLines:Array = new Array();
            for (var i:int = 0; i < NP; i++) {
                for (var t:int = i+2; t < NP; t++) {
                    // 終了点と開始点を結ぶ線は除外しておく
                    if (i == 0 && t == NP-1) break;
                    // 全ての接続線を表示(目視確認用)
                    pFrom=new Point(datas[i*2],datas[i*2+1]);
                    pTo=new Point(datas[t*2],datas[t*2+1]);
                    graphics.lineStyle(0,0xeeeeee);
                    graphics.moveTo(pFrom.x,pFrom.y);
                    graphics.lineTo(pTo.x,pTo.y);
                    // 外周線と交差しないかチェック
                    var outFlg:Boolean = false;
                    var myLine:SeparateLine=new SeparateLine(pFrom,pTo);
                    for (o = 0; o < NP; o++) {
                        if (getCrossPoint(myLine,outlines[o])==true) {
                            outFlg=true;
                            break;
                        }
                    }
                    // 図形の内向きの線チェック
                    if (outFlg == false && checkInner(i,getVector(pFrom,pTo))) {
                        separateLines.push(myLine);
                        graphics.lineStyle(2,0xdddddd);
                        graphics.moveTo(pFrom.x,pFrom.y);
                        graphics.lineTo(pTo.x,pTo.y);
                    }
                }
            }
            // 分割線を短いものから確定していく
            var resultLines:Array = new Array();
            separateLines.sortOn("distance", Array.NUMERIC);
            while (separateLines.length > 0) {
                var shortLine:SeparateLine = (separateLines.splice(0,1))[0];
                resultLines.push(shortLine);
                // 短い線と交わる線を配列から取り除く
                var targetInd:int=0;
                while (separateLines.length > targetInd) {
                    if (getCrossPoint(shortLine,separateLines[targetInd])) {
                        separateLines.splice(targetInd,1);
                    } else {
                        targetInd++;
                    }
                }
            }
            dispLines(resultLines);
        }

        // 図形の内向きの線チェック
        private function checkInner(ind:int, rT:Number):Boolean {
            var innerFlg:Boolean=false;
            // 描画オブジェクトの範囲内となる角度を得る
            var beforeInd:int=ind>0?ind-1:NP-1;
            var afterInd:int=ind;
            // この頂点に向かうベクトルを反転して
            var rBefore:Number=vectors[beforeInd]-Math.PI;
            var rAfter:Number=vectors[afterInd];
            // 正の値にしておく
            if (rBefore < 0) {
                rBefore+=Math.PI*2;
            }
            // 単純に計算できるのはrBefor>rToの場合
            // 誰かもっとエレガントにしてください
            if (rBefore >= rAfter) {
                if (rBefore>rT&&rT>rAfter) {
                    innerFlg=true;
                }
            } else {
                if (rBefore < rT && rT < rAfter) {
                } else {
                    innerFlg=true;
                }
            }
            return innerFlg;
        }

        // pFromからpToの角度を0~Math.PI*2の範囲で取得する
        private function getVector(pFrom:Point, pTo:Point):Number {
            var radian:Number = Math.atan2((pTo.y-pFrom.y),(pTo.x-pFrom.x));
            if (radian<0) {
                radian+=Math.PI*2;
            }
            return radian;
        }

        // 配列に含まれる線を描画
        private function dispLines(lines:Array, t:Number=4, c:int=0):void {
            var numLines:int=lines.length;
            for (var i:int = 0; i < numLines; i++) {
                graphics.lineStyle(t,c);
                graphics.moveTo(lines[i].pA.x,lines[i].pA.y);
                graphics.lineTo(lines[i].pB.x,lines[i].pB.y);
            }
        }

        // 2本の直線の交点を計算
        // 交点が存在する場合trueを返す
        private function getCrossPoint(lineA:SeparateLine, lineB:SeparateLine):Boolean {
            var flg:Boolean=false;
            // det == 0 は平行
            var det:Number=lineB.f*lineA.g-lineA.f*lineB.g;
            if (det!=0) {
                var dx:Number=lineB.pA.x-lineA.pA.x;
                var dy:Number=lineB.pA.y-lineA.pA.y;
                var t1:Number = (lineB.f*dy - lineB.g*dx)/det;
                var t2:Number = (lineA.f*dy - lineA.g*dx)/det;
                // t1, t2の値が0~1の範囲外の場合、交点は延長線上に存在する
                if (t1>=0&&t1<=1&&t2>=0&&t2<=1) {
                    var crossPoint:Point = new Point();
                    crossPoint.x=lineA.pA.x+lineA.f*t1;
                    crossPoint.y=lineA.pA.y+lineA.g*t1;
                    // 交点が始点か終点と同じなら交差してないことにする
                    if (crossPoint.equals(lineA.pA)||crossPoint.equals(lineA.pB)) {
                    } else {
                        flg=true;
                    }
                }
            }
            return flg;
        }
    }
}
import flash.geom.Point;
class SeparateLine {
    public var distance:Number;
    public var f:Number;
    public var g:Number;
    public var pA:Point;
    public var pB:Point;
    public function SeparateLine(pointA:Point, pointB:Point):void {
        pA = pointA;
        pB = pointB;
        distance = Point.distance(pA,pB);
        f=pB.x-pA.x;
        g=pB.y-pA.y;
    }
}

import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.events.Event;
class DraggablePoint extends Sprite {
    public function DraggablePoint(radius:Number=5, color:int=0xff0000, num:String=null):void {
        graphics.beginFill(color);
        graphics.drawCircle(0,0,radius);
        graphics.endFill();
        addEventListener(MouseEvent.MOUSE_DOWN, dragStart);
    }
    private function dragStart(e:MouseEvent):void {
        startDrag();
        stage.addEventListener(MouseEvent.MOUSE_UP, dragStop);
        e.target.removeEventListener(MouseEvent.MOUSE_DOWN, dragStart);
        addEventListener(MouseEvent.MOUSE_MOVE, xMove);
    }
    private function dragStop(e:MouseEvent):void {
        stopDrag();
        stage.removeEventListener(MouseEvent.MOUSE_UP, dragStop);
        e.target.addEventListener(MouseEvent.MOUSE_DOWN, dragStart);
        //removeEventListener(MouseEvent.MOUSE_MOVE, xMove);
    }
    private function xMove(e:MouseEvent):void {
        var myEventObject:Event = new Event("PointMove");
        dispatchEvent(myEventObject);
    }
}