Revision: 59825
Initial Code
Initial URL
Initial Description
Initial Title
Initial Tags
Initial Language
at October 3, 2012 22:45 by adrianparr
Initial Code
package nl.funkymonkey.drawing
{
import flash.display.*;
/**
* based on source code found at:
* http://www.macromedia.com/devnet/mx/flash/articles/adv_draw_methods.html
*
* @author Ric Ewing - version 1.4 - 4.7.2002
* @author Kevin Williams - version 2.0 - 4.7.2005
* @author Aden Forshaw - Version AS3 - 19.4.2010
* @author Sidney de Koning - Version AS3 - 20.4.2010 - errors/correct datatypes/optimized math operations
*
* Usage:
* var s : Shape = new Shape( ); // Or Sprite of MovieClip or any other Class that makes use of the Graphics class
*
* // Draw an ARC
* s.graphics.lineStyle( 4, 0xE16606 );
* DrawingShapes.drawArc( s.graphics, 50, 50, 10, 150, 60 );
*
* // Draw an BURST
* s.graphics.lineStyle( 3, 0x000000 );
* DrawingShapes.drawBurst( s.graphics, 80, 60, 3, 15, 6, 27 );
*
* // Draw an DASHED-LINE like so - - - -
* s.graphics.lineStyle( 1, 0x3C3C39 );
* DrawingShapes.drawDash( s.graphics, 120, 60, 150, 80, 2, 2 );
*
* // Draw an GEAR
* s.graphics.lineStyle( 3, 0xE16606 );
* DrawingShapes.drawGear( s.graphics, 200, 60, 13, 31, 26, 0, 7, 13 );
*
* // Draw a POLYGON
* s.graphics.lineStyle( 3, 0x0074B9 );
* DrawingShapes.drawPolygon( s.graphics, 270, 60, 7, 30, 45 );
*
* // Draw a STAR
* s.graphics.lineStyle( 2, 0x000000 );
* DrawingShapes.drawStar( s.graphics, 340, 60, 18, 24, 19, 27 );
*
* // Draw an WEDGE - good for pie charts or pacmans
* s.graphics.lineStyle( 2, 0xFFCC00 );
* DrawingShapes.drawWedge( s.graphics, 400, 60, 30, 309, 209 );
*
* // Draw a LINE
* s.graphics.lineStyle( 2, 0x0074B9 );
* DrawingShapes.drawLine( s.graphics, 440, 85, 30, DrawingShapes.VERTICAL_LINE );
*
* addChild( s );
*/
public class DrawingShapes
{
public static const HORIZONTAL_LINE:String = "DrawingShapes.horizontal";
public static const VERTICAL_LINE:String = "DrawingShapes.vertical";
public function DrawingShapes()
{
throw new ArgumentError("The DrawingShapes Class cannot be instanicated.");
}
/**
* drawDash
* Draws a dashed line from the point x1,y1 to the point x2,y2
*
* @param target Graphics the Graphics Class on which the dashed line will be drawn.
* @param x1 Number starting position on x axis - <strong>required</strong>
* @param y1 Number starting position on y axis - <strong>required</strong>
* @param x2 Number finishing position on x axis - <strong>required</strong>
* @param y2 Number finishing position on y axis - <strong>required</strong>
* @param dashLength [optional] Number the number of pixels long each dash
* will be. Default = 5
* @param spaceLength [optional] Number the number of pixels between each
* dash. Default = 5
*/
public static function drawDash(target:Graphics, x1:Number, y1:Number, x2:Number, y2:Number, dashLength:Number=5, spaceLength:Number=5):void
{
var x:Number = x2 - x1;
var y:Number = y2 - y1;
var hyp:Number = Math.sqrt((x) * (x) + (y) * (y));
var units:Number = hyp / (dashLength + spaceLength);
var dashSpaceRatio:Number = dashLength / (dashLength + spaceLength);
var dashX:Number = (x / units) * dashSpaceRatio;
var spaceX:Number = (x / units) - dashX;
var dashY:Number = (y / units) * dashSpaceRatio;
var spaceY:Number = (y / units) - dashY;
target.moveTo(x1, y1);
while (hyp > 0)
{
x1 += dashX;
y1 += dashY;
hyp -= dashLength;
if (hyp < 0)
{
x1 = x2;
y1 = y2;
}
target.lineTo(x1, y1);
x1 += spaceX;
y1 += spaceY;
target.moveTo(x1, y1);
hyp -= spaceLength;
}
target.moveTo(x2, y2);
}
/**
* Draws an arc from the starting position of x,y.
*
* @param target the Graphics Class that the Arc is drawn on.
* @param x x coordinate of the starting pen position
* @param y y coordinate of the starting pen position
* @param radius radius of Arc.
* @param arc = sweep of the arc. Negative values draw clockwise.
* @param startAngle = [optional] starting offset angle in degrees.
* @param yRadius = [optional] y radius of arc. if different than
* radius, then the arc will draw as the arc of an oval.
* default = radius.
*
* Based on mc.drawArc by Ric Ewing.
* the version by Ric assumes that the pen is at x:y before this
* method is called. I explictily move the pen to x:y to be
* consistent with the behaviour of the other methods.
*/
public static function drawArc(target:Graphics, x:Number, y:Number, radius:Number, arc:Number, startAngle:Number=0, yRadius:Number=0):void
{
if (arguments.length < 5)
{
throw new ArgumentError("DrawingShapes.drawArc() - too few parameters, need atleast 5.");
return;
}
// if startAngle is undefined, startAngle = 0
if (startAngle == 0)
{
startAngle = 0;
}
// if yRadius is undefined, yRadius = radius
if (yRadius == 0)
{
yRadius = radius;
}
// Init vars
var segAngle:Number, theta:Number, angle:Number, angleMid:Number, segs:Number, ax:Number, ay:Number, bx:Number, by:Number, cx:Number, cy:Number;
// no sense in drawing more than is needed :)
if (DrawingShapes.abs(arc) > 360)
{
arc = 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.
segs = DrawingShapes.ceil(DrawingShapes.abs(arc) / 45);
// Now calculate the sweep of each segment
segAngle = arc / segs;
// The math requires radians rather than degrees. To convert from degrees
// use the formula (degrees/180)*Math.PI to get radians.
theta = -(segAngle / 180) * Math.PI;
// convert angle startAngle to radians
angle = -(startAngle / 180) * Math.PI;
// find our starting points (ax,ay) relative to the secified x,y
ax = x - Math.cos(angle) * radius;
ay = y - Math.sin(angle) * yRadius;
// if our arc is larger than 45 degrees, draw as 45 degree segments
// so that we match Flash's native circle routines.
if (segs > 0)
{
target.moveTo(x, y);
// Loop for drawing arc segments
for (var i:int = 0; i < segs; ++i)
{
// increment our angle
angle += theta;
// find the angle halfway between the last angle and the new
angleMid = angle - (theta / 2);
// calculate our end point
bx = ax + Math.cos(angle) * radius;
by = ay + Math.sin(angle) * yRadius;
// calculate our control point
cx = ax + Math.cos(angleMid) * (radius / Math.cos(theta / 2));
cy = ay + Math.sin(angleMid) * (yRadius / Math.cos(theta / 2));
// draw the arc segment
target.curveTo(cx, cy, bx, by);
}
}
}
/**
* draws pie shaped wedges. Could be employeed to draw pie charts.
*
* @param target the Graphics on which the wedge is to be drawn.
* @param x x coordinate of the center point of the wedge
* @param y y coordinate of the center point of the wedge
* @param radius the radius of the wedge
* @param arc the sweep of the wedge. negative values draw clockwise
* @param startAngle the starting angle in degrees
* @param yRadius [optional] the y axis radius of the wedge.
* If not defined, then yRadius = radius.
*
* based on mc.drawWedge() - by Ric Ewing (ric at formequalsfunction.com) - version 1.4 - 4.7.2002
*/
public static function drawWedge(target:Graphics, x:Number, y:Number, radius:Number, arc:Number, startAngle:Number=0, yRadius:Number=0):void
{
// if yRadius is undefined, yRadius = radius
if (yRadius == 0)
{
yRadius = radius;
}
// move to x,y position
target.moveTo(x, y);
// if yRadius is undefined, yRadius = radius
if (yRadius == 0)
{
yRadius = radius;
}
// Init vars
var segAngle:Number, theta:Number, angle:Number, angleMid:Number, segs:Number, ax:Number, ay:Number, bx:Number, by:Number, cx:Number, cy:Number;
// limit sweep to reasonable numbers
if (DrawingShapes.abs(arc) > 360)
{
arc = 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.
segs = DrawingShapes.ceil(DrawingShapes.abs(arc) / 45);
// Now calculate the sweep of each segment.
segAngle = arc / segs;
// The math requires radians rather than degrees. To convert from degrees
// use the formula (degrees/180)*Math.PI to get radians.
theta = -(segAngle / 180) * Math.PI;
// convert angle startAngle to radians
angle = -(startAngle / 180) * Math.PI;
// draw the curve in segments no larger than 45 degrees.
if (segs > 0)
{
// draw a line from the center to the start of the curve
ax = x + Math.cos(startAngle / 180 * Math.PI) * radius;
ay = y + Math.sin(-startAngle / 180 * Math.PI) * yRadius;
target.lineTo(ax, ay);
// Loop for drawing curve segments
for (var i:int = 0; i < segs; ++i)
{
angle += theta;
angleMid = angle - (theta / 2);
bx = x + Math.cos(angle) * radius;
by = y + Math.sin(angle) * yRadius;
cx = x + Math.cos(angleMid) * (radius / Math.cos(theta / 2));
cy = y + Math.sin(angleMid) * (yRadius / Math.cos(theta / 2));
target.curveTo(cx, cy, bx, by);
}
// close the wedge by drawing a line to the center
target.lineTo(x, y);
}
}
/**
* start draws a star shaped polygon.
*
* <blockquote>Note that the stars by default 'point' to
* the right. This is because the method starts drawing
* at 0 degrees by default, putting the first point to
* the right of center. Negative values for points
* draws the star in reverse direction, allowing for
* knock-outs when used as part of a mask.</blockquote>
*
* @param target the Graphics that the star is drawn on
* @param x x coordinate of the center of the star
* @param y y coordinate of the center of the star
* @param points the number of points on the star
* @param innerRadius the radius of the inside angles of the star
* @param outerRadius the radius of the outside angles of the star
* @param angle [optional] the offet angle that the start is rotated
*
* based on mc.drawStar() - by Ric Ewing (ric at formequalsfunction.com) - version 1.4 - 4.7.2002
*/
public static function drawStar(target:Graphics, x:Number, y:Number, points:uint, innerRadius:Number, outerRadius:Number, angle:Number=0):void
{
// check that points is sufficient to build polygon
if (points <= 2)
{
throw ArgumentError("DrawingShapes.drawStar() - parameter 'points' needs to be atleast 3");
return;
}
if (points > 2)
{
// init vars
var step:Number, halfStep:Number, start:Number, n:Number, dx:Number, dy:Number;
// calculate distance between points
step = (Math.PI * 2) / points;
halfStep = step / 2;
// calculate starting angle in radians
start = (angle / 180) * Math.PI;
target.moveTo(x + (Math.cos(start) * outerRadius), y - (Math.sin(start) * outerRadius));
// draw lines
for (n = 1; n <= points; ++n)
{
dx = x + Math.cos(start + (step * n) - halfStep) * innerRadius;
dy = y - Math.sin(start + (step * n) - halfStep) * innerRadius;
target.lineTo(dx, dy);
dx = x + Math.cos(start + (step * n)) * outerRadius;
dy = y - Math.sin(start + (step * n)) * outerRadius;
target.lineTo(dx, dy);
}
}
}
/**
* a method for creating polygon shapes. Negative values will draw
* the polygon in reverse direction. Negative drawing may be useful
* for creating knock-outs in masks.
*
* @param target the Graphics that the polygon is to be drawn on
* @param x x coordinate of the center of the polygon
* @param y y coordinate of the center of the polygon
* @param sides the number of sides (must be > 2)
* @param radius the radius from the center point to the points
* on the polygon
* @param angle [optional] the starting offset angle (degrees) from
* 0. Default = 0
*
* based on mc.drawPoly() - by Ric Ewing (ric at formequalsfunction.com) - version 1.4 - 4.7.2002
*/
public static function drawPolygon(target:Graphics, x:Number, y:Number, sides:uint, radius:Number, angle:Number=0):void
{
// check that sides is sufficient to build
if (sides <= 2)
{
throw ArgumentError("DrawingShapes.drawPolygon() - parameter 'sides' needs to be atleast 3");
return;
}
if (sides > 2)
{
// init vars
var step:Number, start:Number, n:Number, dx:Number, dy:Number;
// calculate span of sides
step = (Math.PI * 2) / sides;
// calculate starting angle in radians
start = (angle / 180) * Math.PI;
target.moveTo(x + (Math.cos(start) * radius), y - (Math.sin(start) * radius));
// draw the polygon
for (n = 1; n <= sides; ++n)
{
dx = x + Math.cos(start + (step * n)) * radius;
dy = y - Math.sin(start + (step * n)) * radius;
target.lineTo(dx, dy);
}
}
}
/**
* Burst is a method for drawing star bursts. If you've ever worked
* with an advertising department, you know what they are ;-)
* Clients tend to want them, Developers tend to hate them...
*
* @param target Graphics where the Burst is to be drawn.
* @param x x coordinate of the center of the burst
* @param y y coordinate of the center of the burst
* @param sides number of sides or points
* @param innerRadius radius of the indent of the curves
* @param outerRadius radius of the outermost points
* @param angle [optional] starting angle in degrees. (defaults to 0)
*
* based on mc.drawBurst() - by Ric Ewing (ric at formequalsfunction.com) - version 1.4 - 4.7.2002
*/
public static function drawBurst(target:Graphics, x:Number, y:Number, sides:uint, innerRadius:Number, outerRadius:Number, angle:Number=0):void
{
// check that sides is sufficient to build
if (sides <= 2)
{
throw ArgumentError("DrawingShapes.drawBurst() - parameter 'sides' needs to be atleast 3");
return;
}
if (sides > 2)
{
// init vars
var step:Number, halfStep:Number, qtrStep:Number, start:Number, n:Number, dx:Number, dy:Number, cx:Number, cy:Number;
// calculate length of sides
step = (Math.PI * 2) / sides;
halfStep = step / 2;
qtrStep = step / 4;
// calculate starting angle in radians
start = (angle / 180) * Math.PI;
target.moveTo(x + (Math.cos(start) * outerRadius), y - (Math.sin(start) * outerRadius));
// draw curves
for (n = 1; n <= sides; ++n)
{
cx = x + Math.cos(start + (step * n) - (qtrStep * 3)) * (innerRadius / Math.cos(qtrStep));
cy = y - Math.sin(start + (step * n) - (qtrStep * 3)) * (innerRadius / Math.cos(qtrStep));
dx = x + Math.cos(start + (step * n) - halfStep) * innerRadius;
dy = y - Math.sin(start + (step * n) - halfStep) * innerRadius;
target.curveTo(cx, cy, dx, dy);
cx = x + Math.cos(start + (step * n) - qtrStep) * (innerRadius / Math.cos(qtrStep));
cy = y - Math.sin(start + (step * n) - qtrStep) * (innerRadius / Math.cos(qtrStep));
dx = x + Math.cos(start + (step * n)) * outerRadius;
dy = y - Math.sin(start + (step * n)) * outerRadius;
target.curveTo(cx, cy, dx, dy);
}
}
}
/**
* draws a gear shape on the Graphics target. The gear position
* is indicated by the x and y arguments.
*
* @param target Graphics on which the gear is to be drawn.
* @param x x coordinate of the center of the gear
* @param y y coordinate of the center of the gear
* @param sides number of teeth on gear. (must be > 2)
* @param innerRadius radius of the indent of the teeth.
* @param outerRadius outer radius of the teeth.
* @param angle = [optional] starting angle in degrees. Defaults to 0.
* @param holeSides [optional] draw a polygonal hole with this many sides (must be > 2)
* @param holeRadius [optional] size of hole. Default = innerRadius/3.
*
* based on mc.drawGear() - by Ric Ewing (ric at formequalsfunction.com) - version 1.4 - 4.7.2002
*/
public static function drawGear(target:Graphics, x:Number, y:Number, sides:uint, innerRadius:Number=80, outerRadius:Number=4, angle:Number=0, holeSides:Number=2, holeRadius:Number=0):void
{
// check that sides is sufficient to build polygon
if (sides <= 2)
{
throw ArgumentError("DrawingShapes.drawGear() - parameter 'sides' needs to be atleast 3");
return;
}
if (sides > 2)
{
// init vars
var step:Number, qtrStep:Number, start:Number, n:Number, dx:Number, dy:Number;
// calculate length of sides
step = (Math.PI * 2) / sides;
qtrStep = step / 4;
// calculate starting angle in radians
start = (angle / 180) * Math.PI;
target.moveTo(x + (Math.cos(start) * outerRadius), y - (Math.sin(start) * outerRadius));
// draw lines
for (n = 1; n <= sides; ++n)
{
dx = x + Math.cos(start + (step * n) - (qtrStep * 3)) * innerRadius;
dy = y - Math.sin(start + (step * n) - (qtrStep * 3)) * innerRadius;
target.lineTo(dx, dy);
dx = x + Math.cos(start + (step * n) - (qtrStep * 2)) * innerRadius;
dy = y - Math.sin(start + (step * n) - (qtrStep * 2)) * innerRadius;
target.lineTo(dx, dy);
dx = x + Math.cos(start + (step * n) - qtrStep) * outerRadius;
dy = y - Math.sin(start + (step * n) - qtrStep) * outerRadius;
target.lineTo(dx, dy);
dx = x + Math.cos(start + (step * n)) * outerRadius;
dy = y - Math.sin(start + (step * n)) * outerRadius;
target.lineTo(dx, dy);
}
// This is complete overkill... but I had it done already. :)
if (holeSides > 2)
{
step = (Math.PI * 2) / holeSides;
target.moveTo(x + (Math.cos(start) * holeRadius), y - (Math.sin(start) * holeRadius));
for (n = 1; n <= holeSides; ++n)
{
dx = x + Math.cos(start + (step * n)) * holeRadius;
dy = y - Math.sin(start + (step * n)) * holeRadius;
target.lineTo(dx, dy);
}
}
}
}
/**
* draws a line between two points. Make it horizontal or vertical
*
* @param target Graphics on which the gear is to be drawn.
* @param x x coordinate of the center of the gear
* @param y y coordinate of the center of the gear
* @param sides number of teeth on gear. (must be > 2)
*
*
*/
public static function drawLine(target:Graphics, x:Number, y:Number, length:Number, direction:String=DrawingShapes.HORIZONTAL_LINE):void
{
target.moveTo(x, y);
switch (direction)
{
case DrawingShapes.HORIZONTAL_LINE:
target.lineTo(length, y);
break;
case DrawingShapes.VERTICAL_LINE:
target.moveTo(x, y);
target.lineTo(x, length);
break;
}
}
/*
* new abs function, about 25x faster than Math.abs
*/
private static function abs(value:Number):Number
{
return value < 0 ? -value : value;
}
/*
* new ceil function about 75% faster than Math.ceil.
*/
private static function ceil(value:Number):Number
{
return (value % 1) ? int(value) + 1 : value;
}
}
}
Initial URL
Initial Description
Credit for this goes to Adobe, Ric Ewing, Kevin Williams, Aden Forshaw and Sidney de Koning.
Initial Title
AS3 Drawing Shapes (ARC, BURST, DASHED-LINE, GEAR, POLYGON, STAR, WEDGE, LINE)
Initial Tags
line
Initial Language
ActionScript 3