一点を通る直線に他の一点から下ろした垂点の軌跡
/**
* Copyright keno42 ( http://wonderfl.net/user/keno42 )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/uF1D
*/
// forked from keno42's 垂線
package {
import flash.display.Sprite;
import flash.geom.Point;
import flash.events.Event;
public class FlashTest extends Sprite {
// ドラッグ移動できる点の宣言
private var mpA:MovablePoint = new MovablePoint(3, 0xFFFF0000, true);
private var mpB:MovablePoint = new MovablePoint(3, 0xFFFF0000, true);
private var mpC:MovablePoint = new MovablePoint(3, 0xFF00FF00, true);
private var rotP:MovablePoint = new MovablePoint(3, 0xFF880000, false);
private var result:MovablePoint = new MovablePoint(3, 0xFF0000FF, false);
private var count:Number = 0; // フレームカウント
private var rotC:Number = Math.PI / 30; // 回転速度
private var numHistory:int = 60; // 推移記録数
private var history:Array = new Array(numHistory); // 垂点の推移
private var historyIndex:int = 0; // 最新のインデックス
// コンストラクタ
public function FlashTest() {
// write as3 code here..
// 適当に初期条件
mpA.x = 200;
mpA.y = 200;
addChild(mpA);
mpB.x = 300;
mpB.y = 300;
addChild(rotP);
addChild(mpB);
mpC.x = 210;
mpC.y = 320;
addChild(mpC);
addChild(result);
// 推移記録用配列の初期化
_initHistory();
// 常時更新
onStartRefresh(null);
}
// 配列初期化
private function _initHistory():void{
for( var i:int = 0; i < numHistory; i++ ){
history[i] = new Point();
}
}
// 点のドラッグ開始で画面描画を開始
private function onStartRefresh(e:Event):void{
this.addEventListener(Event.ENTER_FRAME, _onEnter);
}
// 点のドラッグ終了で画面描画を停止
private function onStopRefresh(e:Event):void{
this.removeEventListener(Event.ENTER_FRAME, _onEnter);
// _refresh();
}
// 毎フレーム画面描画
private function _onEnter(e:Event):void{
_refreshRotPoint();
_refresh(mpA, rotP, mpC, result);
_updateHistory();
}
// 回転する人の更新
private function _refreshRotPoint():void{
count++;
var temp:Number = count * rotC;
var rotPradius:Number = _getDistance(mpA,mpB);
rotP.x = mpA.x + rotPradius * Math.cos(temp);
rotP.y = mpA.y + rotPradius * Math.sin(temp);
}
// 履歴更新
private function _updateHistory():void{
historyIndex = (historyIndex+1) % numHistory;
var targetP:Point = history[historyIndex];
targetP.x = result.x;
targetP.y = result.y;
}
// 距離計算メソッド
private function _getDistance(a:Sprite, b:Sprite):Number{
return Math.sqrt(Math.pow(a.x-b.x,2) + Math.pow(a.y-b.y,2));
}
// 画面描画メソッド
private function _refresh(mpA:Sprite, mpB:Sprite, mpC:Sprite, result:Sprite):void{
this.graphics.clear();
this.graphics.lineStyle(0, 0x0000FF, 0.5);
this.graphics.drawCircle(mpA.x, mpA.y, _getDistance(mpA,mpB));
this.graphics.lineStyle(0, 0x0);
// もろもろ計算用のPoint ぴったり重なったときのゼロ除算を避けるためにちょっとだけ加算
var tempPoint:Point = new Point(mpB.x + 0.0001,mpB.y + 0.0001);
// 垂点座標の計算
var p:Point = _calc(mpA.x, mpA.y, tempPoint.x, tempPoint.y, mpC.x-0.0001, mpC.y-0.0001);
var A:Point = new Point(mpA.x, mpA.y);
tempPoint = tempPoint.subtract(A);
tempPoint.normalize(465); // ABの長さを465に伸ばしたベクトル
// 直線描画
this.graphics.moveTo(A.x+tempPoint.x, A.y+tempPoint.y);
this.graphics.lineTo(A.x-tempPoint.x, A.y-tempPoint.y);
this.graphics.lineStyle(0, 0x0000FF);
// 垂線描画
this.graphics.moveTo(mpC.x, mpC.y);
this.graphics.lineTo(p.x, p.y);
// 垂点の表示位置を更新
result.x = p.x;
result.y = p.y;
for( var i:int = 0; i < numHistory; i++ ){
var targetP:Point = history[i];
this.graphics.drawRect(targetP.x, targetP.y, 1, 1);
}
}
// 垂点座標計算メソッド
private function _calc(Ax:Number, Ay:Number, Bx:Number, By:Number, Cx:Number, Cy:Number):Point{
var A:Point = new Point(Ax, Ay); // 直線上の点A
var B:Point = new Point(Bx, By); // 直線上の点B
var C:Point = new Point(Cx, Cy); // 直線外の点C
var AB:Point = B.subtract(A); // ベクトルAB
var unitAB:Point = AB.clone(); // ABの単位ベクトル
unitAB.normalize(1);
var AC:Point = C.subtract(A); // ベクトルAC
// ACのAB方向の成分を取得
var unitABxAC:Number = unitAB.x*AC.x+unitAB.y*AC.y;
// ACのAB軸への射影を計算
var ret:Point = new Point(unitAB.x*unitABxAC, unitAB.y*unitABxAC);
return ret.add(A); // A+上の射影が垂点の位置
}
}
}
import flash.display.*;
import flash.events.*;
// ドラッグで移動する点
class MovablePoint extends Sprite{
public function MovablePoint(radius:Number, color:uint, isMovable:Boolean){
this.graphics.lineStyle(1, color);
this.graphics.beginFill(color & 0xFFFFFF, 0.75);
this.graphics.drawCircle(0, 0, radius);
if( isMovable ){
this.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
this.buttonMode = true;
}
}
private function onDown(e:MouseEvent):void{
this.startDrag();
this.dispatchEvent(new Event("startRefresh"));
this.addEventListener(MouseEvent.MOUSE_UP, onUp);
this.stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
}
private function onUp(e:MouseEvent):void{
this.stopDrag();
this.dispatchEvent(new Event("stopRefresh"));
this.removeEventListener(MouseEvent.MOUSE_UP, onUp);
this.stage.removeEventListener(MouseEvent.MOUSE_UP, onUp);
}
}