flash:二次貝塞爾曲線應用-生成飛機路徑示意圖


本周聽到公司其它項目組同事在討論一個小需求:

給定3個點(其實是飛機經過的航站,比如:從浦東-西安-北京),在UI上生成一段曲線,用來示意飛機的路線圖(其實用直線我覺得也能將就,反正只是示意,只是大家覺得直線太out,不美觀),晚上無事,嘗試了一下:
有二個方案:
1、橢圓(很快被自己給否定了,橢圓的標准方程 (x-m)^2/(a^2) + (y-n)^2/(b^2)=1,有m,n,a,b 四個未知數,3個點無法唯一確定,如果把圓心定在頁面中心,理論上可以解決,但是開平方也是比較繁瑣的)
2、貝塞爾曲線

根據:(貝塞爾曲線)喂雞百科的解釋:
二次標准方程為:

正好以前在學習flash時也研究過,所以決定用它了。解決了曲線的生成問題,還有飛機的朝向問題,飛機頭是有方向的,必須符合曲線的前進方向,這個可用“曲線導數的幾何意義”搞定:曲線某點的導數,正好為該點切線的斜率(換個角度考慮,其實就是飛機圖標的旋轉角度)

搗鼓一陣后,代碼出來了:

先定義一個飛機的實體類(為方便,暫時用小三角形代替)

package  
{
	import flash.display.Shape;
	/**
	 * 飛機實體類
	 * @author jimmy.yang
	 */
	public class Plane extends Shape
	{
		
		public function Plane() 
		{
			//用一個小三角來模擬飛機
			graphics.lineStyle(1, 0xff0000, 1);			
			graphics.beginFill(0xff0000, 1);
			graphics.moveTo( -50, -25);
			graphics.lineTo(50, 0);
			graphics.lineTo( -50, 25);
			graphics.lineTo( -50, -25);
			graphics.endFill();		
		}
		
		public function setAngle(y:Number,x:Number) {
			this.rotation = Math.atan2(y,x) * 180 / Math.PI;
		}
		
	}

}

 下面是生成曲線及調整飛機頭朝向的代碼:

package 
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.text.TextField;

	/**
	 * 二次貝茲曲線,生成飛機路線圖
	 * @author jimmy.yang (yjmyzz@126.com 菩提樹下的楊過 http://yjmyzz.cnblogs.com/)
	 */
	[Frame(factoryClass="Preloader")]
	public class Main extends Sprite 
	{		
		
		public function Main():void 
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}

		private function init(e:Event = null):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);		
			testBzCurve();
		}
		
		private function testBzCurve():void {
			
			var txtP0:TextField = new TextField();
			var txtP1:TextField = new TextField();
			var txtP3:TextField = new TextField();
			addChild(txtP0);
			addChild(txtP1);
			addChild(txtP3);
		
			var p0X:int = 100;
			var p0Y:int = 300;
			
			txtP0.x = p0X-10;
			txtP0.y = p0Y+10;
			txtP0.text = "浦東(PVG)";
			
			var p1X:int = 300;
			var p1Y:int = 250;
			txtP1.x = p1X;
			txtP1.y = p1Y+20;
			txtP1.text = "西安(XIY)";
			
			var p2X:int = 500;
			var p2Y:int = 50;
			txtP3.x = p2X+5;
			txtP3.y = p2Y;
			txtP3.text = "北京(PEK)";
			
			
			//人為抬高控制點,以便讓曲線經過控制點
			p1X = p1X * 2 - (p0X + p2X) / 2;
			p1Y = p1Y * 2 - (p1Y + p2Y) / 2;
				
			//生成10個示例點
			for (var t:Number = 0; t <=1; t+=0.1) 
			{		
				//二次Bz曲線的公式
				var x:Number = (1 - t) * (1 - t) * p0X + 2 * t * (1 - t) * p1X + t * t * p2X;
				var y:Number = (1 - t) * (1 - t) * p0Y + 2 * t * (1 - t) * p1Y + t * t * p2Y;				
				
				
				
				//Bz曲線在t點時的導數坐標
				var Fx:Number = 2 * (t - 1) * p0X + 2 * (1 - 2 * t) * p1X + 2 * t * p2X;
				var Fy:Number = 2 * (t - 1) * p0Y + 2 * (1 - 2 * t) * p1Y + 2 * t * t * p2Y;
				
				
				//放入小飛機
				var p = new Plane();
				addChild(p);
				p.x = x;
				p.y = y;
				p.scaleX = 0.2;
				p.scaleY = 0.2;
				p.setAngle(Fy, Fx);//導數的幾何意義
				
				
				
			}
			
			//畫出Bz曲線(當背景用)
			graphics.lineStyle(1, 0x000000, 0.5);
			graphics.moveTo(p0X, p0Y);
			graphics.curveTo(p1X, p1Y, p2X, p2Y);
			
			
		}
		
		

	}

}

 無圖無真相:

感慨:數學真心有用!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM