In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

3つの円に直交する円の作図

3つの円に直交する円を作図します。
赤い点はドラッグ移動できます。
3円の中心の位置が一直線に近づくと、途中の計算が発散気味になります。
出展 数学100の勝利 31 "モンジュの問題"
Get Adobe Flash player
by keno42 09 Feb 2010
/**
 * Copyright keno42 ( http://wonderfl.net/user/keno42 )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/2m7y
 */

package  
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Point;
	/**
	 * 3つの円に直交する円を作図します。
	 * 赤い点はドラッグ移動できます。
	 * 3円の中心の位置が一直線に近づくと、途中の計算が発散気味になります。
	 * 出展 数学100の勝利 31 "モンジュの問題"
	 */
	public class Monju extends Sprite
	{
		private var mcA:MovableCircle = new MovableCircle(60, 0xFF00FFFF, 3, 0xFFFF0000, true);
		private var mcB:MovableCircle = new MovableCircle(80, 0xFF00FF00, 3, 0xFFFF0000, true);
		private var mcC:MovableCircle = new MovableCircle(90, 0xFF0000FF, 3, 0xFFFF0000, true);
		public function Monju() 
		{
			mcA.x = 90;
			mcA.y = 120;
			addChild(mcA);
			mcB.x = 340;
			mcB.y = 180;
			addChild(mcB);
			mcC.x = 140;
			mcC.y = 350;
			addChild(mcC);
			
			this.addEventListener("startRefresh", onStartRefresh, true);
			this.addEventListener("stopRefresh", onStopRefresh, true);
			_refresh();
		}
		private function onStopRefresh(e:Event):void 
		{
			this.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
			_refresh();
		}
		
		private function onStartRefresh(e:Event):void 
		{
			this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
		}
		
		private function onEnterFrame(e:Event):void {
			_refresh();
		}
		
		private function _refresh():void
		{
			var f:Number, l:Number;
			
			// 根線(A,B)
			l = Math.sqrt(Math.pow(mcB.x - mcA.x, 2) + Math.pow(mcB.y - mcA.y, 2));
			f = (Math.pow(l, 2) - Math.pow(mcB.radius, 2) + Math.pow(mcA.radius, 2)) / (2 * l)
			
			var p1:Point = GeomUtil.getNaibunten(mcA.x, mcA.y, mcB.x, mcB.y, f/l);
			var p2:Point = new Point(p1.x + (mcB.y - mcA.y), p1.y - (mcB.x - mcA.x));
			
			// 根線(A,C)
			l = Math.sqrt(Math.pow(mcC.x - mcA.x, 2) + Math.pow(mcC.y - mcA.y, 2));
			f = (Math.pow(l, 2) - Math.pow(mcC.radius, 2) + Math.pow(mcA.radius, 2)) / (2 * l)
			
			var p3:Point = GeomUtil.getNaibunten(mcA.x, mcA.y, mcC.x, mcC.y, f/l);
			var p4:Point = new Point(p3.x + (mcC.y - mcA.y), p3.y - (mcC.x - mcA.x));
			
			// 根点
			var p5:Point = GeomUtil.getKoten(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y);
			
			var radius:Number = Math.sqrt(
				(Math.pow(p5.x - mcA.x, 2) + Math.pow(p5.y - mcA.y, 2))	- Math.pow(mcA.radius,2)
			);
			
			this.graphics.clear();
			// 半径が大きいとき、なんか途中でオーバーフローとかしちゃってる?
			if ( radius > 4000 ) {
				this.graphics.lineStyle(0, 0xFF0000);
			} else {
				this.graphics.lineStyle(0, 0x88FFC8);
			}
			if( !isNaN(radius) ){
				this.graphics.drawCircle(p5.x, p5.y, radius);
			}
			
		}
		
	}
	
}

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;
        } else {
			this.mouseEnabled = this.mouseChildren = false;
		}
    }
    protected 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);
    }
}

// 円
class MovableCircle extends MovablePoint {
	public var radius:Number;
	private var _mp:MovablePoint;
	private var _line:Sprite = new Sprite;
	private var _circleColor:uint;
	public function MovableCircle(radius:Number, circleColor:uint, pointRadius:Number, pointColor:uint, isMovable:Boolean) {
		_circleColor = circleColor;
		_mp = new MovablePoint(pointRadius, pointColor, isMovable);
		_mp.alpha = 0.75;
		var theta:Number = Math.random() * Math.PI * 2;
		_mp.x = radius * Math.cos(theta);
		_mp.y = radius * Math.sin(theta);
		this.radius = radius;
		if( isMovable ){
			this.addEventListener("startRefresh", onStartRefresh, true);
			this.addEventListener("stopRefresh", onStopRefresh, true);
		}
		super(pointRadius, pointColor, isMovable);
		addChild(_line);
		addChild(_mp);
		_refresh();
	}
	
	private function onStopRefresh(e:Event):void 
	{
		_isChildDragging = false;
		this.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
		_refresh();
	}
	
	private function onStartRefresh(e:Event):void 
	{
		_isChildDragging = true;
		this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
	}
	
	private var _isChildDragging:Boolean = false;
	override protected function onDown(e:MouseEvent):void 
	{
		if ( _isChildDragging ) {
			return;
		}
		super.onDown(e);
	}
	
	private function onEnterFrame(e:Event):void {
		_refresh();
	}
	
	private function _refresh():void
	{
		radius = Math.sqrt(Math.pow(_mp.x, 2) + Math.pow(_mp.y, 2));
		_line.graphics.clear();
		_line.graphics.lineStyle(0, _circleColor & 0xFFFFFF);
		_line.graphics.lineTo(_mp.x, _mp.y);
		_line.graphics.drawCircle(0, 0, radius);
	}
}
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));
	}
}