1  /*
     2   Copyright aswing.org, see the LICENCE.txt.
     3  */
     4   
     5  import org.aswing.graphices.Brush;
     6  import org.aswing.graphices.Pen;
     7   
     8  /**
     9   * Graphics, use to paint graphics contexts on a MovieClip.
    10   * @author iiley
    11   */
    12  class org.aswing.graphices.Graphics {
    13  	
    14  	private var target_mc:MovieClip;
    15  	private var brush:Brush;
    16  	
    17  	/**
    18  	 * Create a graphics with target MovieClip.
    19  	 * @param target_mc where the graphics contexts will be paint on.
    20  	 */
    21  	public function Graphics(target_mc:MovieClip){
    22  		this.target_mc = target_mc;
    23  	}
    24  	
    25  	private function setTarget(target_mc:MovieClip):Void{
    26  		this.target_mc = target_mc;
    27  	}
    28  	
    29  	private function dispose():Void{
    30  		target_mc = null;
    31  	}
    32  	
    33  	private function startPen(p:Pen):Void{
    34  		p.setTo(target_mc);
    35  	}
    36  	
    37  	private function endPen():Void{
    38  		target_mc.lineStyle();
    39  		target_mc.moveTo(0, 0); //avoid a drawing error
    40  	}
    41  	
    42  	private function startBrush(b:Brush):Void{
    43  		brush = b;
    44  		b.beginFill(target_mc);
    45  	}
    46  	
    47  	private function endBrush():Void{
    48  		brush.endFill(target_mc);
    49  		target_mc.moveTo(0, 0); //avoid a drawing error
    50  	}
    51  	
    52  	//-------------------------------Public Functions-------------------
    53  	/**
    54  	 * Clears the graphics contexts drawn on the target MovieClip.
    55  	 */
    56  	private function clear():Void {
    57  		if(target_mc!=undefined) target_mc.clear();
    58  	}
    59  	
    60  	/**
    61  	 * Draws a line. 
    62  	 * Between the points (x1, y1) and (x2, y2) in the target MovieClip. 
    63  	 * @param p the pen to draw
    64  	 * @param x1 the x corrdinate of the first point.
    65  	 * @param y1 the y corrdinate of the first point.
    66  	 * @param x2 the x corrdinate of the sencod point.
    67  	 * @param y2 the y corrdinate of the sencod point.
    68  	 */
    69  	public function drawLine(p:Pen, x1:Number, y1:Number, x2:Number, y2:Number):Void {
    70  		startPen(p);
    71  		target_mc.moveTo(x1, y1);
    72  		target_mc.lineTo(x2, y2);
    73  		//target_mc.lineTo(x1, y1);//line back to avoid a flash player bug
    74  		endPen();
    75  	}
    76  	
    77  	/**
    78  	 * Draws a polygon.
    79  	 * Start with the points[0] and end of the points[0] as a closed path. 
    80  	 * 
    81  	 * @param p the pen to draw
    82  	 * @param points the Array contains all vertex points in the polygon.
    83  	 */
    84  	public function drawPolygon(p:Pen, points:Array):Void{
    85  		startPen(p);
    86  		polygon(points);
    87  		endPen();
    88  	}
    89  	
    90  	/**
    91  	 * Fills a polygon.
    92  	 * Start with the points[0] and end of the points[0] as a closed path. 
    93  	 * 
    94  	 * @param b the brush to fill.
    95  	 * @param points the Array contains all vertex points in the polygon.
    96  	 */	
    97  	public function fillPolygon(b:Brush, points:Array):Void{
    98  		startBrush(b);
    99  		polygon(points);
   100  		endBrush();
   101  	}
   102  	
   103  	/**
   104  	 * Fills a polygon ring.
   105  	 * @param b the brush to fill.
   106  	 * @param points1 the first polygon's points.
   107  	 * @param points2 the second polygon's points.
   108  	 */
   109  	public function fillPolygonRing(b:Brush, points1:Array, points2:Array):Void{
   110  		startBrush(b);
   111  		polygon(points1);
   112  		polygon(points2);
   113  		endBrush();
   114  	}
   115  	
   116  	/**
   117  	 * Draws a rectange.
   118  	 * @param pen the pen to draw.
   119  	 * @param x the left top the rectange bounds' x corrdinate.
   120  	 * @param y the left top the rectange bounds' y corrdinate.
   121  	 * @param w the width of rectange bounds.
   122  	 * @param h the height of rectange bounds.
   123  	 */
   124  	public function drawRectangle(pen:Pen, x:Number, y:Number, w:Number, h:Number):Void {
   125  		this.startPen(pen);
   126  		this.rectangle(x, y, w, h);
   127  		this.endPen();
   128  	}
   129  	
   130  	/**
   131  	 * Fills a rectange.
   132  	 * @param brush the brush to fill.
   133  	 * @param x the left top the rectange bounds' x corrdinate.
   134  	 * @param y the left top the rectange bounds' y corrdinate.
   135  	 * @param w the width of rectange bounds.
   136  	 * @param h the height of rectange bounds.
   137  	 */	
   138  	public function fillRectangle(brush:Brush, x:Number, y:Number, width:Number, height:Number):Void{
   139  		startBrush(brush);
   140  		rectangle(x,y,width,height);
   141  		endBrush();
   142  	}
   143  	
   144  	/**
   145  	 * Fills a rectange ring.
   146  	 * @param brush the brush to fill.
   147  	 * @param cx the center of the ring's x corrdinate.
   148  	 * @param cy the center of the ring's y corrdinate.
   149  	 * @param w1 the first rectange's width.
   150  	 * @param h1 the first rectange's height.
   151  	 * @param w2 the second rectange's width.
   152  	 * @param h2 the second rectange's height.
   153  	 */	
   154  	public function fillRectangleRing(brush:Brush, cx:Number, cy:Number, w1:Number, h1:Number, w2:Number, h2:Number):Void{
   155  		startBrush(brush);
   156  		rectangle(cx-w1/2, cy-h1/2, w1, h1);
   157  		rectangle(cx-w2/2, cy-h2/2, w2, h2);
   158  		endBrush();
   159  	}
   160  	
   161  	/**
   162  	 * Fills a rectange ring with specified thickness.
   163  	 * @param brush the brush to fill.
   164  	 * @param x the left top the ring bounds' x corrdinate.
   165  	 * @param y the left top the ring bounds' y corrdinate.
   166  	 * @param w the width of ring periphery bounds.
   167  	 * @param h the height of ring periphery bounds.
   168  	 * @param t the thickness of the ring.
   169  	 */
   170  	public function fillRectangleRingWithThickness(brush:Brush, x:Number, y:Number, w:Number, h:Number, t:Number):Void{
   171  		startBrush(brush);
   172  		rectangle(x, y, w, h);
   173  		rectangle(x+t, y+t, w - t*2, h - t*2);
   174  		endBrush();
   175  	}	
   176  	
   177  	/**
   178  	 * Draws a circle.
   179  	 * @param p the pen to draw.
   180  	 * @param cx the center of the circle's x corrdinate.
   181  	 * @param cy the center of the circle's y corrdinate.
   182  	 * @param radius the radius of the circle.
   183  	 */
   184  	public function drawCircle(p:Pen, cx:Number, cy:Number, radius:Number):Void{
   185  		startPen(p);
   186  		circle(cx, cy, radius);
   187  		endPen();		
   188  	}
   189  	
   190  	/**
   191  	 * Fills a circle.
   192  	 * @param b the brush to draw.
   193  	 * @param cx the center of the circle's x corrdinate.
   194  	 * @param cy the center of the circle's y corrdinate.
   195  	 * @param radius the radius of the circle.
   196  	 */
   197  	public function fillCircle(b:Brush, cx:Number, cy:Number, radius:Number):Void{
   198  		startBrush(b);
   199  		circle(cx, cy, radius);
   200  		endBrush();
   201  	}
   202  	
   203  	/**
   204  	 * Fills a circle ring.
   205  	 * @param b the brush to draw.
   206  	 * @param cx the center of the ring's x corrdinate.
   207  	 * @param cy the center of the ring's y corrdinate.
   208  	 * @param r1 the first circle radius.
   209  	 * @param r2 the second circle radius.
   210  	 */
   211  	public function fillCircleRing(b:Brush, cx:Number, cy:Number, r1:Number, r2:Number):Void{
   212  		startBrush(b);
   213  		circle(cx, cy, r1);
   214  		circle(cx, cy, r2);
   215  		endBrush();
   216  	}
   217  	
   218  	/**
   219  	 * Fills a circle ring with specified thickness.
   220  	 * @param b the brush to draw.
   221  	 * @param cx the center of the ring's x corrdinate.
   222  	 * @param cy the center of the ring's y corrdinate.
   223  	 * @param r the radius of circle periphery.
   224  	 * @param t the thickness of the ring.
   225  	 */
   226  	public function fillCircleRingWithThickness(b:Brush, cx:Number, cy:Number, r:Number, t:Number):Void{
   227  		startBrush(b);
   228  		circle(cx, cy, r);
   229  		r -= t;
   230  		circle(cx, cy, r);
   231  		endBrush();
   232  	}
   233  	
   234  	/**
   235  	 * Draws a ellipse.
   236  	 * @param brush the brush to fill.
   237  	 * @param x the left top the ellipse bounds' x corrdinate.
   238  	 * @param y the left top the ellipse bounds' y corrdinate.
   239  	 * @param w the width of ellipse bounds.
   240  	 * @param h the height of ellipse bounds.
   241  	 */	
   242  	public function drawEllipse(p:Pen, x:Number, y:Number, width:Number, height:Number):Void{
   243  		startPen(p);
   244  		ellipse(x, y, width, height);
   245  		endPen();
   246  	}
   247  	
   248  	/**
   249  	 * Fills a rectange.
   250  	 * @param brush the brush to fill.
   251  	 * @param x the left top the ellipse bounds' x corrdinate.
   252  	 * @param y the left top the ellipse bounds' y corrdinate.
   253  	 * @param w the width of ellipse bounds.
   254  	 * @param h the height of ellipse bounds.
   255  	 */		
   256  	public function fillEllipse(b:Brush, x:Number, y:Number, width:Number, height:Number):Void{
   257  		startBrush(b);
   258  		ellipse(x, y, width, height);
   259  		endBrush();
   260  	}
   261  	
   262  	/**
   263  	 * Fill a ellipse ring.
   264  	 * @param brush the brush to fill.
   265  	 * @param cx the center of the ring's x corrdinate.
   266  	 * @param cy the center of the ring's y corrdinate.
   267  	 * @param w1 the first eclipse's width.
   268  	 * @param h1 the first eclipse's height.
   269  	 * @param w2 the second eclipse's width.
   270  	 * @param h2 the second eclipse's height.
   271  	 */
   272  	public function fillEllipseRing(brush:Brush, cx:Number, cy:Number, w1:Number, h1:Number, w2:Number, h2:Number):Void{
   273  		startBrush(brush);
   274  		ellipse(cx-w1/2, cy-h1/2, w1, h1);
   275  		ellipse(cx-w2/2, cy-h2/2, w2, h2);
   276  		endBrush();
   277  	}
   278  	
   279  	/**
   280  	 * Fill a ellipse ring with specified thickness.
   281  	 * @param brush the brush to fill.
   282  	 * @param x the left top the ring bounds' x corrdinate.
   283  	 * @param y the left top the ring bounds' y corrdinate.
   284  	 * @param w the width of ellipse periphery bounds.
   285  	 * @param h the height of ellipse periphery bounds.
   286  	 * @param t the thickness of the ring.
   287  	 */
   288  	public function fillEllipseRingWithThickness(brush:Brush, x:Number, y:Number, w:Number, h:Number, t:Number):Void{
   289  		startBrush(brush);
   290  		ellipse(x, y, w, h);
   291  		ellipse(x+t, y+t, w-t*2, h-t*2);
   292  		endBrush();
   293  	}	
   294  	
   295  	/**
   296  	 * Draws a round rectangle.
   297  	 * @param pen the pen to draw.
   298  	 * @param x the left top the rectangle bounds' x corrdinate.
   299  	 * @param y the left top the rectangle bounds' y corrdinate.
   300  	 * @param width the width of rectangle bounds.
   301  	 * @param height the height of rectangle bounds.
   302  	 * @param radius the top left corner's round radius.
   303  	 * @param trR the top right corner's round radius. (miss this param default to same as radius)
   304  	 * @param blR the bottom left corner's round radius. (miss this param default to same as radius)
   305  	 * @param brR the bottom right corner's round radius. (miss this param default to same as radius)
   306  	 */
   307  	public function drawRoundRect(pen:Pen, x:Number, y:Number, width:Number, height:Number, radius:Number, trR:Number, blR:Number, brR:Number):Void{
   308  		startPen(pen);
   309  		roundRect(x, y, width, height, radius, trR, blR, brR);
   310  		endPen();
   311  	}
   312  	
   313  	/**
   314  	 * Fills a round rectangle.
   315  	 * @param brush the brush to fill.
   316  	 * @param x the left top the rectangle bounds' x corrdinate.
   317  	 * @param y the left top the rectangle bounds' y corrdinate.
   318  	 * @param width the width of rectangle bounds.
   319  	 * @param height the height of rectangle bounds.
   320  	 * @param radius the top left corner's round radius.
   321  	 * @param trR the top right corner's round radius. (miss this param default to same as radius)
   322  	 * @param blR the bottom left corner's round radius. (miss this param default to same as radius)
   323  	 * @param brR the bottom right corner's round radius. (miss this param default to same as radius)
   324  	 */	
   325  	public function fillRoundRect(brush:Brush, x:Number, y:Number, width:Number, height:Number, radius:Number, trR:Number, blR:Number, brR:Number):Void{
   326  		startBrush(brush);
   327  		roundRect(x,y,width,height,radius,trR,blR,brR);
   328  		endBrush();
   329  	}
   330  	
   331  	/**
   332  	 * Fill a round rect ring.
   333  	 * @param brush the brush to fill
   334  	 * @param cx the center of the ring's x corrdinate
   335  	 * @param cy the center of the ring's y corrdinate
   336  	 * @param w1 the first round rect's width
   337  	 * @param h1 the first round rect's height
   338  	 * @param r1 the first round rect's round radius
   339  	 * @param w2 the second round rect's width
   340  	 * @param h2 the second round rect's height
   341  	 * @param r2 the second round rect's round radius
   342  	 */	
   343  	public function fillRoundRectRing(brush:Brush,cx:Number,cy:Number,w1:Number,h1:Number,r1:Number, w2:Number, h2:Number, r2:Number):Void{
   344  		startBrush(brush);
   345  		roundRect(cx-w1/2, cy-h1/2, w1, h1, r1);
   346  		roundRect(cx-w2/2, cy-h2/2, w2, h2, r2);
   347  		endBrush();
   348  	}
   349  	
   350  	/**
   351  	 * Fill a round rect ring with specified thickness.
   352  	 * @param brush the brush to fill
   353  	 * @param x the left top the ring bounds' x corrdinate
   354  	 * @param y the left top the ring bounds' y corrdinate
   355  	 * @param w the width of ring periphery bounds
   356  	 * @param h the height of ring periphery bounds
   357  	 * @param r the round radius of the round rect
   358  	 * @param t the thickness of the ring
   359  	 * @param ir the inboard round radius, default is <code>r-t</code>
   360  	 */	
   361  	public function fillRoundRectRingWithThickness(brush:Brush, x:Number, y:Number, w:Number, h:Number, r:Number, t:Number, ir:Number):Void{
   362  		startBrush(brush);
   363  		roundRect(x, y, w, h, r);
   364  		if(ir == undefined) ir = r - t;
   365  		roundRect(x+t, y+t, w-t*2, h-t*2, ir);
   366  		endBrush();
   367  	}	
   368  	
   369  	public function beginFill(brush:Brush):Void{
   370  		startBrush(brush);
   371  	}
   372  	public function endFill():Void{
   373  		endBrush();
   374  		target_mc.moveTo(0, 0); //avoid a drawing error
   375  	}
   376  	public function beginDraw(pen:Pen):Void{
   377  		startPen(pen);
   378  	}
   379  	public function endDraw():Void{
   380  		endPen();
   381  		target_mc.moveTo(0, 0); //avoid a drawing error
   382  	}
   383  	public function moveTo(x:Number, y:Number):Void{
   384  		target_mc.moveTo(x, y);
   385  	}
   386  	public function curveTo(controlX:Number, controlY:Number, anchorX:Number, anchorY:Number):Void{
   387  		target_mc.curveTo(controlX, controlY, anchorX, anchorY);
   388  	}
   389  	public function lineTo(x:Number, y:Number):Void{
   390  		target_mc.lineTo(x, y);
   391  	}
   392  	
   393  	//---------------------------------------------------------------------------
   394  	
   395  	/**
   396  	 * Paths a polygon.
   397  	 * @see #drawPolygon()
   398  	 * @see #fillPolygon()
   399  	 */
   400  	public function polygon(points:Array):Void{
   401  		target_mc.moveTo(points[0].x, points[0].y);
   402  		for(var i:Number=1; i<points.length; i++){
   403  			target_mc.lineTo(points[i].x, points[i].y);
   404  		}
   405  		target_mc.lineTo(points[0].x, points[0].y);
   406  	}
   407  	
   408  	/**
   409  	 * Paths a rectangle.
   410  	 * @see #drawRectangle()
   411  	 * @see #fillRectangle()
   412  	 */
   413  	public function rectangle(x:Number,y:Number,width:Number,height:Number):Void{
   414  		target_mc.moveTo(x, y);
   415  		target_mc.lineTo(x+width,y);
   416  		target_mc.lineTo(x+width,y+height);
   417  		target_mc.lineTo(x,y+height);
   418  		target_mc.lineTo(x,y);
   419  	}
   420  	
   421  	/**
   422  	 * Paths a ellipse.
   423  	 * @see #drawEllipse()
   424  	 * @see #fillEllipse()
   425  	 */
   426  	public function ellipse(x:Number, y:Number, width:Number, height:Number):Void{
   427  		var pi:Number = Math.PI;
   428          var xradius:Number = width/2;
   429          var yradius:Number = height/ 2;
   430          var cx:Number = x + xradius;
   431          var cy:Number = y + yradius;
   432          target_mc.moveTo(xradius + cx, 0 + cy);
   433          target_mc.curveTo(xradius + cx, (yradius * Math.tan(pi / 8)) + cy, (xradius * Math.cos(pi / 4)) + cx, (yradius * Math.sin(pi / 4)) + cy);
   434          target_mc.curveTo((xradius * Math.tan(pi / 8)) + cx, yradius + cy, 0 + cx, yradius + cy);
   435          target_mc.curveTo(((-xradius) * Math.tan(pi / 8)) + cx, yradius + cy, ((-xradius) * Math.cos(pi / 4)) + cx, (yradius * Math.sin(pi / 4)) + cy);
   436          target_mc.curveTo((-xradius) + cx, (yradius * Math.tan(pi / 8)) + cy, (-xradius) + cx, 0 + cy);
   437          target_mc.curveTo((-xradius) + cx, ((-yradius) * Math.tan(pi / 8)) + cy, ((-xradius) * Math.cos(pi / 4)) + cx, ((-yradius) * Math.sin(pi / 4)) + cy);
   438          target_mc.curveTo(((-xradius) * Math.tan(pi / 8)) + cx, (-yradius) + cy, 0 + cx, (-yradius) + cy);
   439          target_mc.curveTo((xradius * Math.tan(pi / 8)) + cx, (-yradius) + cy, (xradius * Math.cos(pi / 4)) + cx, ((-yradius) * Math.sin(pi / 4)) + cy);
   440          target_mc.curveTo(xradius + cx, ((-yradius) * Math.tan(pi / 8)) + cy, xradius + cx, 0 + cy);		
   441  	}
   442  	
   443  	/**
   444  	 * Paths a circle
   445  	 * @see #drawCircle()
   446  	 * @see #fillCircle()
   447  	 */
   448  	public function circle(cx:Number, cy:Number, r:Number):Void{
   449  		//start at top center point
   450  		ellipse(cx-r, cy-r, r*2, r*2);
   451  //		target_mc.moveTo(cx, cy - r);
   452  //		target_mc.curveTo(cx + r, cy - r, cx + r, cy);
   453  //		target_mc.curveTo(cx + r, cy + r, cx, cy + r);
   454  //		target_mc.curveTo(cx - r, cy + r, cx - r, cy);
   455  //		target_mc.curveTo(cx - r, cy - r, cx, cy - r);
   456  	}
   457  	
   458  	/**
   459  	 * Paths a round rect.
   460  	 * @see #drawRoundRect()
   461  	 * @see #fillRoundRect()
   462  	 * @param radius top left radius, if other corner radius if undefined, will be set to this radius
   463  	 */
   464  	public function roundRect(x:Number,y:Number,width:Number,height:Number, radius:Number, trR:Number, blR:Number, brR:Number):Void{
   465  		var tlR:Number = radius;
   466  		if(trR == undefined) trR = radius;
   467  		if(blR == undefined) blR = radius;
   468  		if(brR == undefined) brR = radius;
   469  		//Bottom right
   470  		target_mc.moveTo(x+blR, y+height);
   471  		target_mc.lineTo(x+width-brR, y+height);
   472  		target_mc.curveTo(x+width, y+height, x+width, y+height-blR);
   473  		//Top right
   474  		target_mc.lineTo (x+width, y+trR);
   475  		target_mc.curveTo(x+width, y, x+width-trR, y);
   476  		//Top left
   477  		target_mc.lineTo (x+tlR, y);
   478  		target_mc.curveTo(x, y, x, y+tlR);
   479  		//Bottom left
   480  		target_mc.lineTo (x, y+height-blR );
   481  		target_mc.curveTo(x, y+height, x+blR, y+height);
   482  	}
   483  	
   484  	/**
   485  	 * path a wedge.
   486  	 */
   487  	public function wedge(radius:Number, x:Number, y:Number, angle:Number, rot:Number):Void {
   488  		target_mc.moveTo(0, 0);
   489  		target_mc.lineTo(radius, 0);
   490  		var nSeg:Number = Math.floor(angle/30);
   491  		var pSeg:Number = angle-nSeg*30;
   492  		var a:Number = 0.268;
   493  		var endx:Number;
   494  		var endy:Number;
   495  		var ax:Number;
   496  		var ay:Number;
   497  		var storeCount:Number=0;
   498  		for (var i:Number = 0; i<nSeg; i++) {
   499  			endx = radius*Math.cos((i+1)*30*(Math.PI/180));
   500  			endy = radius*Math.sin((i+1)*30*(Math.PI/180));
   501  			ax = endx+radius*a*Math.cos(((i+1)*30-90)*(Math.PI/180));
   502  			ay = endy+radius*a*Math.sin(((i+1)*30-90)*(Math.PI/180));
   503  			target_mc.curveTo(ax, ay, endx, endy);
   504  			storeCount=i+1;
   505  		}
   506  		if (pSeg>0) {
   507  			a = Math.tan(pSeg/2*(Math.PI/180));
   508  			endx = radius*Math.cos((storeCount*30+pSeg)*(Math.PI/180));
   509  			endy = radius*Math.sin((storeCount*30+pSeg)*(Math.PI/180));
   510  			ax = endx+radius*a*Math.cos((storeCount*30+pSeg-90)*(Math.PI/180));
   511  			ay = endy+radius*a*Math.sin((storeCount*30+pSeg-90)*(Math.PI/180));
   512  			target_mc.curveTo(ax, ay, endx, endy);
   513  		}
   514  		target_mc.lineTo(0, 0);
   515  		target_mc._rotation = rot;
   516  		target_mc._x = x;
   517  		target_mc._y = y;
   518  	}	
   519  	
   520  	
   521  }
   522