2点透視図法で描く立方体
2点透視図法で描く立方体
黒丸の操作点を移動すると、EL,GL,VPと立方体の高さが変更できます。
/**
* Copyright shinano_cake_koubou ( http://wonderfl.net/user/shinano_cake_koubou )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/nyGf
*/
package {
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.Stage;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
/**
* 2点透視図法で描く立方体
* 黒丸の操作点を移動すると、EL,GL,VPと立方体の高さが変更できます。
*
*
*/
[SWF (width=468, height=468, backgroundColor="#CCCCCC")]
public class Perspective2_Cube extends Sprite
{
/*------------------------------ 定数 ----------------------------------*/
public const PADDING:int = 10; /* 余白 */
public const BG_COLOR:int = 0xFFFFFF; /* 背景色 */
public const BG_ALPHA:Number = 1; /* 背景の透過率 */
public const LINE_COLOR:int = 0x666666; /* 線の色 */
public const LINE_WIDTH:int = 1; /* 線の太さ */
public const CUBELINE_COLOR:int = 0x222222; /* 立方体の線の色 */
public const CUBELINE_WIDTH:int = 2; /* 立方体の線の太さ */
public const CIRCLE_COLOR:int = 0x333333; /* 操作点の色 */
public const CIRCLE_R:int = 5; /* 操作点の大きさ */
/*------------------------------ 変数 ----------------------------------*/
public var eyeLevelY:Number = 200; /* eyeLine y */
public var vpLeftX:Number = 200; /* 消失点 (left) x */
public var vpRightX:Number = 1000; /* 消失点(right) x */
public var glX:Number = 600; /* ground line x */
public var glY:Number = 500; /* ground line y */
public var cubeHeight:Number = 300; /* 立方体の高さ */
private var startX:Number ; /* 左端 */
private var endX:Number ; /* 右端 */
private var line:Shape = new Shape(); /* 線 */
private var cubeLine:Shape = new Shape(); /* 立方体の線 */
private var circleVpLeft:Shape = new Shape(); /* 消失点の操作点(左) */
private var circleVpRight:Shape = new Shape(); /* 消失点の操作点(右) */
private var glCircle:Shape = new Shape(); /* GLの操作点 */
private var cubeHeightCircle:Shape = new Shape(); /* 立方体の高さの操作点 */
private var back:Shape = new Shape(); /* 背景 */
private var vpLeftDragged:Boolean = false; /* 操作点(LVP)がドラッグされているかどうかのフラグ */
private var vpRightDragged:Boolean = false; /* 操作点(RVP)がドラッグされているかどうかのフラグ */
private var glDragged:Boolean = false; /* 操作点(GL) がドラッグされているかどうかのフラグ */
private var cubeDragged:Boolean = false; /* 操作点(立方体の高さ)がドラッグされているかどうかのフラグ */
private var cubeLeftScale:Number = 0.75; /* 立方体の幅 */
private var cubeRightScale:Number = 0.75; /* 立方体の奥行 */
private var cubeRightBtmX:Number; /* 立方体(右下x座標) */
private var cubeRightBtmY:Number; /* 立方体(右下y座標) */
private var cubeLeftBtmX:Number; /* 立方体(左下x座標) */
private var cubeLeftBtmY:Number; /* 立方体(左下y座標) */
private var cubeRightTopX:Number; /* 立方体(右上x座標) */
private var cubeRightTopY:Number; /* 立方体(右上y座標) */
private var cubeLeftTopX:Number; /* 立方体(左上x座標) */
private var cubeLeftTopY:Number; /* 立方体(左上y座標) */
private var cubeBackBtmX:Number; /* 立方体(奥下x座標) */
private var cubeBackBtmY:Number; /* 立方体(奥下y座標) */
private var cubeBackTopX:Number; /* 立方体(奥上x座標) */
private var cubeBackTopY:Number; /* 立方体(奥上y座標) */
private var w:int = 465;
private var h:int = 465;
/*---------------------------- Initialization ---------------------------*/
/** コンストラクタ */
public function Perspective2_Cube()
{
init();
}
/** 初期化処理 */
private function init():void
{
this.stage.align = StageAlign.TOP_LEFT;
this.stage.scaleMode = StageScaleMode.NO_SCALE;
this.mouseEnabled = true;
//this.addEventListener(FlexEvent.CREATION_COMPLETE,onComplete); /* 完了を待つ flex用*/
onComplete(new Event("nop"));
}
/*---------------------------- Event Handelr ----------------------------*/
/** stageができるのを待つ */
private function onComplete(e:Event):void
{
this.startX = PADDING;
this.endX = this.w - PADDING;
eyeLevelY = this.h*1/2; /* eyeLine y */
vpLeftX = this.w*1/10; /* 消失点 (left) x */
vpRightX = this.w-this.w*2/10; /* 消失点(right) x */
glX = this.w*2/3; /* ground line x */
glY = this.h*5/7; /* ground line y */
cubeHeight = glY-eyeLevelY*4/5; /* 立方体の高さ */
this.stage.addEventListener(MouseEvent.MOUSE_DOWN,onMouseClick); /* マウスイベントを拾う */
this.stage.addEventListener(MouseEvent.MOUSE_MOVE,onMouseMove);
this.stage.addEventListener(MouseEvent.MOUSE_UP,onMouseRelease);
//this.addEventListener(ResizeEvent.RESIZE,onResize);
back = new Shape(); /* 背景 */
back.graphics.beginFill(BG_COLOR,BG_ALPHA);
back.graphics.drawRoundRect(PADDING,PADDING,this.w-PADDING*2,this.h-PADDING*2,PADDING,PADDING);
back.graphics.endFill();
this.addChild(back); /* 図形の追加 */
this.addChild(line);
this.addChild(cubeLine);
this.addChild(cubeHeightCircle);
this.addChild(circleVpLeft);
this.addChild(circleVpRight);
this.addChild(glCircle);
this.draw(); /* 描画 */
}
/** マウスクリック時 */
private function onMouseClick(e:MouseEvent):void
{
clearFlag(); /* ドラッグ状態をクリア */
if(circleVpLeft.hitTestPoint(e.stageX,e.stageY)){ /* ドラッグ状態をセット */
vpLeftDragged = true;
}else if(circleVpRight.hitTestPoint(e.stageX,e.stageY)){
vpRightDragged = true;
}else if(glCircle.hitTestPoint(e.stageX,e.stageY)){
glDragged = true;
}else if(cubeHeightCircle.hitTestPoint(e.stageX,e.stageY)){
cubeDragged = true;
}
}
/** すべての操作点のドラッグ状態を解除する */
private function clearFlag():void
{
vpLeftDragged = false;
vpRightDragged = false;
glDragged = false;
cubeDragged = false;
}
/** マウスを動かしたとき */
private function onMouseMove(e:MouseEvent):void
{
if(vpLeftDragged){ /* ドラッグされてる操作点を移動 */
eyeLevelY = e.localY;
vpLeftX = e.localX;
}else if(vpRightDragged){
eyeLevelY = e.localY;
vpRightX = e.localX;
}else if(glDragged){
glY = e.localY;
glX = e.localX;
}else if(cubeDragged){
cubeHeight = glY - e.localY;
glX = e.localX;
}
draw(); /* 再描画 */
}
/** マウスを離したとき */
private function onMouseRelease(e:MouseEvent):void
{
clearFlag(); /* ドラッグ状態を解除 */
}
/** リサイズ時の処理 */
private function onResize(e:Event):void
{
back.graphics.clear();
back.graphics.beginFill(BG_COLOR,BG_ALPHA);
back.graphics.drawRoundRect(PADDING,PADDING,this.w-PADDING,this.h-PADDING,PADDING,PADDING);
back.graphics.endFill();
this.draw();
}
/*--------------------------------------- Drawing ------------------------------------*/
/** 描画処理 */
public function draw():void{
this.initLine(); /* 描画の初期化 */
this.calcCubePoint(); /* 立方体の座標の算出 */
this.drawLine(); /* 線の描画 */
this.drawCube(); /* 立方体の描画 */
this.drawCircle(); /* 操作点の描画 */
}/* End of draw() */
/** 線の初期化 */
private function initLine():void
{
/* 初期化 */
line.graphics.clear(); /* clear */
circleVpLeft.graphics.clear();
circleVpRight.graphics.clear();
glCircle.graphics.clear();
cubeLine.graphics.clear();
cubeHeightCircle.graphics.clear();
/* 線の設定 */
line.graphics.lineStyle(LINE_WIDTH,LINE_COLOR); /* set line style */
cubeLine.graphics.lineStyle(CUBELINE_WIDTH,CUBELINE_COLOR);
}
/** 立方体の座標の計算 */
private function calcCubePoint():void
{
/* 立方体の頂点の座標 */
cubeRightBtmX = glX + (vpRightX - glX)*(1-cubeLeftScale); /* 立方体(右下x座標) */
cubeRightBtmY = eyeLevelY + (glY-eyeLevelY)*cubeLeftScale; /* 立方体(右下y座標) */
cubeLeftBtmX = glX + (vpLeftX - glX)*(1-cubeRightScale); /* 立方体(左下x座標) */
cubeLeftBtmY = eyeLevelY + (glY-eyeLevelY)*cubeRightScale; /* 立方体(左下y座標) */
cubeRightTopX = glX + (vpRightX - glX)*(1-cubeLeftScale); /* 立方体(右上x座標) */
cubeRightTopY = eyeLevelY + (glY-eyeLevelY -cubeHeight)*cubeLeftScale;/* 立方体(右上y座標) */
cubeLeftTopX = glX + (vpLeftX - glX)*(1-cubeRightScale); /* 立方体(左上x座標) */
cubeLeftTopY = eyeLevelY + (glY-eyeLevelY -cubeHeight )*cubeRightScale;/* 立方体(左上y座標) */
if( vpRightX == vpLeftX ){ /* LVP = RVPの時 */
vpRightX -= 0.1; /* ちょっとずらす */
}
/* ------------------------------------- 立方体(奥下の座標を求める )-------------------------------------- */
/* 計算用の変数 */
var a:Number;
var c:Number;
var b:Number;
var d:Number;
if((eyeLevelY != cubeLeftBtmY) && (glY != cubeLeftBtmY)){ /* アイレベル != 立方体の下部の頂点 */
/* かつ GL != 立方体の下部の頂点 */
/* LVP(左上)->GL(下)への直線を y= ax+ b , GL(下)->RVP(右上)への直線を y= cx + d とおき、この一次方程式を解く */
a = (cubeRightBtmY - eyeLevelY) / (cubeRightBtmX-vpLeftX) ;
c = (eyeLevelY - cubeLeftBtmY) / (vpRightX - cubeLeftBtmX );
b = eyeLevelY;
d = ((vpRightX-vpLeftX)*cubeLeftBtmY - (cubeLeftBtmX-vpLeftX)*eyeLevelY) / (vpRightX- cubeLeftBtmX);
cubeBackBtmX = (d - b)/(a - c) + vpLeftX ; /* 立方体(奥下x座標) */
cubeBackBtmY = a * (d - b)/(a - c) + b; /* 立方体(奥下y座標) */
}
/* ------------------------------------- 立方体(奥上の座標を求める )-------------------------------------- */
if((eyeLevelY != cubeLeftTopY) && (glY != cubeLeftTopY)){ /* アイレベル != 立方体の上部の頂点のとき */
/* かつ GL != 立方体の上部の頂点のとき */
/* LVP(左上)->GL(下)への直線を y= ax+ b , GL(下)->RVP(右上)への直線を y= cx + d とおき、この一次方程式を解く */
a = (cubeRightTopY - eyeLevelY) / (cubeRightTopX-vpLeftX) ;
c = (eyeLevelY - cubeLeftTopY) / (vpRightX - cubeLeftTopX );
b = eyeLevelY;
d = ((vpRightX-vpLeftX)*cubeLeftTopY - (cubeLeftTopX-vpLeftX)*eyeLevelY) / (vpRightX- cubeLeftTopX);
cubeBackTopX = (d - b)/(a - c) + vpLeftX ; /* 立方体(奥上x座標) */
cubeBackTopY = a * (d - b)/(a - c) + b; /* 立方体(奥上y座標) */
}
/* 調整 */
if((eyeLevelY == glY) && (eyeLevelY == cubeLeftTopY)) { /* アイレベル = GL */
cubeBackTopX = eyeLevelY; /* 立方体(奥上y座標) */
cubeBackBtmY = eyeLevelY; /* 立方体(奥下y座標) */
cubeBackTopX = (cubeRightBtmX-cubeRightBtmX)>> 1; /* 立方体(奥上x座標) */
cubeBackBtmX = (cubeRightBtmX-cubeRightBtmX)>> 1; /* 立方体(奥下x座標) */
}else if(eyeLevelY == glY) { /* アイレベル = GL */
cubeBackBtmX = cubeBackTopX; /* 立方体(奥上x座標) */
cubeBackBtmY = eyeLevelY; /* 立方体(奥上y座標) */
}else if(eyeLevelY == cubeLeftTopY) { /* アイレベル = 立方体の上部の頂点のとき */
cubeBackTopX = cubeBackBtmX; /* 立方体(奥上x座標) */
cubeBackTopY = eyeLevelY; /* 立方体(奥上y座標) */
}
}/* End of calcCubePoint() */
/** 線の描画(立方体以外) */
private function drawLine():void
{
line.graphics.moveTo(this.startX,eyeLevelY); /* Eye Level */
line.graphics.lineTo(this.w,eyeLevelY);
line.graphics.moveTo(this.startX,glY); /* Ground Line */
line.graphics.lineTo(this.w,glY);
line.graphics.moveTo(vpLeftX,eyeLevelY); /* LVP -> GL */
line.graphics.lineTo(glX,glY );
line.graphics.lineTo(vpRightX,eyeLevelY); /* GL -> RVP */
line.graphics.moveTo(vpLeftX,eyeLevelY); /* LVP -> CubeTop */
line.graphics.lineTo(glX,glY - cubeHeight);
line.graphics.lineTo(vpRightX,eyeLevelY); /* CubeTop -> RVP */
line.graphics.moveTo(vpLeftX,eyeLevelY);
line.graphics.lineTo(cubeRightTopX,cubeRightTopY);
line.graphics.moveTo(vpRightX,eyeLevelY);
line.graphics.lineTo(cubeLeftTopX,cubeLeftTopY);
line.graphics.moveTo(vpLeftX,eyeLevelY);
line.graphics.lineTo(cubeRightBtmX,cubeRightBtmY);
line.graphics.moveTo(vpRightX,eyeLevelY);
line.graphics.lineTo(cubeLeftBtmX,cubeLeftBtmY);
}/* End of drawLine() */
/** 立方体の描画 */
private function drawCube():void
{
cubeLine.graphics.moveTo(cubeRightBtmX,cubeRightBtmY);
cubeLine.graphics.lineTo(cubeRightTopX,cubeRightTopY);
cubeLine.graphics.moveTo(cubeLeftBtmX,cubeLeftBtmY);
cubeLine.graphics.lineTo(cubeLeftTopX,cubeLeftTopY);
cubeLine.graphics.moveTo(cubeLeftBtmX,cubeLeftBtmY);
cubeLine.graphics.lineTo(glX,glY);
cubeLine.graphics.lineTo(cubeRightBtmX,cubeRightBtmY);
cubeLine.graphics.lineTo(cubeBackBtmX,cubeBackBtmY);
cubeLine.graphics.lineTo(cubeLeftBtmX,cubeLeftBtmY);
cubeLine.graphics.moveTo(cubeRightTopX,cubeRightTopY);
cubeLine.graphics.lineTo(cubeBackTopX,cubeBackTopY);
cubeLine.graphics.lineTo(cubeLeftTopX,cubeLeftTopY);
cubeLine.graphics.moveTo(cubeBackTopX,cubeBackTopY);
cubeLine.graphics.lineTo(cubeBackBtmX,cubeBackBtmY);
cubeLine.graphics.moveTo(cubeLeftTopX,cubeLeftTopY);
cubeLine.graphics.lineTo(glX,glY - cubeHeight);
cubeLine.graphics.lineTo(cubeRightTopX,cubeRightTopY);
cubeLine.graphics.moveTo(glX,glY);
cubeLine.graphics.lineTo(glX,glY - cubeHeight);
}/* End of drawCube() */
/** 操作点の描画 */
private function drawCircle():void
{
circleVpLeft.graphics.beginFill(CIRCLE_COLOR,1); /* left viewPoNumber */
circleVpLeft.graphics.drawCircle(vpLeftX,eyeLevelY,CIRCLE_R);
circleVpLeft.graphics.endFill();
circleVpRight.graphics.beginFill(CIRCLE_COLOR,1); /* right viewPoNumber */
circleVpRight.graphics.drawCircle(vpRightX,eyeLevelY,CIRCLE_R);
circleVpRight.graphics.endFill();
glCircle.graphics.beginFill(CIRCLE_COLOR,1); /* gl */
glCircle.graphics.drawCircle(glX,glY,CIRCLE_R);
glCircle.graphics.endFill();
cubeHeightCircle.graphics.beginFill(CIRCLE_COLOR,1); /* cubeHeight */
cubeHeightCircle.graphics.drawCircle(glX,glY - cubeHeight,5);
cubeHeightCircle.graphics.endFill();
}/* End of drawCircle() */
}
}