平面に描いた線を3D化(表もあれば裏もある)
マウスで引いた線を立体にする
* マウスを押して動かしている間線を描いて
* マウスを離したら3D化
*----------------------------------------
* 交点を検出して表示します。
* Special Thanks uwiさん
*----------------------------------------
* ToDo 陰影をつける
* 3D描画時に交点情報を入れる
* 透視投影にする
* 余分な頂点を割愛する
* etc. etc...
/**
* Copyright Kay ( http://wonderfl.net/user/Kay )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/7fEM
*/
// forked from Kay's 平面に描いた線を3D化(暫定Ver)
// 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;
import flash.display.TriangleCulling;
import flash.geom.PerspectiveProjection;
[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);
lineCanvas.z = 0;
// 交点表示用カンバス
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, 50);
vertices.push(lines[0].p1.x, lines[0].p1.y, -50);
for (var i:uint = 1; i < totalCount; i++) {
// 以降交点と描画終了点を取り出す
vertices.push(lines[i].p2.x-CX, lines[i].p2.y-CY, -50);
// ※ Z値が異なる頂点は後処理で追加したほうが楽しい効果を得られる
// ※ が、暫定版としてこのまま処理
vertices.push(lines[i].p2.x-CX, lines[i].p2.y-CY, 50);
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(3,Vector3D.X_AXIS);
mtx.appendRotation(2,Vector3D.Y_AXIS);
mtx.appendRotation(1,Vector3D.Z_AXIS);
var vout:Vector.<Number> = new Vector.<Number>();
Utils3D.projectVectors(mtx,vertices,vout,uvt);
mainCanvas.graphics.beginFill(0x99cc33,0.5);
mainCanvas.graphics.drawTriangles(vout,indices,null,TriangleCulling.NEGATIVE);
mainCanvas.graphics.beginFill(0x0099ff,0.5);
mainCanvas.graphics.drawTriangles(vout,indices,null,TriangleCulling.POSITIVE);
}
// ラインを描画し、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;
}
}