任意の凸四角形は長方形に出来る

元々この問題を考えたのは,

数学セミナー12月号(だったと思う)の「エレガントな解答を求む」のコーナーで

Dudeneyの三角形を知ったからだ.

Dudeneyの三角形とは,

正三角形を4つのピースに切り分け, 再配置して正方形を作れるか

という,英パズル作家のDudeneyのクイズ.

この作図は非常に難しいが,感動する.

そうして,色々調べていたら,

四角形を分割して正方形にする

というサイトに遭遇.これまた感動的な再配置を多数学ぶ.

特に,任意の四角形が長方形に出来る,ということを知った.

そして,どうせなら自分でflashを作ってみようと思った.作った.

http://schch.net/jimako/tetragon.swf

実装にあたり,Tween24というライブラリを使ってみた.これは回転と平行移動を同時に実現するトゥイーンをスクリプトで書くため.

基本的に使いやすかったのだけれども,やはり個人的には「デザイン屋のおもちゃ」という感じがした.

変形過程で,serialとしたのはparallelでうまくいかなかったから.

回転と同時に移動,みたいな難解なアクションは

(いくらTween24が素晴らしいライブラリでも)座標計算が難しい面倒なので

結局serialにして$$xyに頼りましたとさ.

ただ,完全に(回転&平行)移動終了後に頂点の座標を取得しようとすると,

回転前座標に平行移動座標を加えただけで,座標の回転操作がされていないみたいで,

これ以上機能盛り込むことが出来なかった.意味不明.

時間ができたら調べてみたいが,多分もうない.

ソースコードは続きにて.


package  {
	import flash.display.Sprite;
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.MouseEvent;

	import a24.tween.Tween24;
	import a24.tween.events.Tween24Event;
	import flash.geom.Point;
	import flash.geom.Rectangle;

	/**
	* Tetragon...
	* @author nsplat
	*/

	public class Main extends MovieClip {
		const RAD_TO_DEG:Number = 180/Math.PI;

		const POINTSIZE:Number = 3;
		const POINTCOLOR:Number = 0x0;
		const LINESIZE:Number = 3;
		const LINECOLOR:Number = 0x0;
		const DOMAINCOLOR1:Number = 0xFF0000;
		const DOMAINCOLOR2:Number = 0xFFFF00;
		const DOMAINCOLOR3:Number = 0x00FF00;
		const DOMAINCOLOR4:Number = 0x00FFFF;
		const DOMAINCOLOR5:Number = 0x0000FF;
		const DOMAINCOLOR6:Number = 0xFF00FF;
		const OPACITY:Number = 0.5;

		var Point1:Point;
		var Point2:Point;
		var Point3:Point;
		var Point4:Point;

		var PointsArray:Array = new Array();

		var PointA:Sprite = new Sprite();
		var PointB:Sprite = new Sprite();
		var PointC:Sprite = new Sprite();
		var PointD:Sprite = new Sprite();

		var PointK:Point;
		var PointL:Point;
		var PointM:Point;
		var PointN:Point;

		var PointH1:Point;
		var PointH2:Point;

		var DomainA:Sprite = new Sprite();
		var DomainB:Sprite = new Sprite();
		var DomainC:Sprite = new Sprite();
		var DomainD:Sprite = new Sprite();

		var Domains:Array = [DomainA, DomainB, DomainC , DomainD];

		var ArgA:Number;
		var ArgB:Number;
		var ArgC:Number;
		var ArgD:Number;

		public function Main() {
			// constructor code
			addEventListener(Event.ADDED_TO_STAGE , init);
		}

		private function init(e:Event):void{

			stage.removeEventListener(MouseEvent.CLICK , init);

			gotoAndPlay(1);

			PointsArray = new Array();
			PointsArray[0] = new Array();

			Tween24.prop(DomainA).alignXY(0 , 0).rotation(0).play();
			Tween24.prop(DomainC).alignXY(0 , 0).rotation(0).play();

			DomainA.x = 0;
			DomainA.y = 0;

			DomainB.x = 0;
			DomainB.y = 0;

			DomainC.x = 0;
			DomainC.y = 0;

			DomainD.x = 0;
			DomainD.y = 0;

			DomainA.graphics.clear();
			DomainB.graphics.clear();
			DomainC.graphics.clear();
			DomainD.graphics.clear();

			Tween24.prop(Text2).fadeOut().play();
			Tween24.prop(EndMessage).fadeOut().play();

			stage.addEventListener(MouseEvent.CLICK , Func_Click);
		}

		private function Func_Click(event:MouseEvent):void {

			var num:int = PointsArray[0].length + 1;
			var tmpPoint:Sprite = new Sprite();
			tmpPoint.graphics.beginFill(POINTCOLOR);
			tmpPoint.graphics.drawCircle( 0 , 0 , POINTSIZE);
			tmpPoint.graphics.endFill();
			tmpPoint.x = stage.mouseX;
			tmpPoint.y = stage.mouseY;

			stage.addChild(tmpPoint);

			if (num <= 4) PointsArray[0].push(tmpPoint);
 			if (num == 4) {
 				stage.removeEventListener(MouseEvent.CLICK , Func_Click);
 				var Point0:Point = new Point((PointsArray[0][0].x + PointsArray[0][1].x + PointsArray[0][2].x + PointsArray[0][3].x)/4 , (PointsArray[0][0].y + PointsArray[0][1].y + PointsArray[0][2].y + PointsArray[0][3].y)/4);
 				PointsArray[1] = [
 					RatioToRad(PointsArray[0][0].y - Point0.y , PointsArray[0][0].x - Point0.x) * RAD_TO_DEG , 
 					RatioToRad(PointsArray[0][1].y - Point0.y , PointsArray[0][1].x - Point0.x) * RAD_TO_DEG ,
  					RatioToRad(PointsArray[0][2].y - Point0.y , PointsArray[0][2].x - Point0.x) * RAD_TO_DEG ,
  					RatioToRad(PointsArray[0][3].y - Point0.y , PointsArray[0][3].x - Point0.x) * RAD_TO_DEG
 				];
 				var ranking:Array = PointsArray[1].sort(1|16|8);
 				PointA.graphics.clear();
 				PointA.graphics.beginFill(POINTCOLOR);
 				PointA.graphics.drawCircle( 0 , 0 , POINTSIZE);
 				PointA.graphics.endFill();
 				PointA.x = PointsArray[0][ranking[0]].x;
 				PointA.y = PointsArray[0][ranking[0]].y;
 				PointB.graphics.clear();
 				PointB.graphics.beginFill(POINTCOLOR);
 				PointB.graphics.drawCircle( 0 , 0 , POINTSIZE);
 				PointB.graphics.endFill();
 				PointB.x = PointsArray[0][ranking[1]].x;
 				PointB.y = PointsArray[0][ranking[1]].y;
 				PointC.graphics.clear();
 				PointC.graphics.beginFill(POINTCOLOR);
 				PointC.graphics.drawCircle( 0 , 0 , POINTSIZE);
 				PointC.graphics.endFill();
 				PointC.x = PointsArray[0][ranking[2]].x;
 				PointC.y = PointsArray[0][ranking[2]].y;
 				PointD.graphics.clear();
 				PointD.graphics.beginFill(POINTCOLOR);
 				PointD.graphics.drawCircle( 0 , 0 , POINTSIZE);
 				PointD.graphics.endFill();
 				PointD.x = PointsArray[0][ranking[3]].x;
 				PointD.y = PointsArray[0][ranking[3]].y;
 				PointsArray[0][0].graphics.clear();
 				PointsArray[0][1].graphics.clear();
 				PointsArray[0][2].graphics.clear();
 				PointsArray[0][3].graphics.clear();
 				stage.removeChild(tmpPoint);
 				stage.addChild(PointA);
 				stage.addChild(PointB);
 				stage.addChild(PointC);
 				stage.addChild(PointD);
 				ArrangeRectangle();
 			}
 		}
 		private function ArrangeRectangle():void {
 			addChildAt(DomainA , 1);
 			addChildAt(DomainB , 1);
 			addChildAt(DomainC , 1);
 			addChildAt(DomainD , 1);
 			PointK = new Point((PointA.x + PointB.x)/2 , (PointA.y + PointB.y)/2);
 			PointL = new Point((PointB.x + PointC.x)/2 , (PointB.y + PointC.y)/2);
 			PointM = new Point((PointC.x + PointD.x)/2 , (PointC.y + PointD.y)/2);
 			PointN = new Point((PointD.x + PointA.x)/2 , (PointD.y + PointA.y)/2);
 			var CoEff1:Number = ((PointK.x-PointL.x)*(PointK.x-PointM.x)+(PointK.y-PointL.y)*(PointK.y-PointM.y))/(Math.pow(PointK.x-PointM.x , 2)+Math.pow(PointK.y-PointM.y , 2));
 			var CoEff2:Number = ((PointK.x-PointN.x)*(PointK.x-PointM.x)+(PointK.y-PointN.y)*(PointK.y-PointM.y))/(Math.pow(PointK.x-PointM.x , 2)+Math.pow(PointK.y-PointM.y , 2));
 			PointH1 = new Point( CoEff1 * (PointM.x - PointK.x) + PointK.x , CoEff1 * (PointM.y - PointK.y) + PointK.y);
 			PointH2 = new Point( CoEff2 * (PointM.x - PointK.x) + PointK.x , CoEff2 * (PointM.y - PointK.y) + PointK.y);
 			DomainA.graphics.clear();
 			DomainA.graphics.lineStyle(LINESIZE,LINECOLOR);
 			DomainA.graphics.beginFill(DOMAINCOLOR1 , OPACITY);
 			DomainA.graphics.moveTo( PointH2.x , PointH2.y);
 			DomainA.graphics.lineTo( PointN.x , PointN.y);
 			DomainA.graphics.lineTo( PointA.x , PointA.y);
 			DomainA.graphics.lineTo( PointK.x , PointK.y);
 			DomainA.graphics.endFill();
 			DomainB.graphics.clear();
 			DomainB.graphics.lineStyle(LINESIZE,LINECOLOR);
 			DomainB.graphics.beginFill(DOMAINCOLOR2 , OPACITY);
 			DomainB.graphics.moveTo( PointH1.x , PointH1.y);
 			DomainB.graphics.lineTo( PointK.x , PointK.y);
 			DomainB.graphics.lineTo( PointB.x , PointB.y);
 			DomainB.graphics.lineTo( PointL.x , PointL.y);
 			DomainB.graphics.endFill();
 			DomainC.graphics.clear();
 			DomainC.graphics.lineStyle(LINESIZE,LINECOLOR);
 			DomainC.graphics.beginFill(DOMAINCOLOR3 , OPACITY);
 			DomainC.graphics.moveTo( PointH1.x , PointH1.y);
 			DomainC.graphics.lineTo( PointL.x , PointL.y);
 			DomainC.graphics.lineTo( PointC.x , PointC.y);
 			DomainC.graphics.lineTo( PointM.x , PointM.y);
 			DomainC.graphics.endFill();
 			DomainD.graphics.clear();
 			DomainD.graphics.lineStyle(LINESIZE,LINECOLOR);
 			DomainD.graphics.beginFill(DOMAINCOLOR4 , OPACITY);
 			DomainD.graphics.moveTo( PointH2.x , PointH2.y);
 			DomainD.graphics.lineTo( PointM.x , PointM.y);
 			DomainD.graphics.lineTo( PointD.x , PointD.y);
 			DomainD.graphics.lineTo( PointN.x , PointN.y);
 			DomainD.graphics.endFill();
 			stage.removeChild(PointA);
 			stage.removeChild(PointB);
 			stage.removeChild(PointC);
 			stage.removeChild(PointD);
 			ArgA = RatioToRad(PointN.y - PointH2.y , PointN.x - PointH2.x) * RAD_TO_DEG;
 			ArgB = RatioToRad(PointL.y - PointH1.y , PointL.x - PointH1.x) * RAD_TO_DEG;
 			ArgC = RatioToRad(PointL.y - PointH1.y , PointL.x - PointH1.x) * RAD_TO_DEG;
 			ArgD = RatioToRad(PointN.y - PointH2.y , PointN.x - PointH2.x) * RAD_TO_DEG;
	 		var motion:Tween24 = Tween24.serial(
 				Tween24.prop(Domains).fadeOut()
 				,Tween24.tween(Domains, 1).fadeIn()
 				,Tween24.wait(0.5)
 				,Tween24.tween(DomainD , 2).$$xy(PointB.x - PointD.x , PointB.y - PointD.y).delay(1)
 				,Tween24.tween(DomainA , 2).alignXY(PointK.x , PointK.y).$$rotation(180)
 				,Tween24.tween(DomainC , 2).alignXY(PointL.x , PointL.y).$$rotation(-180)
 				,Tween24.tween(Domains , 2).$$xy(stage.stageWidth/2 - PointB.x , stage.stageHeight/2 - PointB.y)
 				,Tween24.tween(Text2 , 2).fadeIn()
 			);
 			motion.play();
 			motion.onComplete(Restart);
 		}
 		private function Restart():void{
 			Tween24.tween(EndMessage , 2).fadeIn().play();
 			stage.addEventListener(MouseEvent.CLICK , init);
 		}
 		private function RatioToRad(Y:Number,X:Number):Number {
 			if(X == 0 && Y>0){
				return ( Math.PI/2 );
			}else if(X == 0 && Y<0){
 				return ( Math.PI * 3/2);
 			}else if(X>0 && Y>0) {
				return ( Math.atan(Y/X) );
			}else if(X>0 && Y<0) {
				return ( 2 * Math.PI + Math.atan(Y/X) );
			}else{
				return ( Math.atan(Y/X) + Math.PI );
			}
		}

	}

}
広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中