AS3 三角形填充

		private var bmd:BitmapData = new BitmapData(800,600, false, 0);
		private var bmp:Bitmap = new Bitmap(bmd);
//		private var clip:Rectangle = new Rectangle(120,150,40,30);
		private var clip:Rectangle = new Rectangle(0,0,800,600);
//		private var clip:Rectangle = new Rectangle(80,0,70,600);
		public function GeometryTest()
		{
			addChild(bmp);
//			flatBottom(new Point(100,200),new Point(50,100),new Point(150,100));
//			flatTop(new Point(50,100), new Point(150,100), new Point(100,0));
//			drawTriangle(new Point(30,200),new Point(50,80),new Point(150,90));
			stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
		}
		private var count:int = 0;
		protected function onEnterFrame(event:Event):void
		{
			if(count == 0)
			{
				bmd.fillRect(clip,0);
				count = 10;
				drawTriangle(new Point(Math.random()*800,300),new Point(Math.random()*800,500),new Point(Math.random()*800,200));
			}
			count--;
		}
		
		public function drawTriangle(p1:Point, p2:Point, p3:Point):void
		{
			var x1:Number = p1.x, y1:Number = p1.y;
			var x2:Number = p2.x, y2:Number = p2.y;
			var x3:Number = p3.x, y3:Number = p3.y;
			//三點共線 則不能成爲三角形
			if((x1 == x2 && x2 == x3) || (y1 == y2 && y2 == y3))
			{
				return;
			}
			
			//讓點按照 P1 P2 P3 的y值從大到小排序
			var tempX:Number;
			var tempY:Number;
			if(y1 < y2)
			{
				tempX = x2;
				x2 = x1;
				x1 = tempX;
				
				tempY = y2;
				y2 = y1;
				y1 = tempY;
			}
			
			if(y1 < y3)
			{
				tempX = x3;
				x3 = x1;
				x1 = tempX;
				
				tempY = y3;
				y3 = y1;
				y1 = tempY;
			}
			
			if(y2 < y3)
			{
				tempX = x3;
				x3 = x2;
				x2 = tempX;
				
				tempY = y3;
				y3 = y2;
				y2 = tempY;
			}
			
			//如果所有定點都在裁剪區域外則不能繪圖
			if(y3 > clip.bottom || y1 < clip.top || 
				(x1 < clip.left && x2 < clip.left && x3 < clip.left) ||
				(x1 > clip.right && x2 > clip.right && x3 > clip.right))
			{
				return;
			}
			
			var temp1:Point = new Point(x1, y1);
			var temp2:Point = new Point(x2, y2);
			var temp3:Point = new Point(x3, y3);
			//平頂
			if(y1 == y2)
			{
				flatTop(temp1, temp2, temp3);
			}else if(y2 == y3)//平底
			{
				flatBottom(temp1, temp2, temp3);
			}else
			{
				//要求出 1-3邊上的點new_x, 其中 2-new_x 可以將三角性分爲平頂三角形和平底三角形
				//公式畫圖可得,就是求 當走過 y2-y3 個步長時 ,x3 在 1-3邊上 所走的距離
				var newX:Number = x3 + (y2 - y3)*(x3 -x1)/(y3 - y1);
				var tempNew:Point = new Point(newX, y2);
				
				flatTop(temp2, tempNew, temp3);
				flatBottom(temp1, tempNew, temp2);
			}
		}
		
		//畫平底即底邊比頂點的Y值小
		public function flatBottom(p1:Point, p2:Point, p3:Point):void
		{
			bmd.lock();
			//指定p1爲底點,p2-p3爲平底
			var x1:Number = p1.x, y1:Number = p1.y;
			var x2:Number = p2.x, y2:Number = p2.y;
			var x3:Number = p3.x, y3:Number = p3.y;
			//保證 x2 是左斜邊,x3是右斜邊
			if(x2 > x3)
			{
				var temp:Number = x2;
				x2 = x3;
				x3 = temp;
			}
			//計算斜率
			var dxyLeft:Number = (x2 - x1)/(y2 - y1);//是通過Y的增加來求X的變化率,所以是斜率的倒數
			var dxyRight:Number = (x3 - x1)/(y3 - y1);
			
			var xs:Number = x2;
			var xe:Number = x3;
			
			if(y1 > clip.bottom)
			{
				xs = xs + dxyLeft*(-y1 + clip.bottom);//當前的點xs + 走過(-y1 + clip.top)步的變化率,就是需要的xs點
				xe = xe + dxyRight*(-y1 + clip.bottom);//當前的點xe + 走過(-y1 + clip.top)步的變化率,就是需要的xe點
				y1 = clip.bottom;
			}
			if(y3 < clip.top)
			{
				y3 = clip.top;
			}
			var y:int;
			var x:int;
			//假如x點都在裁剪區域內
			if(x1 >= clip.left && x1 <= clip.right &&
				x2 >= clip.left && x2 <= clip.right &&
				x3 >= clip.left && x3 <= clip.right)
			{
				for(y = y3; y <= y1; y++)
				{
					//drawLine(new Point(xs, y), new Point(xe, y), 0x00ff00);
					for(x = xs; x <= xe; x++)
					{
						bmd.setPixel32(x, y, 0xffffff*Math.random());
					}
					xs += dxyLeft;
					xe += dxyRight;
				}
			}else//加入有x點不在裁剪區域內則每增加一步,就要判斷x是否超出clip範圍,如果超出則映射到對應的clip邊上(當然也可以直接用這個else的所有內容,而不必寫這個if-else, 寫if-else 主要是爲了讓if更快)
			{
				var left:Number = xs;
				var right:Number = xe;
				for(y = y3; y <= y1; y++)
				{
					left = xs;
					right = xe;
					if(left < clip.left)
					{
						left = clip.left;
						if(right < clip.left)
						{
							continue;
						}
					}
					if(right > clip.right)
					{
						right = clip.right;
						if(left > clip.right)
						{
							continue;
						}
					}
//					drawLine(new Point(left, y), new Point(right, y), 0x00ff00);
					for(x = left; x <= right; x++)
					{
						bmd.setPixel32(x, y, 0xff0000);
					}
					xs += dxyLeft;
					xe += dxyRight;
				}
			}
			bmd.unlock();
		}
		
		//畫平頂即底邊比頂點的Y值大
		public function flatTop(p1:Point, p2:Point, p3:Point):void
		{
			bmd.lock();
			//指定p3爲底點,p1-p2爲平頂
			var x1:Number = p1.x, y1:Number = p1.y;
			var x2:Number = p2.x, y2:Number = p2.y;
			var x3:Number = p3.x, y3:Number = p3.y;
			//保證 x1 是左斜邊,x2是右斜邊
			if(x1 > x2)
			{
				var temp:Number = x1;
				x1 = x2;
				x2 = temp;
			}
			//計算斜率
			var dxyLeft:Number = (x1 - x3)/(y1 - y3);//是通過Y的增加來求X的變化率,所以是斜率的倒數
			var dxyRight:Number = (x2 - x3)/(y2 - y3);
			var xs:Number = x3;//如果xs 或者 xe 是 int 型的話,需要加0.5 除去誤差,相當於四捨五入到整點,比如1.8 +0.5 = 2.3 ≈ 2 , 1.2 + 0.5 = 1.7 ≈ 1
			var xe:Number = x3;
			
			if(y3 < clip.top)
			{
				xs = xs + dxyLeft*(-y3 + clip.top);
				xe = xe + dxyRight*(-y3 + clip.top);
				y3 = clip.top;
			}
			
			if(y1 > clip.bottom)
			{
				y1 = clip.bottom;
			}
			
			var y:int;
			var x:int;
			//假如x點都在裁剪區域內
			if(x1 >= clip.left && x1 <= clip.right &&
				x2 >= clip.left && x2 <= clip.right &&
				x3 >= clip.left && x3 <= clip.right)
			{
				for(y = y3; y <= y1; y++)
				{
					for(x = xs; x <= xe; x++)
					{
						bmd.setPixel32(x, y, 0xffffff*Math.random());
					}
					
					xs += dxyLeft;
					xe += dxyRight;
				}
			}else
			{
				var left:Number = xs;
				var right:Number = xe;
				for(y = y3; y <= y1; y++)
				{
					left = xs;
					right = xe;
					if(left < clip.left)
					{
						left = clip.left;
						if(right < clip.left)
						{
							continue;
						}
					}
					if(right > clip.right)
					{
						right = clip.right;
						if(left > clip.right)
						{
							continue;
						}
					}
					for(x = left; x <= right; x++)
					{
						bmd.setPixel32(x, y, 0xffff00);
					}
					
					xs += dxyLeft;
					xe += dxyRight;
				}
			}
			bmd.unlock();
		}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章