Monthly archive December 2009

 
 

Flex4 Arc class (for Beta 2)

The Wedge FilledElement for Flex4 previously posted is not compatible with Flex4 Beta2.

The updated class (called Arc) is as follows.

package 
{
	import flash.display.Graphics;
	
	import spark.primitives.Ellipse;
	
	public class Arc extends Ellipse
	{
		public function Arc()
		{
			super();
		}
		
		private var _angle:Number = 0;
		
		[Inspectable(category="General")]
		/**
		 * Start angle for the wedge, in degrees. Zero degrees is 3 O'clock, or East.
		 */
		public function get angle():Number
		{
			return _angle;
		}
		
		public function set angle(value:Number):void
		{
			if (value != _angle)
			{
				_angle = value;
				invalidateSize();
				invalidateDisplayList();
				invalidateParentSizeAndDisplayList();
			}
		}
		
		private var _arc:Number = 0;
		
		[Inspectable(category="General")]
		/**
		 * Arc angle for the wedge, in degrees.
		 */
		public function get arc():Number
		{
			return _arc;
		}
		
		public function set arc(value:Number):void
		{
			if (value != _arc)
			{
				_arc = value;
				invalidateSize();
				invalidateDisplayList();
				invalidateParentSizeAndDisplayList();
			}
		}
		private var _thickness:Number = 0;
		
		[Inspectable(category="General")]
		/**
		 * Thickness of the wedge, measured inward from radius. 
		 */
		public function get thickness():Number
		{
			return _thickness;
		}
		
		public function set thickness(value:Number):void
		{
			if (value != _thickness)
			{
				_thickness = value;
				invalidateSize();
				invalidateDisplayList();
				invalidateParentSizeAndDisplayList();
			}
		}
		
		private var _radius:Number = 0;
		
		[Inspectable(category="General")]
		/**
		 * Exterior radius of the wedge
		 */
		public function get radius():Number
		{
			return _radius;
		}
		
		public function set radius(value:Number):void
		{
			if (value != _radius)
			{
				_radius = value;
				invalidateSize();
				invalidateDisplayList();
				invalidateParentSizeAndDisplayList();
			}
		}
		
		
		override protected function draw(g:Graphics):void
		{
			var xo:Number = drawX + (width/2);
			var yo:Number = drawY + (width/2);
			
			var workingArc:Number = _arc;
			// limit sweep to reasonable numbers
			if (Math.abs(workingArc) > 360)
				workingArc = 360;
			
			// Flash uses 8 segments per circle, to match that, we draw in a maximum
			// of 45 degree segments. First we calculate how many segments are needed
			// for our arc.
			var segs:Number = Math.ceil(Math.abs(workingArc) / 45);
			
			// Now calculate the sweep of each segment.
			var segAngle_a:Number = workingArc / segs
			var segAngle_b:Number = -workingArc / segs;
			
			// The math requires radians rather than degrees. To convert from degrees
			// use the formula (degrees/180)*Math.PI to get radians.
			var theta_a:Number = -(segAngle_a / 180) * Math.PI;
			var theta_b:Number = -(segAngle_b / 180) * Math.PI;
			
			// convert angle workingAngle to radians
			var workingAngle:Number = _angle;
			var angle:Number = -(workingAngle / 180) * Math.PI;
			
			// draw the curve in segments no larger than 45 degrees.
			if (segs > 0)
			{
				// draw a line from the end of the interior curve to the start of the exterior curve
				var workingRadius:Number = _radius;
				var ax:Number = xo + Math.cos(workingAngle / 180 * Math.PI) * workingRadius;
				var ay:Number = yo + Math.sin(-workingAngle / 180 * Math.PI) * workingRadius;
				g.moveTo(ax, ay);
				
				// Loop for drawing exterior  curve segments
				for (var i:int = 0; i < segs; i++)
				{
					angle += theta_a;
					var angleMid:Number;
					angleMid = angle - (theta_a / 2);
					var bx:Number = xo + Math.cos(angle) * workingRadius;
					var by:Number = yo + Math.sin(angle) * workingRadius;
					var cx:Number = xo + Math.cos(angleMid) * (workingRadius / Math.cos(theta_a / 2));
					var cy:Number = yo + Math.sin(angleMid) * (workingRadius / Math.cos(theta_a / 2));
					g.curveTo(cx, cy, bx, by);
				}
				
				// draw a line from the end of the exterior curve to the start of the interior curve
				workingAngle += workingArc;
				angle = -(workingAngle / 180) * Math.PI;
				
				// draw the interior (subtractive) wedge
				// draw a line from the center to the start of the interior curve
				var interiorRadius:Number = workingRadius - _thickness;
				var dx:Number = xo + Math.cos(workingAngle / 180 * Math.PI) * interiorRadius;
				var dy:Number = yo + Math.sin(-workingAngle / 180 * Math.PI) * interiorRadius;
				g.lineTo(dx, dy);
				
				// Loop for drawing interior curve segments
				for (i = 0; i < segs; i++)
				{
					angle += theta_b;
					angleMid = angle - (theta_b / 2);
					bx = xo + Math.cos(angle) * interiorRadius;
					by = yo + Math.sin(angle) * interiorRadius;
					cx = xo + Math.cos(angleMid) * (interiorRadius / Math.cos(theta_b / 2));
					cy = yo + Math.sin(angleMid) * (interiorRadius / Math.cos(theta_b / 2));
					g.curveTo(cx, cy, bx, by);
				}
				g.lineTo(ax, ay);
			}
		}
		
	}
}