Home

Blast from the past

Beginning Game Programming

Differential Equations

Browsing and Exploring a Folder

Flash-O-Rama!

Beginning Programming Part IV

Four Methods for Drawing Arcs

Newsletter Help

Index


| Watson's Method |

| Drake's Method |

| Nally's Method |

| Amaya's Method |


"I'm Trying to Draw an Arc..."

In April of 2002, "lazman2001" left a modest request in the LBExp (Liberty BASIC Expert) newsgroup on Yahoo:

I'm trying to draw an arc in a graphics window.
LB doesn't have an arc command. How would I draw
an arc with the following information.

X and Y center point
Radius
starting angle
ending angle

Any ideas?
~laz

Any ideas you ask? If there is one thing that the helpful and creative LB community has, it's ideas! Our five or six newsgroups are spilling over with ideas! We can hardly contain them! Even our ideas have ideas!

To Laz's satisfaction, users of the LBExp group posted three effective ways for drawing arcs within a day of his request. All three of those code samples are posted below, with permission of the authors.

But programming geometry is too much fun, and can't be confined by time. Conforums group member Andy Amaya has recently produced another arc drawing routine, which we also feature here with his permission.

To effectively use any of the methods, it's important to understand what input is required by each routine. I'll leave that up to the readers to identify the input as the four methods are presented below.

| Top |


Alyce Calls the Windows API

Screenshot: Alyce's arc generator

Few among us can command the Windows API as effectively as Alyce Watson, and she responded to Laz' request using the tools written by the Microsoft engineers.

As you examine the code below, note that the Windows API arc function has nine arguements. These arguements are identified in the comments at the end of the routine.

In addition to the fact that The Alyce method is API-based, it differs from the proceeding two methods in another respect: the arcs output by the routine can be portions of ellipses, not just circles.

To use this method in your programs, copy the code shown below, and paste it into your favorite LB editor.

NoMainWin
WindowWidth=600:WindowHeight=400

Open "Arc" For graphics_nsb_nf As #1
Print #1, "trapclose [quit]"
Print #1, "down; fill yellow;size 5"
Print #1, "color blue"

hwDC=GetDC(hWnd(#1))

Call Arc hwDC,10,10,350,250,40,100,300,200

'to flush graphics drawn via api:
Print #1, "getbmp arc 0 0 500 300"
Print #1, "drawbmp arc 0 0;flush"

Wait

[quit]
Call ReleaseDC hWnd(#1), hwDC
Close #1:End

Sub Arc hDC,x1,y1,x2,y2,x3,y3,x4,y4
CallDLL #gdi32, "Arc",hDC As long,x1 As long,y1 As long,_
x2 As long,y2 As long,x3 As long,y3 As long,_
x4 As long,y4 As long,results As boolean
End Sub

Function GetDC(hWnd)
CallDLL #user32, "GetDC",hWnd As long,GetDC As long
End Function

Sub ReleaseDC hWnd, hDC
CallDLL#user32,"ReleaseDC",hWnd As long,_
hDC As long,result As long
End Sub

' BOOL Arc(
' HDC hdc, // handle to device context 
' Int nLeftRect, // x-coordinate of bounding rectangle’s upper-left corner 
' Int nTopRect, // y-coordinate of bounding rectangle’s upper-left corner 
' Int nRightRect, // x-coordinate of bounding rectangle’s lower-right corner 
' Int nBottomRect,// y-coordinate of bounding rectangle’s lower-right corner 
' Int nXStartArc, // first radial ending point 
' Int nYStartArc, // first radial ending point 
' Int nXEndArc, // second radial ending point 
' Int nYEndArc // second radial ending point

| Top |


D^2 Writes a Sub

Screenshot: Drake's arc generator

About the same time that Alyce was posting her message, David Drake was uploading his own method.

David wrote a Sub, to which the user would pass the following six arguments:

In David's routine, the zero angle is "due east" of the arc center, and the arcs are drawn counterclockwise.

I made one small adjustment to David's routine. His program requires that the starting and ending angles of the arc be in units of radians. I added a couple of variables that allow the user to specify the start and end angles in degrees, after which the angles are converted to radians for use by the sub.

The user may identify these variables as he studies the code below for use in his own program.


'This demo has an arc maker as a SUB
'By David Drake
'With Minor adjustments by Nally, May 2003

'window stuff
nomainwin
WindowWidth = 500
WindowHeight = 400
open "Drawing Arcs - By David Drake" for graphics as #1
print #1, "trapclose [quit]"
print #1, "color black;backcolor white"
print #1, "down"

'Parameters of arc

startAngleD =  90  ' Start angle given in degrees
                   ' but converted to radians below

startAngle  = (startAngleD / 360) * (2 * 3.14159)

endAngleD  =  270  ' End angle given in degrees
                   ' but converted to radians below

endAngle   = (endAngleD / 360) * (2 * 3.14159)


segments   = 180   ' Segments in arc

centerX    = 150   ' Center of arc X (pixels)
centerY    = 200   ' Center of arc Y (pixels)
radius     = 100   ' Radious of arc (pixels)

call arc startAngle, endAngle, segments, centerX, centerY, radius

wait
[quit]
close #1


'Subroutine that draws arc
sub arc startAngle, endAngle, segments, centerX, centerY, radius

    'endAngle = int(endAngle*100)
    resolution = (endAngle-startAngle)/segments ' Calculates
                                                ' steps in arc based on segments
    x = centerX+radius*cos(startAngle) ' Calculate start point of arc (X)
    y = centerY+radius*sin(startAngle) ' Calculate start point of arc (Y)
    print #1, "place ";x;" ";y         ' Place starting point of arc

    for angle = startAngle to endAngle step resolution ' Sweep arc
        x = centerX+radius*cos(angle) ' Calculate arc point (X)
        y = centerY+radius*sin(angle) ' Calculate arc point (Y)
        print #1, "goto ";x;" ";y     ' Draw line to next point on arc
    next angle

end sub

| Top |


Nally Writes a Function

Screenshot: Nally's Arc Generator

Screenshot: Stars made by calling GenArc()

My own version of arc-drawing turned out to be quite similar to David Drake's in the use of geometry. Our routines even have exactly the same input, though the input is sent to the routine in slightly different order.

One difference in my routine is that I used a user-defined Function instead of a Sub. (I had no reason for choosing a Function as my tool, other than the fact that I had never used a Sub before, and knew a function would do the job.) To call my function, the programmer would need a line that looks something like this:

A = GenArc(Xc, Yc, R, StartD, EndD, NLS)

If you look at the code of the function below, you will see that the function will draw an arc, while the variable GenArc will never be assigned a value. Consequently, the variable A is never assigned a value either. This is an atypical use of a user-defined Function, but it does work.

One unintended capability of my arc-drawing function (and probably of David Drake's, too) is the ability to draw objects that look like stars. This capability arises because of the fact the function divides the arc into a series of small, adjacent "subarcs", then connects the endpoints of these subarcs with line segments. But if the arc to be drawn is a large multiple of 360 degrees (7200 degrees, say), and if the number of line segments used to draw the arc is a prime number (47, say), then the line segments will criss-cross the circle of the arc connecting the endpoints of the 47 subarcs. A star--like one of those shown on the right--is the result.

As seen below, the function itself is called GenArc(). But included in the zip archive of this newsletter is more complete BASIC program called GenArc01.bas which provides a simple GUI to allow the user to test out the function by adjusting the input one value at a time.

See the GenArc() function below.

Function GenArc(Xc, Yc, R, StartD, EndD, NLS)
    pi = 4*atn(1)
    StartR = (StartD/360)*(2*pi)
    EndR   = (EndD/360)*(2*pi)
    ArcElement = (EndR - StartR) / NLS

    xplot(0) = Xc + R * cos(StartR)
    yplot(0) = Yc - R * sin(StartR)

    For i = 1 to NLS
        xplot(i) = Xc + R * cos(StartR + i*ArcElement)
        yplot(i) = Yc - R * sin(StartR + i*ArcElement)
    Next i

    'Draw a small cross at the arc center


    print #main.Gbox1, "line " + str$(Xc - 5) + " " + str$(Yc)+ " " + str$(Xc + 5) + " " + str$(Yc)
    print #main.Gbox1, "line " + str$(Xc) + " " + str$(Yc + 5)+ " "  + str$(Xc) + " " + str$(Yc - 5)

    'Plot the Arc

    For i = 1 to NLS
        ArcString$ = Str$(xplot(i-1)) + " " + _
                     Str$(yplot(i-1)) + " " + _
                     Str$(xplot(i)) + " " + _
                     Str$(yplot(i))
        print #main.Gbox1, "line " + ArcString$
    next i

End Function

| Top |


Andy Amaya's Artistic Arcs

Screenshot: Amaya's arc generator

Just as I started compiling this article on drawing arcs about a week ago, Andy Amaya posted this interesting message on the Conforums message board:

Hi All,

Have recently uploaded two graphics demos
to the FTP site for this forum (at bottom
of forum home page).

arcSUB demo.bas - shows how to implement
drawing arcs (parts of a circle) in LB using
dots (single plotted points) or using lines
to connect the dots. Also demonstrates how
to move sprites in perfect circles.

Though sometimes less is more, in this case more is more, so we decided to ask Andy's permission to include his creative work in this article. He agreed.

The input to Andy's Sub is quite similar in substance to the input in Drake's Sub and in Nally's Function. There are at least two differences, however. In Andy's routine, one does not specify the number of "subarcs" in the arc. Rather, one sends the incSize to the Sub, which is the spacing between the points of the arc.

The second difference involves the inclusion of an additional parameter in the input sent to the Sub. This parameter is mode. A mode of 0 instructs the Sub to build the arc with dots, while a mode of 1 instructs the Sub to build the arc using lines.

All we present below is the Sub itself. However, in the zip archive of the newsletter is a cool application, Arc-Sub demo.bas, in which Andy artfully uses his Sub to draw designs.

Please note this, however. You should install Andy's Arc-Sub demo.bas in the same folder in which Liberty BASIC is installed. This is because Andy's program calls sprite and background graphics that are part of the Liberty BASIC distribution. These commands look for these graphics in a particular folder. Example:


LOADBMP "smile1","sprites\smiley2.bmp"

Have fun using Arc-Sub demo.bas! It's worth running a few times even if you have no need to learn how to draw arcs!

Meanwhile, Andy's Sub arc is shown below.


'*********************************   SUB arc  *******************************
'** Parameters are:                                                        **
'** CenterX coord, CenterY coord, Radius, Angle1, Angle2, incSize, mode    **
'** incSize determines spacing between points, mode: 0 = dots, 1 = lines   **
'**                                                                        **
'** All parameters are numeric, compiler error occurs IF strings are used. **
'**                                                                        **
'** Includes logic to allow plotting from 180 to > 360 degrees. Avoiding   **
'** having to call routine twice to plot from 180 to 360 then calling again**
'** from 0 to 179. To cross 360/0 boundary, make call with 2nd angle       **
'** greater than 360 and less than or equal to 540.                        **
'** For Example: make call with angle1=180, angle2=539 (clockwise) or      **
'** angle1=539, angle2=180 (counter-clockwise).                            **
'**                                                                        **
'** Source: Developed this routine FOR use with TRS-80 mode1 I graphics    **
'****************************************************************************
SUB arc centerX,centerY,radius,angle1,angle2,incSize,mode
    'check angles: make sure they are within acceptable range
    IF angle1 < 0 OR angle1 > 540 OR angle2 < 0 OR angle2 > 540 THEN [badParm]

    'Determine 'STEP' direction and magnitude used in FOR..NEXT loop to plot
    IF angle1 < angle2 THEN inc = incSize ELSE inc = -1 * incSize

    'one degree of arc resolution, otherwise it's a single point
    IF angle1 <> angle2 THEN            'plot arc

        'use mode=0 to plot single dots, use mode=1 to connect dots with lines
        IF mode = 0 THEN
            FOR x = angle1 TO angle2 STEP inc
                IF x > 360 THEN rx = x - 360 ELSE rx = x
                arcX=dx(rx) * radius + centerX
                arcY=dy(rx) * radius + centerY
                'change to handle name of graphic window used in your program
                PRINT #1.g,"SET ";arcX;" ";arcY
            NEXT x
        ELSE
            IF angle1 > 360 THEN rx = angle1 - 360 ELSE rx = angle1
            x1 = dx(rx) * radius + centerX
            y1 = dy(rx) * radius + centerY
            FOR x = angle1+inc TO angle2 STEP inc
                IF x > 360 THEN rx = x - 360 ELSE rx = x
                arcX = dx(rx) * radius + centerX
                arcY = dy(rx) * radius + centerY
                'change to handle name of graphic window used in your program
                PRINT #1.g,"LINE ";x1;" ";y1;" ";arcX;" ";arcY
                x1 = arcX
                y1 = arcY
            NEXT x
        END IF
    ELSE
        'angles are the same, so just plot a single point indicated by angle
        PRINT #1.g,"SET ";arcX;" ";arcY
    END IF
[badParm]
END SUB

| Top |


Home

Blast from the past

Beginning Game Programming

Differential Equations

Browsing and Exploring a Folder

Flash-O-Rama!

Beginning Programming Part IV

Four Methods for Drawing Arcs

Newsletter Help

Index