package com.ulfben.utils {
import flash.display.*;
import flash.geom.*;
public class FastShapes {
public static const HORIZONTAL_LINE:String = "FastShapes.horizontal";
public static const VERTICAL_LINE:String = "FastShapes.vertical";
public static const TO_RAD:Number = (Math.PI / 180);
public static const TO_DEG:Number = (180 / Math.PI);
public static const PI2:Number = Math.PI * 2;
public static const HALF_PI:Number = Math.PI * 0.5;
public static const QUARTER_PI:Number = Math.PI * 0.25;
public static const EIGHTH_PI:Number = Math.PI * 0.125;
/**
* Creates look up tables for sin and cos, to reduce function calls.
* index = int(angle * (2048/2PI))
*/
public static var sCosLUT:Vector.<Number> = new Vector.<Number>(0x800, true);
public static var sSinLUT:Vector.<Number> = new Vector.<Number>(0x800, true);
public static function initLUTs():void {
for (var i:int = 0; i < 0x800; ++i)
{
sCosLUT[i & 0x7FF] = Math.cos(i * 0.00306796157577128245943617517898); // 0.003067... is 2PI/2048
sSinLUT[i & 0x7FF] = Math.sin(i * 0.00306796157577128245943617517898);
}
}
public static function sinLUT(x:Number):Number{
return sSinLUT[(x * 325.94932345220164765467394738691) & 2047]; // 325.949... is 2048/2PI
}
public static function cosLUT(x:Number):Number{
return sCosLUT[((x * 325.94932345220164765467394738691) & 2047)]; //325.949... is 2048/2PI
}
public static function sinCoarse(x:Number):Number {
if (x < -3.14159265) { //always wrap input angle to -PI..PI
x += 6.28318531;
} else if (x > 3.14159265) {
x -= 6.28318531;
}
return (x < 0) ? (1.27323954 * x + .405284735 * x * x) : (1.27323954 * x - 0.405284735 * x * x);
}
public static function cosCoarse(x:Number):Number {
if (x < -3.14159265) { //always wrap input angle to -PI..PI
x += 6.28318531;
} else if (x > 3.14159265) {
x -= 6.28318531;
}
x += 1.57079632; // //compute cosine: sin(x + PI/2) = cos(x)
if (x > 3.14159265) {
x -= 6.28318531;
}
return (x < 0) ? (1.27323954 * x + 0.405284735 * x * x) : (1.27323954 * x - 0.405284735 * x * x);
}
public static function sinFine(x:Number):Number {
if(x < -3.14159265) {
x += 6.28318531;
} else if(x > 3.14159265) {
x -= 6.28318531;
}
x = (x < 0.0) ? (1.27323954 * x + .405284735 * x * x) : (1.27323954 * x - 0.405284735 * x * x)
return (x < 0.0) ? (0.225 * (x *-x - x) + x) : (0.225 * (x * x - x) + x)
}
public static function cosFine(x:Number): Number {
if(x < -3.14159265) {
x += 6.28318531;
} else if(x > 3.14159265) {
x -= 6.28318531;
}
x += 1.57079632;
if(x > 3.14159265) {
x -= 6.28318531;
}
x = (x < 0.0) ? (1.27323954 * x + .405284735 * x * x) : (1.27323954 * x - 0.405284735 * x * x)
return (x < 0.0) ? (0.225 * (x *-x - x) + x) : (0.225 * (x * x - x) + x)
}
public static var testCos:Function = cosFine; // cosLUT, cosCoarse, cosFine
public static var testSin:Function = sinFine; // sinLUT, sinCoarse, sinFine
public function FastShapes() {
throw new ArgumentError("The FastShapes Class cannot be instanicated.");
}
/***
* drawCircle
* Since Flash Player 8 there is an internal drawCircle-method. Before that I
* used this. At some point they should be benchmarked against eachother.
*/
public static function drawCircle(target:Graphics, x:Number, y:Number, r:Number):void {
var tan:Number = Math.tan(EIGHTH_PI) * r;
var sin:Number = testSin(QUARTER_PI) * r;
target.moveTo(x + r, y);
target.curveTo(r + x, tan + y, sin + x, sin + y);
target.curveTo(tan + x, r + y, x, r + y);
target.curveTo((-tan) + x, r + y, (-sin) + x, sin + y);
target.curveTo(-r + x, tan + y, -r + x, y);
target.curveTo(-r + x, (-tan) + y, (-sin) + x, (-sin) + y);
target.curveTo((-tan) + x, -r + y, x, -r + y);
target.curveTo(tan + x, -r + y, sin + x, (-sin) + y);
target.curveTo(r + x, (-tan) + y, r + x, y);
target.moveTo(x, y);
}
// wobbleFactor in percent. 0.04-0.08 is a good default range.
public static function handDrawLine(target:Graphics, startPoint:Point, endPoint:Point, wobbleFactor:Number = 0.05):void {
var wobble:Number = Point.distance(startPoint, endPoint) * wobbleFactor;
var r1:Number = Math.random();
var r2:Number = Math.random();
var xfactor:Number = Math.random() > 0.5 ? wobble : -wobble;
var yfactor:Number = Math.random() > 0.5 ? wobble : -wobble;
var control1:Point = new Point((endPoint.x - startPoint.x) * r1 + startPoint.x + xfactor, (endPoint.y - startPoint.y) * r1 + startPoint.y + yfactor);
var control2:Point = new Point((endPoint.x - startPoint.x) * r2 + startPoint.x - xfactor, (endPoint.y - startPoint.y) * r2 + startPoint.y - yfactor);
target.moveTo(startPoint.x, startPoint.y);
target.cubicCurveTo(control1.x, control1.y, control2.x, control2.y, endPoint.x, endPoint.y);
}
// Draws a dashed line from the point x1,y1 to the point x2,y2
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 invertedUnits:Number = 1 / units;
var dashSpaceRatio:Number = dashLength / (dashLength + spaceLength);
var dashX:Number = (x * invertedUnits) * dashSpaceRatio;
var spaceX:Number = (x * invertedUnits) - dashX;
var dashY:Number = (y * invertedUnits) * dashSpaceRatio;
var spaceY:Number = (y * invertedUnits) - 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.
public static function drawArc(target:Graphics, x:Number, y:Number, radius:Number, arc:Number, startAngle:Number = 0, yRadius:Number = 0):void {
if (yRadius == 0) {
yRadius = radius;
}
var segAngle:Number, theta:Number, halfTheta:Number, angle:Number, angleMid:Number, segs:Number, ax:Number, ay:Number, bx:Number, by:Number, cx:Number, cy:Number;
if (FastShapes.abs(arc) > 360) {
arc = 360; // no sense in drawing more than is needed :)
}
// Flash uses 8 segments per circle, to match that, we draw in a maximum of 45 degree segments.
segs = FastShapes.ceil(FastShapes.abs(arc) / 45);
segAngle = arc / segs;
theta = -(segAngle) * FastShapes.TO_RAD;
angle = -(startAngle) * FastShapes.TO_RAD;
ax = x - testCos(angle) * radius;
ay = y - testSin(angle) * yRadius;
if (segs > 0) {
target.moveTo(x, y);
halfTheta = theta * 0.5;
var radiusCosHalfTheta:Number = radius / testCos(halfTheta);
var yRadiusCosHalfTheta:Number = yRadius / testCos(halfTheta);
for (var i:int = 0; i < segs; ++i) {
angle += theta;
angleMid = angle - halfTheta;
bx = ax + testCos(angle) * radius;
by = ay + testSin(angle) * yRadius;
cx = ax + testCos(angleMid) * radiusCosHalfTheta;
cy = ay + testSin(angleMid) * yRadiusCosHalfTheta;
target.curveTo(cx, cy, bx, by);
}
}
}
// draws pie shaped wedges. Could be employed to draw pie charts.
public static function drawWedge(target:Graphics, x:Number, y:Number, radius:Number, arc:Number, startAngle:Number = 0, yRadius:Number = 0):void {
if (yRadius == 0) {
yRadius = radius;
}
if (FastShapes.abs(arc) > 360) {
arc = 360;
}
target.moveTo(x, y);
var segAngle:Number, theta:Number, halfTheta:Number, angle:Number, angleMid:Number, segs:Number, ax:Number, ay:Number, bx:Number, by:Number, cx:Number, cy:Number;
// Flash uses 8 segments per circle, to match that, we draw in a maximum of 45 degree segments.
segs = FastShapes.ceil(FastShapes.abs(arc) / 45);
segAngle = arc / segs;
theta = -(segAngle) * FastShapes.TO_RAD;
angle = -(startAngle) * FastShapes.TO_RAD;
// draw the curve in segments no larger than 45 degrees.
if (segs > 0) {
ay = y + testSin(angle) * yRadius; //NOTE: angle is negative!
ax = x + testCos(-angle) * radius; //NOTE: -angle == positive value here!
target.lineTo(ax, ay);
halfTheta = theta * 0.5;
var radiusCosHalfTheta:Number = radius / testCos(halfTheta);
var yRadiusCosHalfTheta:Number = yRadius / testCos(halfTheta);
for (var i:int = 0; i < segs; ++i) {
angle += theta;
angleMid = angle - halfTheta;
bx = x + testCos(angle) * radius;
by = y + testSin(angle) * yRadius;
cx = x + testCos(angleMid) * radiusCosHalfTheta;
cy = y + testSin(angleMid) * yRadiusCosHalfTheta;
target.curveTo(cx, cy, bx, by);
}
target.lineTo(x, y);
}
}
// draws a star shaped polygon.
public static function drawStar(target:Graphics, x:Number, y:Number, points:uint, innerRadius:Number, outerRadius:Number, angle:Number = 0):void {
if (points <= 2) {
throw ArgumentError("FastShapes.drawStar() - parameter 'points' needs to be atleast 3");
return;
}
var step:Number, startnstep:Number, halfStep:Number, start:Number, n:Number, dx:Number, dy:Number;
step = FastShapes.PI2 / points;
halfStep = step * 0.5;
start = angle * FastShapes.TO_RAD;
target.moveTo(x + (testCos(start) * outerRadius), y - (testSin(start) * outerRadius));
for (n = 1; n <= points; ++n) {
startnstep = start + (step * n);
dx = x + testCos(startnstep - halfStep) * innerRadius;
dy = y - testSin(startnstep - halfStep) * innerRadius;
target.lineTo(dx, dy);
dx = x + testCos(startnstep) * outerRadius;
dy = y - testSin(startnstep) * 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.
*/
public static function drawPolygon(target:Graphics, x:Number, y:Number, sides:uint, radius:Number, angle:Number = 0):void {
if (sides <= 2) {
throw ArgumentError("FastShapes.drawPolygon() - parameter 'sides' needs to be atleast 3");
return;
}
var step:Number, startnstep:Number, start:Number, n:Number, dx:Number, dy:Number;
step = FastShapes.PI2 / sides;
start = angle * FastShapes.TO_RAD;
target.moveTo(x + (testCos(start) * radius), y - (testSin(start) * radius));
for (n = 1; n <= sides; ++n) {
startnstep = start + (step * n);
dx = x + testCos(startnstep) * radius;
dy = y - testSin(startnstep) * radius;
target.lineTo(dx, dy);
}
}
/**
* a method for creating hand drawn polygon shapes. Negative values will draw
* the polygon in reverse direction. Negative drawing may be useful
* for creating knock-outs in masks.
*/
public static function handDrawPolygon(target:Graphics, x:Number, y:Number, sides:uint, radius:Number, wobbleFactor:Number = 0.05, angle:Number = 0):void {
if (sides <= 2) {
throw ArgumentError("FastShapes.handDrawPolygon() - parameter 'sides' needs to be atleast 3");
return;
}
var step:Number, start:Number, startnstep:Number, n:Number, dx:Number, dy:Number;
step = FastShapes.PI2 / sides;
start = angle * FastShapes.TO_RAD;
var p1:Point = new Point(x + (testCos(start) * radius), y - (testSin(start) * radius))
var p2:Point = new Point();
target.moveTo(p1.x, p1.y);
for (n = 1; n <= sides; ++n) {
startnstep = start + (step * n);
p2.x = x + testCos(startnstep) * radius; //dx
p2.y = y - testSin(startnstep) * radius; //dy
handDrawLine(target, p1, p2, wobbleFactor);
p1.x = p2.x;
p1.y = p2.y;
}
}
/**
* 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...
*/
public static function drawBurst(target:Graphics, x:Number, y:Number, sides:uint, innerRadius:Number, outerRadius:Number, angle:Number = 0):void {
if (sides <= 2) {
throw ArgumentError("FastShapes.drawBurst - parameter 'sides' needs to be atleast 3");
return;
}
var step:Number, halfStep:Number, qtrStep:Number, qtrStep3:Number, start:Number, n:Number, dx:Number, dy:Number, cx:Number, cy:Number;
var startnstep:Number, innercos:Number;
step = FastShapes.PI2 / sides;
qtrStep = step * 0.25;
halfStep = step * 0.5;
qtrStep3 = step * 0.75;
start = angle * FastShapes.TO_RAD;
target.moveTo(x + (testCos(start) * outerRadius), y - (testSin(start) * outerRadius));
for (n = 1; n <= sides; ++n) {
startnstep = start + (step * n);
innercos = (innerRadius / testCos(qtrStep));
cx = x + testCos(startnstep - qtrStep3) * innercos;
cy = y - testSin(startnstep - qtrStep3) * innercos;
dx = x + testCos(startnstep - halfStep) * innerRadius;
dy = y - testSin(startnstep - halfStep) * innerRadius;
target.curveTo(cx, cy, dx, dy);
cx = x + testCos(startnstep - qtrStep) * innercos;
cy = y - testSin(startnstep - qtrStep) * innercos;
dx = x + testCos(startnstep) * outerRadius;
dy = y - testSin(startnstep) * outerRadius;
target.curveTo(cx, cy, dx, dy);
}
}
// draws a gear shape on the Graphics target
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 {
if (sides <= 2) {
throw ArgumentError("FastShapes.drawGear() - parameter 'sides' needs to be atleast 3");
return;
}
var step:Number, startnstep:Number, qtrStep:Number, qtrStep2:Number, qtrStep3:Number, start:Number, n:Number, dx:Number, dy:Number;
step = FastShapes.PI2 / sides;
qtrStep = step * 0.25;
qtrStep2 = (qtrStep * 2);
qtrStep3 = (qtrStep * 3);
start = angle * FastShapes.TO_RAD;
target.moveTo(x + (testCos(start) * outerRadius), y - (testSin(start) * outerRadius));
for (n = 1; n <= sides; ++n) {
startnstep = start + (step * n);
dx = x + testCos(startnstep - qtrStep3) * innerRadius;
dy = y - testSin(startnstep - qtrStep3) * innerRadius;
target.lineTo(dx, dy);
dx = x + testCos(startnstep - qtrStep2) * innerRadius;
dy = y - testSin(startnstep - qtrStep2) * innerRadius;
target.lineTo(dx, dy);
dx = x + testCos(startnstep - qtrStep) * outerRadius;
dy = y - testSin(startnstep - qtrStep) * outerRadius;
target.lineTo(dx, dy);
dx = x + testCos(startnstep) * outerRadius;
dy = y - testSin(startnstep) * outerRadius;
target.lineTo(dx, dy);
}
// This is complete overkill... but I had it done already. :)
if (holeSides > 2) {
step = FastShapes.PI2 / holeSides;
target.moveTo(x + (testCos(start) * holeRadius), y - (testSin(start) * holeRadius));
for (n = 1; n <= holeSides; ++n) {
startnstep = start + (step * n);
dx = x + testCos(startnstep) * holeRadius;
dy = y - testSin(startnstep) * holeRadius;
target.lineTo(dx, dy);
}
}
}
// draws a line between two points. Make it horizontal or vertical
public static function drawLine(target:Graphics, x:Number, y:Number, length:Number, direction:String = FastShapes.HORIZONTAL_LINE):void {
switch (direction) {
case FastShapes.HORIZONTAL_LINE:
target.moveTo(x, y);
target.lineTo(length, y);
break;
case FastShapes.VERTICAL_LINE:
target.moveTo(x, y);
target.lineTo(x, length);
break;
}
}
}
}
Comments
0 B
|👍
/👎
0 B
|0 👍
/0 👎
0 B
|👍
/👎
0 B
|👍
/👎