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:

  1. Draw the inner part of the arc in one direction.
  2. Draw a straight line to the outer part of the arc.
  3. Draw the outer part of the arc in the opposite direction.
  4. 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.

11 Responses to “Drawing a Closed Arc Shape”

  1. Leexxx says:

    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

  2. carl says:

    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 TO USE AS3 by Jeff T)
    //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);
    //
    //
  3. carl says:

    does anyone know how to round the corners??

  4. Grandmaof4 says:

    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.

  5. JLM says:

    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)

    MovieClip.prototype.drawElipse=function(x,y,w,h,t,c,a,s,f,fa){
    //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);
  6. marije says:

    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?

  7. Jeff says:

    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);
    //
    //
  8. Jeff says:

    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!

  9. Jason says:

    Thanks! I’ve been looking for something like this for a while. Much appreciated.

  10. tyler says:

    Ahhh… yes. That makes perfect sense. Thank you very much!

Leave a Reply

PixelWit.com's Comment Guidelines

© Sean O'Shell 2007-2017
css.php