Drawing a Closed Arc Shape
This tutorial provides the ActionScript needed to draw a “Closed Arc” which is my way of describing the solid shape created by connecting a pair of concentric arcs with 2 straight lines. Here’s an illustration to explain:
(If you’re new to drawing arcs I suggest reading my previous circle and arc tutorials for an introduction to trigonometry in Flash.)
In my standard arc drawing tutorial I explained the following ActionScript code:
function drawArc(centerX, centerY, radius, startAngle, arcAngle, steps){
var twoPI = 2 * Math.PI;
var angleStep = arcAngle/steps;
var xx = centerX + Math.cos(startAngle * twoPI) * radius;
var yy = centerY + Math.sin(startAngle * twoPI) * radius;
moveTo(xx, yy);
for(var i=1; i<=steps; i++){
var angle = startAngle + i * angleStep;
xx = centerX + Math.cos(angle * twoPI) * radius;
yy = centerY + Math.sin(angle * twoPI) * radius;
lineTo(xx, yy);
}
}
lineStyle(0, 0xFF0000);
drawArc(250, 250, 200, 45/360, -90/360, 20);
//
The above code produced this SWF file:
It doesn't look like much. But by looking at the above SWF you can probably deduce all of the steps needed to draw a solid arc:
- Draw the inner part of the arc in one direction.
- Draw a straight line to the outer part of the arc.
- Draw the outer part of the arc in the opposite direction.
- Draw a straight line back to the inner part of the arc to complete the shape.
Here you can see how the above ActionScript has been modified to do just that:
// The DrawSolidArc function takes standard arc drawing
// arguments but the "radius" has been split into 2 different
// variables, "innerRadius" and "outerRadius".
function DrawSolidArc (centerX, centerY, innerRadius, outerRadius, startAngle, arcAngle, steps){
//
// Used to convert angles to radians.
var twoPI = 2 * Math.PI;
//
// How much to rotate for each point along the arc.
var angleStep = arcAngle/steps;
//
// Variables set later.
var angle, i, endAngle;
//
// Find the coordinates of the first point on the inner arc.
var xx = centerX + Math.cos(startAngle * twoPI) * innerRadius;
var yy = centerY + Math.sin(startAngle * twoPI) * innerRadius;
//
// Store the coordiantes in an object.
var startPoint = {x:xx, y:yy};
//
// Move to the first point on the inner arc.
moveTo(xx, yy);
//
// Draw all of the other points along the inner arc.
for(i=1; i<=steps; i++){
angle = (startAngle + i * angleStep) * twoPI;
xx = centerX + Math.cos(angle) * innerRadius;
yy = centerY + Math.sin(angle) * innerRadius;
lineTo(xx, yy);
}
//
// Determine the ending angle of the arc so you can
// rotate around the outer arc in the opposite direction.
endAngle = startAngle + arcAngle;
//
// Start drawing all points on the outer arc.
for(i=0; i<=steps; i++){
//
// To go the opposite direction, we subtract rather than add.
angle = (endAngle - i * angleStep) * twoPI;
xx = centerX + Math.cos(angle) * outerRadius;
yy = centerY + Math.sin(angle) * outerRadius;
lineTo(xx, yy);
}
//
// Close the shape by drawing a straight
// line back to the inner arc.
lineTo(startPoint.x, startPoint.y);
}
//
// Draw 4 colored arcs around a circle without any overlap.
beginFill(0xFF0000, 50);
DrawSolidArc (250, 250, 80, 200, 45/360, -90/360, 20);
beginFill(0x00FF00, 50);
DrawSolidArc (250, 250, 80, 200, 135/360, -90/360, 20);
beginFill(0x0000FF, 50);
DrawSolidArc (250, 250, 80, 200, 225/360, -90/360, 20);
beginFill(0xFFFF00, 50);
DrawSolidArc (250, 250, 80, 200, 315/360, -90/360, 20);
//
//
The preceding ActionScript code produces a series of closed arcs forming a circle. The arcs are drawn with 50% opacity to show that they fit together tightly and without any overlap.
I was trying to apply your code but i’m not viewing anything. when i trace x & Y position the value stays the same. Any knows how i can fix it? Thanks
[…] … drawing arcs with fill inspired by PiXELWiT: […]
Modified Jeff T’s As3 version to put the angle conversions inside the function rather than in the constructor
Also added a check for angles larger than 360
//FROM PIXELWIT.COM (MODIFIED Jeff T Version by Carl L)
//checks for proper angles and angle coversion inside functin
// The DrawSolidArc function takes standard arc drawing
// arguments but the "radius" has been split into 2 different
// variables, "innerRadius" and "outerRadius". drawObj is the object you have created to draw into (Shape, MovieClip, etc...)
function drawSolidArc (drawObj:Object, centerX:Number,centerY:Number,innerRadius:Number,outerRadius:Number,startAngle:Number,arcAngle:Number,steps:int=20):void {
//
//make sure angles are proper
if (Math.abs(startAngle)>360)startAngle%=360
if (Math.abs(arcAngle)>360)arcAngle%=360
//convert angles to percentages
startAngle/=360,arcAngle/=360
// Used to convert angles [ratio] to radians.
var twoPI:Number = 2 * Math.PI;
//
// How much to rotate for each point along the arc.
var angleStep:Number = arcAngle/steps;
//
// Variables set later.
var angle:Number, i:int, endAngle:Number;
//
// Find the coordinates of the first point on the inner arc.
var xx:Number = centerX + Math.cos(startAngle * twoPI) * innerRadius;
var yy:Number = centerY + Math.sin(startAngle * twoPI) * innerRadius;
//
//Store the coordinates.
var xxInit:Number=xx;
var yyInit:Number=yy;
//
// Move to the first point on the inner arc.
drawObj.graphics.moveTo(xx,yy);
//
// Draw all of the other points along the inner arc.
for(i=1; i<=steps; i++) {
angle = (startAngle + i * angleStep) * twoPI;
xx = centerX + Math.cos(angle) * innerRadius;
yy = centerY + Math.sin(angle) * innerRadius;
drawObj.graphics.lineTo(xx,yy);
}
//
// Determine the ending angle of the arc so you can
// rotate around the outer arc in the opposite direction.
endAngle = startAngle + arcAngle;
//
// Start drawing all points on the outer arc.
for(i=0;i<=steps;i++) {
//
// To go the opposite direction, we subtract rather than add.
angle = (endAngle - i * angleStep) * twoPI;
xx = centerX + Math.cos(angle) * outerRadius;
yy = centerY + Math.sin(angle) * outerRadius;
drawObj.graphics.lineTo(xx,yy);
}
//
// Close the shape by drawing a straight
// line back to the inner arc.
drawObj.graphics.lineTo(xxInit,yyInit);
};
//
//And, to call this function and do the fill, and //show the object, you need to use:
//import flash.display.graphics;
var myArc:Shape = new Shape(); //or another DisplayObject
myArc.graphics.lineStyle(3);
myArc.graphics.beginFill(0x000000, 0.50);
drawSolidArc (myArc,250, 250, 180, 200, -90, 504, 100);
myArc.graphics.endFill();
this.addChild(myArc);
//
//
does anyone know how to round the corners??
I haven’t a clue what any of you are talking about. What’s the matter with using an old fashioned maths compass and just drawing two circles (or semi-circles as required) using the same central point, one inside the other?
P.S. Tyler and Jeff. What are doing up at stupid o-clock in the morning. I thought it was only old fogeys like me that were awake at ridiculous times of night.
Here is another approach sorry too lazy to update my prototype to AS3 (but just put an onLoad round it and it will work in swish as well)
//Justin Mills, JLM at justinfront dot net, 10 October 2003
if (f==undefined) {f=c; fa=0;}else if (fa==undefined) {af=100};
if (s==undefined) {s=5;} //smoothness
this.beginGradientFill('radial', [f,c,c,c], [fa,a,a,0], [255-s*2-t,255-s-t,255-s,255], {matrixType:'box', x:x, y:y, w:w, h:h, r:0});
this.moveTo(x,y);
this.lineStyle(1,0,0);
this.lineTo(x,y+h);
this.lineTo(x+w,y+h);
this.lineTo(x+w,y);
this.lineTo(x,y);
this.endFill();
};
depth=100;
this.createEmptyMovieClip("elipse",depth++);
elipse._x=100;
elipse._y=100;
elipse.drawElipse(0,0,100,100,100,0xff0000,100,5,0xFF0000,0); //x,y,w,h,t=4 thickness,c=red,a=100%,s=5 smoothness,f=fill, fa=fill alpha
this.createEmptyMovieClip("triMask", depth++);
triMask._x=100;
triMask._y=100;
triMask.beginFill(0x0000ff,100);
triMask.lineTo(100,0);
triMask.lineTo(50,50);
triMask.lineTo(0,0);
triMask.endFill();
elipse.setMask(triMask);
I was wondering how i can trace the coordinates of the arcs individually. I work in as3 and the strange thing is that he traces now for every item the x position as 0… how is this possible? And how can i fix it?
Since I did it for my own project, I figured I’d post your example reformatted for AS3–works the same way, just formatted slightly differently (and I added datatype declarations). drawObj is whatever displayObject you are going to use to hold your arc.
//FROM PIXELWIT.COM (MODIFIED TO USE AS3 by Jeff T)
// The DrawSolidArc function takes standard arc drawing
// arguments but the "radius" has been split into 2 different
// variables, "innerRadius" and "outerRadius". drawObj is the object you have created to draw into (Shape, MovieClip, etc...)
function drawSolidArc (drawObj:Object, centerX:Number,centerY:Number,innerRadius:Number,outerRadius:Number,startAngle:Number,arcAngle:Number,steps:int=20):void {
//
// Used to convert angles [ratio] to radians.
var twoPI:Number = 2 * Math.PI;
//
// How much to rotate for each point along the arc.
var angleStep:Number = arcAngle/steps;
//
// Variables set later.
var angle:Number, i:int, endAngle:Number;
//
// Find the coordinates of the first point on the inner arc.
var xx:Number = centerX + Math.cos(startAngle * twoPI) * innerRadius;
var yy:Number = centerY + Math.sin(startAngle * twoPI) * innerRadius;
//
//Store the coordinates.
var xxInit:Number=xx;
var yyInit:Number=yy;
//
// Move to the first point on the inner arc.
drawObj.graphics.moveTo(xx,yy);
//
// Draw all of the other points along the inner arc.
for(i=1; i<=steps; i++) {
angle = (startAngle + i * angleStep) * twoPI;
xx = centerX + Math.cos(angle) * innerRadius;
yy = centerY + Math.sin(angle) * innerRadius;
drawObj.graphics.lineTo(xx,yy);
}
//
// Determine the ending angle of the arc so you can
// rotate around the outer arc in the opposite direction.
endAngle = startAngle + arcAngle;
//
// Start drawing all points on the outer arc.
for(i=0;i<=steps;i++) {
//
// To go the opposite direction, we subtract rather than add.
angle = (endAngle - i * angleStep) * twoPI;
xx = centerX + Math.cos(angle) * outerRadius;
yy = centerY + Math.sin(angle) * outerRadius;
drawObj.graphics.lineTo(xx,yy);
}
//
// Close the shape by drawing a straight
// line back to the inner arc.
drawObj.graphics.lineTo(xxInit,yyInit);
};
//
//And, to call this function and do the fill, and //show the object, you need to use:
//import flash.display.graphics;
var myArc:Shape = new Shape(); //or another DisplayObject
myArc.graphics.lineStyle(3);
myArc.graphics.beginFill(0x000000, 0.50);
drawSolidArc (myArc,250, 250, 80, 200, 45/360, -90/360, 20);
myArc.graphics.endFill();
this.addChild(myArc);
//
//
Thanks a lot for this! I really like your explanation (plus I’ve been trying to figure out how to do this for a while). I also want to tip my hat to you for your “basic circle” guide–I already knew the trig, but I appreciated the simplicity and clarity of your explanation. Heck, I was on the verge of writing a chastizing post about conversions when I realized you were using angle *ratios* (stupid me!). Thanks so much again, you just rescued me from more hours of frustration!
Thanks! I’ve been looking for something like this for a while. Much appreciated.
Ahhh… yes. That makes perfect sense. Thank you very much!