package { // Created: 2010-03-04 by tenasaku import flash.display.Sprite; import flash.events.Event; import flash.text.TextField; public class Main extends Sprite { // リマソン(蝸牛線)の定義を説明するためのプログラムです // 円周 ( 直径: d ) の上に一点 O を固定し、 // その点 O を通る直線 (緑色) と円周のもうひとつの // 交点 P から, 一定の距離 a だけ離れた点 Q を // その直線の延長上にとるとします // 直線をぐるっと360度動かしたとき 動点 Q の描く軌跡が // リマソンです // a = d のときの形はとくに カージオイド と呼ばれています private var _banner:TextField; // タイトルなどを表示 private var _tf:TextField; // 時々刻々の情報を表示 private var Li:Limacon; // 本日の主役リマソンさん private var Ray:Sprite; // ガイド役の直線 // プログラム本体... public function Main():void { [SWF(width="465",height="465",backgroundcolor="#000000")] // 前振りなしにいきなり主役が登場するのは、 // 見出し用のテキストフィールドの値に // 主役 Li のプロパティを引用しているからです Li = new Limacon(180, 90, 0); Li.color = 0x800000; Li.thickness = 2; Li.x = 152; Li.y = 232; Li.showCircle = true; Li.circleColor = 0x000000; Li.draw(); addChild(Li); // ガイド用の直線 Ray = new Sprite(); Ray.graphics.clear(); addChild(Ray); // 見出し用テキストフィールド _banner = new TextField(); _banner.background = true; _banner.backgroundColor = 0xffffff; _banner.text = "Pascal's Limaçon\n[ a = " + String(Li.a / Li.d) + "d ]"; _banner.x = 10; _banner.y = 2; _banner.textColor = 0x800000; _banner.width = 200; _banner.height = 80; _banner.alpha = 0.6 addChild(_banner); // 表示用テキストフィールド _tf = new TextField(); _tf.text = ""; _tf.x = 10; _tf.y = 40; _tf.width = 200; _tf.textColor = 0x000080; addChild(_tf); // 各フレームごとに表示を更新するハンドラーを登録 addEventListener(Event.ENTER_FRAME, _as_time_passes); } // draw a straight line passing thru limaçon's origin and the mouse position ... // 原点とマウスの位置を通る直線を描きます (しかし妙にコムズカシくなってしまった...) private function draw_ray():void { var dx:Number = mouseX - Li.x; // <dx,dy> is the orientation of the line var dy:Number = mouseY - Li.y; var nx:Number; // <nx,ny> is the orthogonal direction var ny:Number; var Ax:Number; // at <Ax,Ay>, the line crosses the boundary. var Ay:Number; var Bx:Number; // <Bx,By> is the other cross point. var By:Number; Ray.graphics.clear(); Ray.graphics.lineStyle(1,0x00ff00); // Draw only if <dx,dy> is not the zero vector... if (( dx != 0 ) || (dy != 0)) { // normalize <dx,dy>... var _r:Number = Math.sqrt(dx * dx + dy * dy); dx /= _r; dy /= _r; // a unit vector perpendicular to <dx,dy> nx = - dy; ny = + dx; // Determine where does the line cross the boundary of Stage. var _NW:Number = nx * (-Li.x) + ny * (-Li.y); var _SW:Number = nx * (-Li.x) + ny * (stage.stageHeight-Li.y); var _SE:Number = nx * (stage.stageWidth-Li.x) + ny * (stage.stageHeight-Li.y); var _NE:Number = nx * (stage.stageWidth-Li.x) + ny * (-Li.y); var _EAST:Boolean = ( _NE*_SE < 0 ); // if the line crosses the east end of stage. var _WEST:Boolean = ( _NW*_SW < 0 ); // if the line crosses the west end of stage. var _NORTH:Boolean = ( _NE*_NW <= 0 ); // if the line crosses the north end of stage. var _SOUTH:Boolean = ( _SE*_SW <= 0 ); // if the line crosses the south end of stage. if ( _EAST ) { // if _EAST, then dx can never be zero. Bx = stage.stageWidth; By = Li.y + (dy/dx)*(stage.stageWidth-Li.x); if ( _NORTH ) { Ax = Li.x - (dx/dy)*Li.y; Ay = 0; } else { if ( _SOUTH ) { Ax = Li.x + (dx/dy)*(stage.stageHeight-Li.y); Ay = stage.stageHeight; } else { // _WEST must be the case Ax = 0; Ay = Li.y - (dy/dx)*Li.x; } } } else { // if not _EAST, three cases remain... if ( _NORTH && _SOUTH ) { Ax = Li.x - (dx/dy)*Li.y; Ay = 0; Bx = Li.x + (dx/dy)*(stage.stageHeight-Li.y); By = stage.stageHeight; } if ( _NORTH && _WEST ) { Ax = Li.x - (dx/dy)*Li.y; Ay = 0; Bx = 0; By = Li.y - (dy/dx)*Li.x; } if ( _SOUTH && _WEST ) { Ax = Li.x + (dx/dy)*(stage.stageHeight-Li.y); Ay = stage.stageHeight; Bx = 0; By = Li.y - (dy/dx)*Li.x; } } Ray.graphics.moveTo(Ax,Ay); Ray.graphics.lineTo(Bx,By); } } // マウスがステージにあれば原点から直線を引き、 // 方向(角度)をテキストフィールドに表示します private function _as_time_passes(e:Event):void { if ( ( mouseX >= 0) && (mouseY >= 0) && (mouseX < stage.stageWidth) && (mouseY < stage.stageHeight) ) { draw_ray(); } var deg:int = Math.round(Math.atan2( - (mouseY-Li.y), mouseX-Li.x) / Math.PI*180); _tf.text = "direction = " + String(deg) + " (deg)"; } } // end of class Main } // end of package /* ===================== */ // Limacon: a class which embodies Pascal's Limaçon. // -------- // Pascal's Limaçon is the plain curve determined by the polar equation // r = d*cos(theta - phi) + a [ where 0 <= theta <= 2*PI ]. // -------- // Note: // Constructor doesn't draw. You call draw() method explicitly. // -------- import flash.display.Sprite; class Limacon extends Sprite { public var d:Number; // Set by the constructor. public var a:Number; // ditto. public var phi:Number; // ditto. These three parameters are mandatory. public var thickness:uint; // default: 2 public var color:uint; // default: 0x000000 ( black ) public var showCircle:Boolean; // Want the circle displayed? (defalut: false) public var showLine:Boolean; // Want the diameter displayed? (defalut: false) public var circleColor:uint; // default: 0xffffff ( white ) public var lineColor:uint; // default: 0xffffff ( white ) // Draws the curve using given parameters public function draw():void { var i:int; var t:Number; var r:Number; this.graphics.clear(); this.graphics.lineStyle(thickness, color); for ( i = 0; i <= 90; ++i ) { t = this.phi + i * Math.PI / 45; r = this.d * Math.cos(t - phi) + this.a; if (i == 0) { this.graphics.moveTo(r * Math.cos(t), r * Math.sin(t)); } else { this.graphics.lineTo(r * Math.cos(t), r * Math.sin(t)); } } if ( showCircle ) { this.graphics.lineStyle(1, this.circleColor); this.graphics.drawCircle(this.d / 2 * Math.cos(phi), - this.d / 2 * Math.sin(phi), d / 2); } if ( showLine ) { this.graphics.lineStyle(1, this.lineColor); graphics.moveTo(0, 0); graphics.lineTo((this.d + this.a * 1.2) * Math.cos(phi), (this.d + this.a * 1.2) * Math.sin(phi)); } } // Constructor... public function Limacon(_d:Number, _a:Number, _phi:Number):void { this.d = _d; this.a = _a; while ( _phi < 0 ) { _phi += Math.PI * 2; } while ( _phi >= Math.PI * 2 ) { _phi -= Math.PI * 2; } this.phi = _phi; this.thickness = 2; this.showCircle = false; this.showLine = false; this.color = 0x000000; this.circleColor = 0xffffff; this.lineColor = 0xffffff; } } リマソン第2弾 (定義編)