平行四辺形に内接する楕円の作図
赤と青の大きい点はドラッグ可能です
平行四辺形に内接する楕円を作図します
出展: 数学100の勝利 43
/**
* Copyright keno42 ( http://wonderfl.net/user/keno42 )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/lzsu
*/
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
// 赤と青の大きい点はドラッグ可能です
// 平行四辺形に内接する楕円を作図します
// 出展: 数学100の勝利 43
public class Heikou_Daen extends Sprite
{
private var mpA:MovablePoint = new MovablePoint(4, 0xFFFF0000, true);
private var mpB:MovablePoint = new MovablePoint(4, 0xFFFF0000, true);
private var mpC:MovablePoint = new MovablePoint(4, 0xFFFF8888, false);
private var mpD:MovablePoint = new MovablePoint(4, 0xFFFF0000, true);
private var mpN:MovablePoint = new MovablePoint(4, 0xFF0000FF, true);
// 弧(1/4)の分割数
private const NUM:int = 20;
public function Heikou_Daen()
{
mpA.x = 70;
mpA.y = 370;
addChild(mpA);
mpB.x = 380;
mpB.y = 310;
addChild(mpB);
addChild(mpC);
mpD.x = 80;
mpD.y = 130;
addChild(mpD);
mpN.x = 300;
mpN.y = 300;
addChild(mpN);
this.addEventListener("startRefresh", onStartRefresh, true);
this.addEventListener("stopRefresh", onStopRefresh, true);
_refresh();
}
private function onStopRefresh(e:Event):void
{
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
_refresh();
}
private function onStartRefresh(e:Event):void
{
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(e:Event):void
{
_refresh();
}
private function _refresh():void
{
// CをAB+ADに移動
mpC.x = mpB.x + mpD.x - mpA.x;
mpC.y = mpB.y + mpD.y - mpA.y;
// Nを垂点に移動
var nLoc:Point = GeomUtil.getSuiten(mpA.x, mpA.y, mpB.x, mpB.y, mpN.x, mpN.y);
var nCase:int = 0;
if ( nLoc.x > mpA.x && nLoc.x > mpB.x )
nCase = 1;
else if ( nLoc.x < mpA.x && nLoc.x < mpB.x )
nCase = 2;
if ( mpA.x > mpB.x ) nCase |= 4;
switch( nCase ) {
case 5:
case 2:
nLoc = GeomUtil.getNaibunten(mpA.x, mpA.y, mpB.x, mpB.y, 0.0001);
break;
case 1:
case 6:
nLoc = GeomUtil.getNaibunten(mpA.x, mpA.y, mpB.x, mpB.y, 0.9999);
break;
}
mpN.x = nLoc.x;
mpN.y = nLoc.y;
// 描画
graphics.clear();
graphics.lineStyle(2, 0x0);
graphics.moveTo(mpA.x, mpA.y);
graphics.lineTo(mpB.x, mpB.y);
graphics.lineTo(mpC.x, mpC.y);
graphics.lineTo(mpD.x, mpD.y);
graphics.lineTo(mpA.x, mpA.y);
// 接点の計算
var temp:Point = new Point(mpC.x - mpA.x, mpC.y - mpA.y);
var K:Point = GeomUtil.getKoten(mpN.x, mpN.y, mpN.x + temp.x, mpN.y + temp.y, mpB.x, mpB.y, mpC.x, mpC.y);
var temp2:Point = new Point(mpD.x - mpB.x, mpD.y - mpB.y);
var H:Point = GeomUtil.getKoten(mpN.x, mpN.y, mpN.x + temp2.x, mpN.y + temp2.y, mpA.x, mpA.y, mpD.x, mpD.y);
var M:Point = new Point(K.x + H.x - mpN.x, K.y + H.y - mpN.y);
// 中央の計算
var O:Point = GeomUtil.getChuten(mpA.x, mpA.y, mpC.x, mpC.y);
// 弧上の点の計算
var i:int, s:Number, p:Point;
var points:Array = [];
// N-OK x M-CK
for ( i = 0; i < NUM; i++ ) {
s = i / NUM;
var OKs:Point = GeomUtil.getNaibunten(O.x, O.y, K.x, K.y, s);
var CKs:Point = GeomUtil.getNaibunten(mpC.x, mpC.y, K.x, K.y, s);
p = GeomUtil.getKoten( mpN.x, mpN.y, OKs.x, OKs.y, M.x, M.y, CKs.x, CKs.y );
points.push(p);
}
// M-KO x N-KB
for ( i = 0; i < NUM; i++ ) {
s = i / NUM;
var KOs:Point = GeomUtil.getNaibunten(K.x, K.y, O.x, O.y, s);
var KBs:Point = GeomUtil.getNaibunten(K.x, K.y, mpB.x, mpB.y, s);
p = GeomUtil.getKoten( M.x, M.y, KOs.x, KOs.y, mpN.x, mpN.y , KBs.x, KBs.y);
points.push(p);
}
for ( i = 0; i < 2*NUM; i++ ) {
points.push(new Point(2 * O.x - points[i].x, 2 * O.y - points[i].y));
}
points.push( M );
graphics.lineStyle(0, 0x00FF00);
graphics.moveTo(M.x, M.y);
var len:int = points.length;
for ( i = 0; i < len; i++ ) {
graphics.lineTo(points[i].x, points[i].y);
}
graphics.lineStyle(0, 0x0000FF);
for ( i = 0; i < len; i++ ) {
graphics.drawCircle(points[i].x, points[i].y, 2);
}
}
}
}
import flash.display.*;
import flash.events.*;
import flash.geom.Matrix;
// ドラッグで移動する点
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);
}
}
import flash.geom.Point;
class GeomUtil {
// 垂点座標計算メソッド
public static function getSuiten(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+上の射影が垂点の位置
}
// 直線ABと直線CDの交点座標計算メソッド
public static function getKoten(Ax:Number, Ay:Number, Bx:Number, By:Number, Cx:Number, Cy:Number, Dx:Number, Dy:Number):Point {
var mat:Matrix = new Matrix(By - Ay, Dy - Cy, Ax - Bx, Cx - Dx);
var XY:Point = mat.transformPoint(new Point(Cx - Ax, Cy - Ay));
var abcd:Number = mat.a * mat.d - mat.b * mat.c;
XY.x /= abcd;
return new Point(Cx + XY.x * (Dx - Cx), Cy + XY.x * (Dy - Cy));
}
// 線分ABの中点座標計算メソッド
public static function getChuten(Ax:Number, Ay:Number, Bx:Number, By:Number):Point {
return new Point(Ax + 0.5 * (Bx - Ax), Ay + 0.5 * (By - Ay));
}
// 線分ABをs:1-sに内分する点の座標計算メソッド
public static function getNaibunten(Ax:Number, Ay:Number, Bx:Number, By:Number, s:Number):Point {
return new Point(Ax + s * (Bx - Ax), Ay + s * (By - Ay));
}
}