// forked from Kay's ドラッグして描いた線の交差判定 // forked from Kay's Basic お絵かき /* * マウスで引いた線を立体にする * マウスを押して動かしている間線を描いて * マウスを離したら3D化 *---------------------------------------- * 交点を検出して表示します。 * Special Thanks uwiさん *---------------------------------------- * ToDo 陰影をつける * 3D描画時に交点情報を入れる * 透視投影にする * 余分な頂点を割愛する * etc. etc... */ package { import flash.display.Sprite; import flash.events.MouseEvent; import flash.events.Event; import flash.text.TextField; import flash.geom.Point; import flash.geom.Matrix3D; import flash.geom.Utils3D; import flash.geom.Vector3D; [SWF(width=400, height=400, frameRate=24, backgroundColor=0x000000)] public class FlashTest extends Sprite { public var dragFlg:Boolean = false; public var statusText:TextField; public var beginPoint:Point; public var lines:Vector.<Line> = new Vector.<Line>; public var pointCanvas:Sprite = new Sprite(); // 交点描画 public var lineCanvas:Sprite = new Sprite(); // 線描画 public var mainCanvas:Sprite = new Sprite(); // 3D描画 public var crossPoint:Point = new Point(); public var mtx:Matrix3D; public const CX:Number = stage.stageWidth/2; public const CY:Number = stage.stageHeight/2; public var vertices:Vector.<Number>; public var indices:Vector.<int>; public var uvt:Vector.<Number>; public function FlashTest() { // 状態表示(基本動作には不要) statusText = new TextField(); statusText.width = stage.stageWidth; statusText.text = ''; statusText.selectable = false; addChild(statusText); // 3D表示用カンバス addChild(mainCanvas); mainCanvas.x = CX; mainCanvas.y = CY; mainCanvas.z = 0; // 線描画用カンバス addChild(lineCanvas); // 交点表示用カンバス addChild(pointCanvas); // イベント検知 stage.addEventListener(MouseEvent.MOUSE_UP, xStopDrag); stage.addEventListener(MouseEvent.MOUSE_MOVE, xDrawLine); stage.addEventListener(MouseEvent.MOUSE_DOWN, xStartDrag); } // 描画開始 public function xStartDrag(e:MouseEvent):void { statusText.text = 'start'; // 状態表示 dragFlg = true; lineCanvas.graphics.clear(); lineCanvas.graphics.lineStyle(3,0xcccccc); var nX:Number = mouseX; var nY:Number = mouseY; lineCanvas.graphics.moveTo(nX, nY); // linesを初期化 lines.splice(0, lines.length); // 描画開始点を記録 beginPoint = new Point(nX, nY); // メインカンバス初期化 mainCanvas.graphics.clear(); // 後で修正 } // 描画中 // マウスが動いたことを検知し // かつマウスが押されている場合(dragFlg==true)だけドラッグと判断する public function xDrawLine(e:MouseEvent):void { if (dragFlg) { statusText.text = 'drag'; // 状態表示 xDrawAndRecord(); } } // 描画終了 public function xStopDrag(e:MouseEvent):void { statusText.text = 'stop'; // 状態表示 dragFlg = false; xDrawAndRecord(); var nL:Number = lines.length; statusText.text = nL.toString(); //lines; // マウス反応を停止 stage.removeEventListener(MouseEvent.MOUSE_UP, xStopDrag); stage.removeEventListener(MouseEvent.MOUSE_MOVE, xDrawLine); stage.removeEventListener(MouseEvent.MOUSE_DOWN, xStartDrag); // 3D化 vertices = new Vector.<Number>(); indices = new Vector.<int>(); uvt = new Vector.<Number>(); // Linesから座標値を取り出す // 交点が複数存在する場合は、開始点から近い順に取り出す var totalCount:uint = lines.length; // 最初のLineから描画開始点を取り出して vertices.push(lines[0].p1.x, lines[0].p1.y, 100); vertices.push(lines[0].p1.x, lines[0].p1.y, 0); for (var i:uint = 1; i < totalCount; i++) { // 以降交点と描画終了点を取り出す vertices.push(lines[i].p2.x-CX, lines[i].p2.y-CY, 0); // ※ Z値が異なる頂点は後処理で追加したほうが楽しい効果を得られる // ※ が、暫定版としてこのまま処理 vertices.push(lines[i].p2.x-CX, lines[i].p2.y-CY, 100); indices.push(i*2+0,i*2+1,i*2+3, i*2+3,i*2+2,i*2+0); //uvt.push(0,0,0,1,1,1,0,1); } // 3D描画処理 // ※drawTrianglesを用いているが、 // ※陰影を表現するためにパネルを1枚ずつ描くように変更 mtx = new Matrix3D(); stage.addEventListener(Event.ENTER_FRAME, xRotate); // 描いたラインと点を徐々に消す stage.addEventListener(Event.ENTER_FRAME,xDeleteLine); } public function xRotate(e:Event):void { mainCanvas.graphics.clear(); mtx.appendRotation(1.3,Vector3D.X_AXIS); mtx.appendRotation(1.7,Vector3D.Y_AXIS); mtx.appendRotation(2.3,Vector3D.Z_AXIS); var vout:Vector.<Number> = new Vector.<Number>(); Utils3D.projectVectors(mtx,vertices,vout,uvt); mainCanvas.graphics.beginFill(0x0099ff,0.5); mainCanvas.graphics.lineStyle(0,0xffffff,0.1); mainCanvas.graphics.drawTriangles(vout,indices); mainCanvas.graphics.endFill(); } // ラインを描画し、linesにLineを追加 public function xDrawAndRecord():void { var nX:Number = mouseX; var nY:Number = mouseY; lineCanvas.graphics.lineTo(nX,nY); // linesにlineを追加 var line:Line = new Line(beginPoint.x, beginPoint.y, nX, nY); lines.push(line); // linesとlineの交点を求める var total:Number = lines.length - 3; for ( var i:uint = 0; i < total; i++) { var targetLine:Line = lines[i]; var cross:Point = new Point(); // 交点が見つかったら、lineに交点を記録し、描画する if (getCrossPoint(lines[i],line)) { // 交点追加 line.crossPoints.push(crossPoint); lines[i].crossPoints.push(crossPoint); // 交点描画 pointCanvas.graphics.lineStyle(2,0xffffff); pointCanvas.graphics.beginFill(0xff0000); pointCanvas.graphics.drawCircle(crossPoint.x, crossPoint.y, 4); pointCanvas.graphics.endFill(); } } // 描画終了点を記録 beginPoint = new Point(nX, nY); } // 2本の直線の交点を計算 public function getCrossPoint(lineA:Line, lineB:Line):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.p1.x - lineA.p1.x; var dy:Number = lineB.p1.y - lineA.p1.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) { crossPoint.x = lineA.p1.x + lineA.f*t1; crossPoint.y = lineA.p1.y + lineA.g*t1; flg = true; } } return flg; } // 画面に描いた線と点を削除 public function xDeleteLine(e:Event):void { lineCanvas.alpha -=0.05; pointCanvas.alpha -= 0.05; if (pointCanvas.alpha <= 0) { lineCanvas.graphics.clear(); pointCanvas.graphics.clear(); lineCanvas.alpha = 1; pointCanvas.alpha = 1; // 消去が完了したら、このイベントを削除 stage.removeEventListener(Event.ENTER_FRAME, xDeleteLine); // マウス反応を再開 // ※タイミングに問題あり stage.addEventListener(MouseEvent.MOUSE_UP, xStopDrag); stage.addEventListener(MouseEvent.MOUSE_MOVE, xDrawLine); stage.addEventListener(MouseEvent.MOUSE_DOWN, xStartDrag); } } } } import flash.geom.Point; class Line { public var p1:Point; public var p2:Point; public var f:Number; public var g:Number; public var color:uint; public var crossPoints:Vector.<Point> = new Vector.<Point>(); public function Line(x1:Number=0, y1:Number=0, x2:Number=0, y2:Number=0, c:uint=0):void { p1 = new Point(x1, y1); p2 = new Point(x2, y2); color = c; f = p2.x - p1.x; g = p2.y - p1.y; } } 平面に描いた線を3D化(暫定Ver)