Drawing any N-sided Polygon



Click here for larger image

Environment: VC 5-6 , Windows 95/98/2000/NT/Me

Recently I had to develop a Graphics Software and wanted to add support for drawing any N-sided Polygon. When I started, I thought that I would have to develop code for every 'N' separately. After churning my head in trigonometry for a couple of hours, I realized that effectively 20 lines of code would do the job.

The figures are drawn (from the center) when you drag the mouse. The drawing mode used is R2_NOT. When the user drags the mouse, the previous drawn figure is erased and the new figure is drawn. You need to include "math.h" in your View.cpp file.

This checks when the User Starts dragging the mouse:

void CPolygonsView::OnLButtonDown(UINT nFlags,
                                  CPoint point)
{
  m_Drag = true; // for mouse drag check
  PointOrigin = point; // val when mouse drag starts
  CView::OnLButtonDown(nFlags, point);
}

void CPolygonsView::OnLButtonUp(UINT nFlags, 
                                CPoint point) 
{

  m_Drag = false;// for mouse drag check
  CView::OnLButtonUp(nFlags, point);
}

All the drawing is done in the MouseMove function. First the previously drawn figure is erased (by redrawing over it using R2_NOT). Then the new figure is drawn using the new coordinates. Note that for drawing the figure only 3 things are required:

  1. The center coordinates
  2. A vertex coordinate
  3. The number of sides of the polygon

The loop computes all the other coordinates using these elements and draws lines connecting one vertex to the other.

//value of pi used for trig calcs 
const double PI = 3.1415926; 
void CPolygonsView::OnMouseMove(UINT nFlags, 
                                CPoint point) 
{
  // TODO: Add your message handler code 
  // here and/or call default
  if (m_Drag && PointOrigin!=point) 
  {                        // for mouse drag check
    CClientDC ClientDC(this); // graphics
    ClientDC.SetROP2(R2_NOT);
    double Ox , Oy , Px , Py;
    double phai ;
    //angle used by me to compute
    double theta ;
    //angle used by me to compute
    double hyp ;
    double x1 ;
    double mu ;
    double x2 ;
    double y2;

    int m_Sides = 3;//default figure = triangle
    Ox = PointOrigin.x;
    Oy = PointOrigin.y;
    Px = PointOld.x;
    Py = PointOld.y;
    phai = PI / ( m_Sides );
    theta = PI / 2 - phai;
    hyp = sqrt( ( Px - Ox ) * ( Px - Ox ) + 
                ( Py - Oy ) * ( Py - Oy ) );
    //hyp = hypotnuse
    // erase the previous drawn polygon
    for ( int f = 0;f <m_Sides;f++)
    {
      x1 = hyp * cos( theta );
      mu = atan2( Py - Oy , Px - Ox );
      x2 = x1 * cos( ( mu - theta ) );
      y2 = x1 * sin( ( mu - theta ) );
      ClientDC.MoveTo( int( Px ) , int( Py ) );
      ClientDC.LineTo( int( Px - 2 * x2 ) , 
                       int( Py - 2 * y2 ) );    
      Px = int( Px - 2 * x2 );
      Py = int( Py - 2 * y2 );
    }
    // draw the new polygon
    Px = point.x;
    Py = point.y;
    hyp = sqrt( ( Px - Ox ) * ( Px - Ox ) + 
                ( Py - Oy ) * ( Py - Oy ) );
    for ( f = 0;f<m_Sides;f++)
    {
      x1 = hyp * cos( theta );
      mu = atan2( Py - Oy , Px - Ox );
      x2 = x1 * cos( ( mu - theta ) );
      y2 = x1 * sin( ( mu - theta ) );
      ClientDC.MoveTo( int( Px ) , int( Py ) );
      ClientDC.LineTo( int( Px - 2 * x2 ) , 
                       int( Py - 2 * y2 ) );
      Px = int( Px - 2 * x2 );
      Py = int( Py - 2 * y2 );
    }
  }
  PointOld = point;// used to erase the previous drawn figure
  CView::OnMouseMove(nFlags, point);
}

Website : www.mayankmalik.cjb.net

Downloads

Download demo project - 88 Kb
Download source - 25 Kb



Comments

  • http://www.ucancode.net

    Posted by Legacy on 08/01/2003 12:00am

    Originally posted by: MFC Diagramming Library with Source Code!

    Great!!

    Reply
  • Speedup

    Posted by Legacy on 06/17/2003 12:00am

    Originally posted by: Alex

    One smart optimisation ( from the old days): Divide the XY area in 8 octants( or hexants,or whatever is the decomposition of N in prime factors). Compute the vertices for one and flip/mirror for th others. This will solve partially the problem of rounding and also speed up a lot the code.


    The code is very interesting.

    Alex

    Reply
  • Alternate Code

    Posted by Legacy on 07/17/2002 12:00am

    Originally posted by: DjinnKahn

    replace the given code snippet with this:
    
    


    void Draw(CClientDC& dc, CPoint orig, CPoint vertex, int iNumSides)
    {
    vertex -= orig;
    for (int i = 0; i <= iNumSides; i++) {
    double fCos = cos(i * 4*acos(0)/iNumSides);
    double fSin = sin(i * 4*acos(0)/iNumSides);
    CPoint p( int(vertex.x * fCos - vertex.y * fSin + .5),
    int(vertex.x * fSin + vertex.y * fCos + .5));
    if (i) dc.LineTo(p + orig);
    dc.MoveTo(p + orig);
    }
    }

    void CPolygonsView::OnMouseMove(UINT nFlags, CPoint point)
    {
    // TODO: Add your message handler code here and/or call default
    if (m_Drag && PointOrigin!=point)// for mouse drag check
    {
    CClientDC ClientDC(this);// INITIALIZE GRAPHICS
    ClientDC.SetROP2(R2_NOT);
    Draw(ClientDC, PointOrigin, PointOld, m_Sides);
    Draw(ClientDC, PointOrigin, point, m_Sides);
    }
    PointOld = point;// used to erase the previous drawn figure
    CView::OnMouseMove(nFlags, point);
    }

    Reply
  • S.O.S

    Posted by Legacy on 09/17/2001 12:00am

    Originally posted by: Samy

    Can anyone help me please?
    To generate a form,

    I want to draw "N" rectangle and lines in my GDI and for each rectangle I need to gave a name and save all properties (X1,Y1,X2,Y2) in text file.
    Each line must be resizable and tracking(I don't know haw to track a line).
    Each rectangle must be resizable and tracking(I already do this with one rectangle).
    Each rectangle must be able to receive a text(I already do this with one rectangle).
    The properties of each text in rectangle must be interactive changed by user and also saved in text file(I already do this using LbuttonDblclick + fontdialog).

    For example:
    Myfile.txt
    Rectangle name: X1: Y1: X2: Y2: fontsize: fontname:

    Title 100 120 200 220 12 Arial
    Adres 150 200 200 250 10 Currier
    .....

    It is posible to decide that I have i.e 10 elements. In this case I must initalize all of them and drawing one to one.
    But in this case user will not have any flexibility to add new rectangle any time when he want.

    Could any one gave me some good algoritm for that?
    Best regards,
    Samuel

    Reply
  • Rounding-problem ? no problem

    Posted by Legacy on 08/22/2001 12:00am

    Originally posted by: Dieter Hammer

    in th loop You have only to remove the (int) casts, that's all folks!
    Px = Px - 2 * x2 ;
    Py = Py - 2 * y2 ;

    Reply
  • The code is ok..Good

    Posted by Legacy on 08/17/2001 12:00am

    Originally posted by: James P

    Your code is quite ok.But can't you make it more powerful

    Reply
  • N-Sided Polygons

    Posted by Legacy on 08/16/2001 12:00am

    Originally posted by: Craig Moore

    I think that it may have been useful to post the fact that you wish to draw n-sided <i>regular</i> polygons, as surely there are scanline rendering algorithsm for drawing polygons already. Also, it may have been useful to post an algorithm for scanlining solid polygons, as they are more useful imho.

    Reply
  • Here are some thoughts for you...

    Posted by Legacy on 08/15/2001 12:00am

    Originally posted by: John

    A better approach might be to have a general n-sided
    
    polygon drawing function, such as:

    void DrawPoly( double x, double y, double Radius, double Angle,
    int Sides, COLORREF Color )
    {
    // set the pen and fill colors as needed
    // ...
    // ...

    double Delta = (2*3.14159265) / Sides;

    for ( int i = 0; i < Sides; i++ )
    {
    double nx, ny;

    nx = x + ( Radius * cos( Angle + i * Delta ) );
    ny = y + ( Radius * sin( Angle + i * Delta ) );

    if ( !i )
    MoveTo( (int)(x + Radius), (int)y );
    else
    LineTo( (int)nx, (int)ny );
    }
    }

    I left out the details of setting pen/brush colors, and I
    glossed over the actual drawing stuff, but the idea is to
    create the function and call it from inside the OnMouseMove
    code. That way, your code is much cleaner, and you can
    create n sided poly's from anywhere without having to
    copy/paste all over the place.


    Remember, C and C++ allow us to create functions which
    should be as reusable as possible. Less code means easier
    debugging and usually more efficient operation.


    Good luck!

    -John

    PS: Editing code in this browser window sucks. :-)

    Reply
  • its interesting

    Posted by Legacy on 08/14/2001 12:00am

    Originally posted by: ambrish

    thats a nice and interesting article.
    
    give a lot of insight.

    Reply
  • mull's vc code

    Posted by Legacy on 08/13/2001 12:00am

    Originally posted by: rohil sahgal

    i think mayank malik is one of the most talented programmers i've met and this is only a sample of what he can do....i've known him for the last 4 yrs and he's as good a person as he is a programmer!! if anybody out there is looking for a dedicated, talented and brilliant software programmer..look no further for he's ur man :)
    ensoi and keep the faith

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date