1package com.yahoo.astra.utils
2{
3	import flash.display.Graphics;
4	import flash.geom.Point;
5
6	/**
7	 * Utility functions for drawing to <code>Graphics</code> objects.
8	 *
9	 * @author Josh Tynjala
10	 * @see flash.display.Graphics
11	 */
12	public class GraphicsUtil
13	{
14		/**
15		 * @private
16		 * Draws a wedge.
17		 *
18		 * @param x				x component of the wedge's center point
19		 * @param y				y component of the wedge's center point
20		 * @param startAngle	starting angle in degrees
21		 * @param arc			sweep of the wedge. Negative values draw clockwise.
22		 * @param radius		radius of wedge. If [optional] yRadius is defined, then radius is the x radius.
23		 * @param yRadius		[optional] y radius for wedge.
24		 */
25		public static function drawWedge(target:Graphics, x:Number, y:Number, startAngle:Number, arc:Number, radius:Number, yRadius:Number = NaN):void
26		{
27			// move to x,y position
28			target.moveTo(x, y);
29
30			// if yRadius is undefined, yRadius = radius
31			if(isNaN(yRadius))
32			{
33				yRadius = radius;
34			}
35
36			// limit sweep to reasonable numbers
37			if(Math.abs(arc) > 360)
38			{
39				arc = 360;
40			}
41
42			// Flash uses 8 segments per circle, to match that, we draw in a maximum
43			// of 45 degree segments. First we calculate how many segments are needed
44			// for our arc.
45			var segs:int = Math.ceil(Math.abs(arc) / 45);
46
47			// Now calculate the sweep of each segment.
48			var segAngle:Number = arc / segs;
49
50			// The math requires radians rather than degrees. To convert from degrees
51			// use the formula (degrees/180)*Math.PI to get radians.
52			var theta:Number = -(segAngle / 180) * Math.PI;
53
54			// convert angle startAngle to radians
55			var angle:Number = -(startAngle / 180) * Math.PI;
56
57			// draw the curve in segments no larger than 45 degrees.
58			if(segs > 0)
59			{
60				// draw a line from the center to the start of the curve
61				var ax:Number = x + Math.cos(startAngle / 180 * Math.PI) * radius;
62				var ay:Number = y + Math.sin(-startAngle / 180 * Math.PI) * yRadius;
63				target.lineTo(ax, ay);
64
65				// Loop for drawing curve segments
66				for(var i:int = 0; i < segs; i++)
67				{
68					angle += theta;
69					var angleMid:Number = angle - (theta / 2);
70					var bx:Number = x + Math.cos(angle) * radius;
71					var by:Number = y + Math.sin(angle) * yRadius;
72					var cx:Number = x + Math.cos(angleMid) * (radius / Math.cos(theta / 2));
73					var cy:Number = y + Math.sin(angleMid) * (yRadius / Math.cos(theta / 2));
74					target.curveTo(cx, cy, bx, by);
75				}
76				// close the wedge by drawing a line to the center
77				target.lineTo(x, y);
78			}
79		}
80
81		/**
82		 * Draws a dashed line between two points.
83		 *
84		 * @param xStart	The x position of the start of the line
85		 * @param yStart	The y position of the start of the line
86		 * @param xEnd		The x position of the end of the line
87		 * @param yEnd		The y position of the end of the line
88		 * @param dashSize	the size of dashes, in pixels
89		 * @param gapSize	the size of gaps between dashes, in pixels
90		 */
91		public static function drawDashedLine(target:Graphics, xStart:Number, yStart:Number, xEnd:Number, yEnd:Number, dashSize:Number = 10, gapSize:Number = 10):void
92		{
93			// calculate the length of a segment
94			var segmentLength:Number = dashSize + gapSize;
95
96			// calculate the length of the dashed line
97			var xDelta:Number = xEnd - xStart;
98			var yDelta:Number = yEnd - yStart;
99			var delta:Number = Math.sqrt(Math.pow(xDelta, 2) + Math.pow(yDelta, 2));
100
101			// calculate the number of segments needed
102			var segmentCount:int = Math.floor(Math.abs(delta / segmentLength));
103
104			// get the angle of the line in radians
105			var radians:Number = Math.atan2(yDelta, xDelta);
106
107			// start the line here
108			var xCurrent:Number = xStart;
109			var yCurrent:Number = yStart;
110
111			// add these to cx, cy to get next seg start
112			xDelta = Math.cos(radians) * segmentLength;
113			yDelta = Math.sin(radians) * segmentLength;
114
115			// loop through each segment
116			for(var i:int = 0; i < segmentCount; i++)
117			{
118				target.moveTo(xCurrent, yCurrent);
119				target.lineTo(xCurrent + Math.cos(radians) * dashSize, yCurrent + Math.sin(radians) * dashSize);
120				xCurrent += xDelta;
121				yCurrent += yDelta;
122			}
123
124			// handle last segment as it is likely to be partial
125			target.moveTo(xCurrent, yCurrent);
126			delta = Math.sqrt((xEnd - xCurrent) * (xEnd - xCurrent) + (yEnd - yCurrent) * (yEnd - yCurrent));
127
128			if(delta > dashSize)
129			{
130				// segment ends in the gap, so draw a full dash
131				target.lineTo(xCurrent + Math.cos(radians) * dashSize, yCurrent + Math.sin(radians) * dashSize);
132			}
133			else if(delta > 0)
134			{
135				// segment is shorter than dash so only draw what is needed
136				target.lineTo(xCurrent + Math.cos(radians) * delta, yCurrent + Math.sin(radians) * delta);
137			}
138
139			// move the pen to the end position
140			target.moveTo(xEnd, yEnd);
141		}
142
143	}
144}