2006-03-24

PIE GRAPHICS WITH PURE VFP CODE

Did you know that it is possible to draw pie style graphics in vfp without the need of any active-x or api call ? With pure VFP code ? draw a circle with foxpro
To draw any circle, there are two main parameters : 1 point with the coordinates of the center of the circle (x,y) and the radius. having this, it is very simple to calculate the coordinates of any point in the circumference border.
Even if you already use gdi+ or any active-x to draw graphics, I think it's imteresting to know how a circle is built, and how to calculate the positions of each point.

For this purpose, I'll need to make you remember the concepts of sine and cosine : 

In any right angled triangle, for any angle:

sine of the angle = length of the opposite side / length of the hypotenuse
cosine of the angle = length of the adjacent side / length of the hypotenuse


hypotenuse of a right angled triangle is the longest side, which is the one opposite the right angle. The adjacent side is the side which is between the angle in question and the right angle. The opposite side is opposite the angle in question.

So, imagine a right angled triangle inside a circumference, like in the picture below.

sine of angle = opposite side (height or y) / hypotenuse (radius) !!!

height = sine of angle * radius

 

 

cosine of angle = adjacent side (width or x) / hypotenuse (radius) !!!

width = cosine of angle * radius

 

Now we can create a loop starting from angle 0 (zero) and finishing at angle 360 degrees. At each step we can calculate the position of every point of the circle !

Then it becomes quite simple to draw the graphic. for that purpose, I'll use the line object, drawing lines from the center of the circle till the point x,y just calculated. and that's all !!!

There's one problem with the line object in VFP. To draw a line, we need to use the properties top, left, width, height and lineslant (specifies which way a line slants, from upper left to lower right or lower left to upper right), instead of simply passing the two points, x1y1 and x2y2. so, as you can see in the code below, depending on the angle and the resulting position in the quadrant (quarter of the circumference of a circle), I needed to make some extra code to deal with this. Pay attention to the "do case" command below.

Procedure DrawPie

LPARAMETERS tnCenterX, tnCenterY, tnRadius, tnStart, tnEnd, tnColor

LOCAL lnLineWidth, N, x, Y, lcObj, lnPointLeft, lnPointTop, lcSlant
m.lnLineWidth = 3

FOR m.N = m.tnStart TO m.tnEnd STEP (1 * m.lnLineWidth)
    m.x = COS(DTOR(m.N)) * m.tnRadius
    m.Y = SIN(DTOR(m.N)) * m.tnRadius

    m.lcObj = "line" + TRANSFORM(m.N * 100)
    THISFORM.container1.ADDOBJECT(m.lcObj,"line")

    DO CASE
        CASE m.N >= 0 AND m.N < 90 && 1st quadrant
            m.lnPointLeft = m.tnCenterX
            m.lnPointTop = m.tnCenterY – m.Y
            m.lcSlant = "/"

        CASE m.N >= 90 AND m.N < 180 && 2nd quadrant
            m.lnPointLeft = m.tnCenterX + m.x
            m.lnPointTop = m.tnCenterY – m.Y
            m.lcSlant = "\"

        CASE m.N >= 180 AND m.N < 270 && 3rd quadrant
            m.lnPointLeft = m.tnCenterX + m.x
            m.lnPointTop = m.tnCenterY
            m.lcSlant = "/"

        CASE m.N >= 270 AND m.N <= 360 && 4th quadrant
            m.lnPointLeft = m.tnCenterX
            m.lnPointTop = m.tnCenterY
            m.lcSlant = "\"
    ENDCASE

    WITH THISFORM.container1.&lcObj.
        .LINESLANT = m.lcSlant
        .BORDERCOLOR = m.tnColor
        .BORDERWIDTH = m.lnLineWidth
        .WIDTH = ABS(m.x)
        .HEIGHT = ABS(m.Y)
        .LEFT = m.lnPointLeft
        .TOP = m.lnPointTop
        .VISIBLE = .T.
    ENDWITH

ENDFOR
RETURN

You may find this procedure slow, specially if you run it in slow machines, but it works ! the biggest problem is that it adds many objects in a form, in the case of a loop with step 1, at least 360 lines !
If we draw a line with borderwidth = 1, in some cases, the calculated points will create some holes between the lines. a wider border will resolve this problem. the bigger the step in the loop (from 0 to 360 degrees), the faster the procedure will run, and less objects will be added.
Run the form piegraphics.scx from the attached file, change the cursor, radius, step, and linewidth values, and check all procedures to better understand this post.

What next ?

Of course, in one of my next posts I'll deal with pie style graphics using Gdi+ – Google for the keyword FOXCHARTS, for a great surprise made in pyure VFP9 code.
Some of the subjects discussed here will help us to create more interesting graphics.







8 comments:

  1. Good example. What about the column percentage Bar Graphics?

    ReplyDelete
  2. You're doing a good job, all your blog entries are really good

    ReplyDelete
  3. Another great post! I've been enjoying your posts on GDI+ as well. Great stuff!

    ReplyDelete
  4. Good work! Taking the idea of graphs 100 % VFP, I have realized a class and an article (in Spanish)


    Graphs with 100 % VFP objects

    (Gráficas con objetos 100% VFP)

    http://www.portalfox.com/article.php?sid=2211


    There I mention to the entries of your blog

    ReplyDelete
  5. Gracias Luis Maria !

    Great article, using some great ideas, with a great result.

    I created the solution of published in this post 2 years ago, with VFP7, and is supposed to work with all VFP versions.

    The approach from Luis Maria Guayan works only with VFP9, but the final result and performance from his solution is really impressive.

    Thanks !

    ReplyDelete
  6. Versión en Español de este artículo en / Spanish version at  http://www.portalfox.com/article.php?sid=2210

    ReplyDelete
  7. An application called STAR Atlas-PRO (see http://www.skylab.com.au/ ) sells worldwide - it is a STAR ATLAS and draws charts of stars and galaxies - the application is written entirely in Visual Foxpro.


    ReplyDelete
  8. Thanks Cesar, for the CASE listing, the solution for LINESLANT; you saved me from synapse overload.

    ReplyDelete