Click here to Skip to main content
Click here to Skip to main content

A Matrix-Based 2-D Polygon Clipping Class

By , 28 Mar 2003
 

Quick shot of the demo application.

Introduction

This code is a two-dimensional polygon-clipping algorithm that determines precisely where a line intersects with a polygon border. This code works for both concave and convex polygons of completely arbitrary shape and is able to handle any line orientation. Furthermore, all arrays used to hold the line and polygon coordinates are allocated dynamically so the only limit on the number of polygon vertices and intersecting lines is the amount of available memory. Error checking is used to ensure that the bounds of the dynamic arrays are not overrun.

Background

This code was developed while working on dose calculation routines for cancer radiation treatment therapy. For these calculations, it was necessary to accurately determine the intersections of certain features, both anatomical and mechanical, with the radiation field. As a result, CPolygonClip was born. Due to its implementation in a clinical setting, this code is quick, accurate and robust. Some methods and functions have been left out due to time constraints, but will be added in future.

Theory or How It Works

This is the nasty mathematical portion of the article. You can, of course, use the class without reading this, but it is best to know what you are dealing with before you dive right in. Fortunately, most programmers will have the necessary mathematical prerequisites to understand the material.
In general, polygon clipping is a mathematical technique that evaluates whether 2 three-dimensional objects intersect one another. In the more limited context of this article, polygon-clipping is used to determine the points of intersection of a line segment with a polygon. To implement the CPolygonClip class, two assumptions have been made. First, the vertices of the polygon are arranged in a clock-wise fashion. Secondly, the coordinate system of the device context is assumed to be MM_TEXT, although it would be relatively simple to convert output from the class to any other system. To define a line segment, a starting point P1(x1,y1) and an ending point P2(x2,y2) are used, while the polygon is defined by a series of verticies Vi(Xi,Yi), i = 1..n. (See figure.)

Polygon clipping illustration.

The coordinates of each point are considered the components of a vector whose z-component is unity. Now, let

Si = determinant(Vi, P1, P2) or,

Matrix determinant.

Si represents the equation of a line, the sign of which will be fixed for points lying on either side of the line. Therefore, by searching for a sign change in Si between two consecutive vertices it is possible to determine if an intersection of line and polygon exists between the vertex pair. Finding a sign change will guarantee an intersection of the polygon with the line segment defined by P1 and P2. This calculation is repeated for all lines that may possibly intersect the polygon border. Once all values of Si for all lines have been calculated, the total number of sign changes of S gives the total number of intersections of lines and polygon. Naturally, the total number of sign changes in Si for a given line is indicative of the number of intersections that particular line makes with the polygon. Si can also be used to determine if a line intersects precisely at a polygon vertex (collinear intersection). This situation is indicated by the condition Si = 0. Having found the number of intersections, it is now possible to determine the coordinates of the intersection points. This is done by formulating a system of two linear equations in two unknowns. It is trivial to solve these and obtain the intersection point. We need two equations:

y = mline*x + bline

and

y = mpoly*x + bpoly

where y is the y coordinate, mline the slope of the line, mpoly the slope of the polygon segment between the two vertices spanning the intersect, x the x-coordinate and bline and bpoly the y-intercept of line and poly, respectively. These equations are easily solved by setting the y values equal - that is, setting one equation equal to another. This allows one to evaluate x, the x-intersection coordinate. Once x is known, either equation may be used to determine y. The coordinate point (x,y) gives the intersection point of line and polygon. Caution must be exercised for lines that are vertical or lines that have the same slope, since the equations above cannot be solved in these cases.

Using the code

Simply insert the .h and .cpp files into your current project and you are away. Call member functions as needed. The compiler will spew out some conversion warnings, but these are mainly due to the screen drawing calls (ie: double to int) and are not particularly significant when placing dots on a screen.

The class consists of a total of 7 functions and 4 adjustable parameters. As mentioned previously, every array used is allocated dynamically thus allowing any arbitrary polygon shape and number of lines to be used (subject to available memory). The CPolygonClip class is constructed using:

CPolygonClip(unsigned int nNumVerticies, unsigned int nNumLines);
Where the parameters passed are the number of vertices of the polygon and the number of lines for which to calculate the intersections. The number of vertices passed must be one greater than the actual number present in the polygon - the last vertex of the polygon must be a duplicate of the first vertex of the polygon.
unsigned int* CalcSiDeterm(double* LineX1, double* LineY1, 
			          double* LineX2, double* LineY2, 
			          double* PolyVertexX, double* PolyVertexY);
This function calculates the Si determinants for all lines passed to it. LineX1 and LineY1 are pointers to arrays holding the x and y coordinate pairs of P1, while LineX2 and LineY2 are pointers to arrays holding the x and y coordinate pairs of P2. PolyVertexX and PolyVertexY are pointers to arrays holding the x and y coordinates of the polygon verticies. Again, it is important that these arrays have, as their last element, a vertex that is a duplicate of the first vertex of the polygon. CalcSiDeterm returns a pointer to an array that holds the number of intersections per line indexed by line number.
bool CPolygonClip::CalculateIntersections(double *LineX1, double *LineX2, 
double *LineY1, double *LineY2, 
double *PolyVertexX, double *PolyVertexY, 
unsigned int nMaxNumSignChanges)
CalculateIntersections() is fairly self-explanatory. It simply calculates the intersection coordinates of the points of intersection between the polygon and the line. It accepts the same parameters as CalcSiDeterm() with the exception of the last parameter, nMaxNumSignChanges which represents the maximum numbers of sign changes for all the given lines. This is returned by FindArrayMax() which is described below.
unsigned int CPolygonClip::FindArrayMax(unsigned int *pNumChanges)
FindArrayMax() simply accepts a pointer to an array and extracts the maximum value from that array. This output is passed as the parameter nMaxNumSignChanges to CalculateIntersections().
void CPolygonClip::Draw(CDC *pDC)
This function simply draws blue points at the location of the intersections. Finally,
double CPolygonClip::TurboDeterm(double Elem11, double Elem12, <BR>                                 double Elem13, double Elem21, double Elem22, <BR>                                 double Elem23)
is a helper function that calculates a quick determinant of a 3x3 matrix, accepting the first six elements of the matrix.
CheckValidPoint(CPoint *lpVertexPoints, int nCount, CPoint aPoint)
A private method to the class which prevents detection of points which to not lie on a finite line.

A typical usage of the class is as follows:
	//////////////////////////////////
	//    BEGIN POLYGON CLIPPING	
	//////////////////////////////////
	m_pPolygonClip = new CPolygonClip(NumberOfVerticies, NumberOfLines);
	ASSERT(m_pPolygonClip != NULL);

	unsigned int* pnSignChanges = 0;
	
	// Calculate the determinants
	pnSignChanges = m_pPolygonClip->CalcSiDeterm(pLineX1, pLineY1, <BR>                                  pLineX2, pLineY2, pPolyVertsX, pPolyVertsY);

       // Find maximum number of intersections
       unsigned int nNumChanges = m_pPolygonClip->FindArrayMax(pnSignChanges);

	// Calculate line/polygon intersections
	bool bSuccess = m_pPolygonClip->CalculateIntersections(pLineX1, <BR>                                       pLineX2, pLineY1, pLineY2, pPolyVertsX, <BR>                                       pPolyVertsY, nNumChanges);

	// should include some other error 
	// handling routine...try/catch, etc...
	// (this will do for now)
	ASSERT(bSuccess);		

	// Draw the intersection points
	m_pPolygonClip->Draw(pDC);
	//////////////////////////////////
	//    END POLYGON CLIPPING		
	//////////////////////////////////

Don't forget to call the destructor when finished with a particular instance of the class.

Points of Interest

A few things to note here. Unfortunately, due to the application this class was written for, it is necessary to call the member functions of the class in a certain order. There are flags present to ensure that calls are made in the correct sequence. This is more due to the architecture of the clinical software than anything else.
Secondly, the dynamic memory allocation was a bit of a chore - especially coming from a FORTRAN background where arrays are indexed from 1. In future, I would probably utilize a 2-D array class for this in order to make life easier.
As it stands, this is not the full implementation of the class. For certain reasons, I had to extract portions of the code in order to make it available. Therefore, some functions have not yet been implemented since they still need trimming. Included among these are functions to determine which segments of the line lie inside/outside of the polygon border and a function to dump some of the information to ASCII file.
The matrix method was used in favour of the vector algebraic method as I feel it is more elegant and matricies are far more suited to computer implementation than vector algebra.
At any rate, I think this provides a quick and easy to use implementation of some basic polygon clipping, routines for which I have not been able to find readily on the internet.

The demo app is fairly static, simply showing a polygon (in red) and some black lines. The blue dots indicate the points of intersection. However, the calculations are all performed at runtime (having placed all the working code in OnDraw()) so this is not simply some pre-drawn picture. Feel free to play around with the polygon verticies and line orientations to see that it works.

Update March 13, 2003

Discovered that for finite lines, points that did not actually lie on the line were being detected and intersection points were being calculated. To correct this a private member function was added that allows detection of points that lie solely on the line segment rather than on an infinite line.

Version History

Error handling in the constructor could be a bit better...

Version 1.0: Initial release.

Version 1.1: Fixed bad implementation which allowed intersection calculation for points that did not necessarily lie ON the line.

License

This article, along with any associated source code and files, is licensed under The Common Development and Distribution License (CDDL)

About the Author

73Zeppelin
Other
Anonymous Proxy Anonymous Proxy
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionNeed Code in C#membersatyasrinivas_45 Feb '12 - 9:03 
Hi,
I found the article very interesting , can you provide me in c#
Generalcrashes with a large number of pointsmemberSonar29 Apr '05 - 19:58 
Thanks for posting this very useful class. I'm trying to use it to clip a large number (serveral thousand) lines to the bounds of a polygon. I found that though it works well for a few hundred lines it crashes with a memory exception when NumberOfLines is set to 1000. Anyone else noticed this or have a solution?
 
Thanks,
 
John
GeneralRe: crashes with a large number of pointsmember73Zeppelin30 Apr '05 - 0:42 
Hmmmm...Does it look like there is a memory leak at all? I haven't had any problems with it to date...
GeneralRe: crashes with a large number of pointsmemberSonar30 Apr '05 - 3:44 
John,
 
Thanks for the quick response.
 
I tried using bounds checker to help find the problem but I didn't come up with anything.   My suspicion is that memory is getting stomped on somewhere.
 
If you chage the line:
<code>#define NumberOfLines 1000</code>
 
and then change your OnDraw function to replace the previously hardwired value of 10 with the following I think you'll exerience ths ame crash.  
 
Thanks again for looking into it.
 
<code>void CPolyClipDemoView::OnDraw(CDC* pDC)
{
     CPolyClipDemoDoc* pDoc = GetDocument();
     ASSERT_VALID(pDoc);
 
     // The code below is far from fancy, but it serves
     // to illustrate the idea...most of this shouldn't be
     // in OnDraw() -> Lines and polygons shouldn't be
     // generated here (slows things down during drawing)
     // but I'm lazy and all the important stuff can be found here
     // so it makes it easier to see what's happenin'
     double *pLineX1, *pLineX2, *pLineY1, *pLineY2;    
     double *pPolyVertsX, *pPolyVertsY;
 
     pLineX1 = new double[NumberOfLines];
     pLineX2 = new double[NumberOfLines];
 
     pLineY1 = new double[NumberOfLines];
     pLineY2 = new double[NumberOfLines];
 
     pPolyVertsX = new double[NumberOfVerticies];
     pPolyVertsY = new double[NumberOfVerticies];
 
     // Arbitrary origin for the lines
     double LineOrigin(/*100*/80);
 
     // Generate some line coordinates and fill arrays
     for (unsigned int LineIndex = 0; LineIndex < NumberOfLines; LineIndex++)
     {
          ASSERT(LineIndex < NumberOfLines);
 
          if (LineIndex < 5)          // Make horizontal lines
          {
               *(pLineX1 + LineIndex) = 100;
               *(pLineY1 + LineIndex) = LineOrigin + 2;
 
               *(pLineX2 + LineIndex) = GetSystemMetrics(SM_CXSCREEN) - 1000;
               *(pLineY2 + LineIndex) = LineOrigin;
          }
          else                         // Make vertical lines
          {
               *(pLineX1 + LineIndex) = LineOrigin - 120;
               *(pLineY1 + LineIndex) = 100;
 
               *(pLineX2 + LineIndex) = LineOrigin - 167;
               *(pLineY2 + LineIndex) = GetSystemMetrics(SM_CYSCREEN) - 650;
          }
 
          LineOrigin += 2;
         
          pDC->MoveTo(*(pLineX1 + LineIndex), *(pLineY1 + LineIndex));
          pDC->LineTo(*(pLineX2 + LineIndex), *(pLineY2 + LineIndex));
     }
    
     // And now the polygon...
     for (unsigned int VertexIndex = 0; VertexIndex < 9; VertexIndex++)
     {
          ASSERT(VertexIndex < NumberOfVerticies);
          switch (VertexIndex)
          {
               case 0:          // Vertex 1
                    *(pPolyVertsX + VertexIndex) = 160;
                    *(pPolyVertsY + VertexIndex) = /*160*/220;
                    break;
               case 1:          // Vertex 2
                    *(pPolyVertsX + VertexIndex) = 190;
                    *(pPolyVertsY + VertexIndex) = /*160*/220;
                    break;
               case 2:          // Vertex 3
                    *(pPolyVertsX + VertexIndex) = 190;
                    *(pPolyVertsY + VertexIndex) = 220;
                    break;
               case 3:          // Vertex 4
                    *(pPolyVertsX + VertexIndex) = /*225*/155;
                    *(pPolyVertsY + VertexIndex) = 220;
                    break;
               case 4:          // etc...
                    *(pPolyVertsX + VertexIndex) = /*225*/155;
                    *(pPolyVertsY + VertexIndex) = 160;
                    break;
               case 5:         
                    *(pPolyVertsX + VertexIndex) = GetSystemMetrics(SM_CXSCREEN) - 1200;
                    *(pPolyVertsY + VertexIndex) = 160;
                    break;
               case 6:         
                    *(pPolyVertsX + VertexIndex) = GetSystemMetrics(SM_CXSCREEN) - 1200;
                    *(pPolyVertsY + VertexIndex) = 600;
                    break;
               case 7:         
                    *(pPolyVertsX + VertexIndex) = /*160*/240;
                    *(pPolyVertsY + VertexIndex) = /*600*/400;
                    break;
               case 8:          // Close the polygon by ending up at the 1st point
                    *(pPolyVertsX + VertexIndex) = 160;
                    *(pPolyVertsY + VertexIndex) = 160;
                    break;
               default:     // Error
                    AfxMessageBox("Error.\n Cannot assign vertex.");         
                    AfxAbort();   // Cheesy bail-out
          }
     }
    
     CPen aPen;
     aPen.CreatePen(PS_SOLID, PenSize, RGB(255, 0, 0));    
     CPen* pOldPen = pDC->SelectObject(&aPen);
    
     // Draw the polygon lines so we can see it
     for (unsigned int i = 0; i < (NumberOfVerticies - 1); i++)
     {
          ASSERT(i < VertexIndex);
         
          pDC->MoveTo(*(pPolyVertsX + i), *(pPolyVertsY + i));
          pDC->LineTo(*(pPolyVertsX + (i + 1)), *(pPolyVertsY + (i + 1)));
     }
    
     pDC->SelectObject(pOldPen);
 
     //////////////////////////////////
     //      BEGIN POLYGON CLIPPING     //
     //////////////////////////////////
     m_pPolygonClip = new CPolygonClip(NumberOfVerticies, NumberOfLines);
     ASSERT(m_pPolygonClip != NULL);
 
     unsigned int* pnSignChanges = 0;
    
     // Calculate the determinants
     pnSignChanges = m_pPolygonClip->CalcSiDeterm(pLineX1, pLineY1,
                                                            pLineX2, pLineY2,
                                                            pPolyVertsX, pPolyVertsY);
 
     // Find maximum number of intersections
     unsigned int nNumChanges = m_pPolygonClip->FindArrayMax(pnSignChanges);
 
     // Calculate line/polygon intersections
     bool bSuccess = m_pPolygonClip->CalculateIntersections(pLineX1, pLineX2,
                                                                         pLineY1, pLineY2,
                                                                         pPolyVertsX, pPolyVertsY,
                                                                         nNumChanges);
     // should include some other error
     // handling routine...try/catch, etc...
     ASSERT(bSuccess);         
 
     // Draw the intersection points
     m_pPolygonClip->Draw(pDC);
     //////////////////////////////////
     //      END POLYGON CLIPPING          //
     //////////////////////////////////
 

     // Free the heap
     delete[] pLineX1;
     delete[] pLineX2;
     delete[] pLineY1;
     delete[] pLineY2;
     delete[] pPolyVertsX;
     delete[] pPolyVertsY;
 
     // Don't forget...
     delete m_pPolygonClip;
 
}</code>
GeneralRe: crashes with a large number of pointsmember73Zeppelin30 Apr '05 - 3:53 
Okay, I'll check it tonight and see if I can reproduce the error. I'm on a machine that doesn't have the code at the moment.
Generaltraitement d'imagesussAnonymous3 Dec '04 - 7:09 
ya personne qui peu m'aider svp
j'ai créer une interface graphique grace aux MFC (MDI) multi document interfae et je veux faire des traitements sur image jpeg ou bmp , c a dire faire une rotatoion par degrées sur cet matrice s'il ya qq1 qui sait comment faire envoyez ça a (bibo2u2002@yahoo.fr) et merci
GeneralRe: traitement d'imagememberKochise27 Nov '06 - 23:55 
http://www.rentacoder.com/
 
Kochise
 
In Code we trust !

GeneralFind the line between two areas&#8230;memberd00_ape15 Jul '04 - 2:46 
Really good article. Actually one of few algebra here on CP.
I’ll like to know if you have or seen a similar example but with intersection-lines instead of intersection-points and areas instead of lines.
 
Hope you get my point…

 
_____________________________
 
...and justice for all
 
APe
GeneralRe: Find the line between two areas…member73Zeppelin22 Jul '04 - 7:00 
Not entirely sure what you mean...
 
Am I correct in assuming that you want to find the area remaining when two polygons intersect?
 
Also, not sure what you mean about intersection-lines...the code in this article handles line-line intersection. The lines have to be defined by two points rather than a parametric equation....
Generalhelpmembertdtjuee10 Mar '04 - 6:11 
hi,john.
I have to say it's a pritty good article,and i am very interested in what you said --"polygon clipping is a mathematical technique that evaluates whether 2 three-dimensional objects intersect one another."
Recently I have been going with my graduate design about two 3D objects(cylinder & cylinder)intersecting ,which is what you said above .Now i want to know how to evaluates whether two 3D objects intersect one another from the polygon clipping. Would you like to give me some examples to explain it for me ?(This is my email: rain_field@eyou.com )
 
I'm a chinese boy,and my english is not good.Anyway,thanks in advance.
 
rainfield
GeneralRe: helpmember73Zeppelin10 Mar '04 - 11:13 
Hello,
 
As mentioned in the article "polygon clipping is a mathematical technique..." and thus you must have strong mathematical skills to understand the geometry of 3D objects. Of course the article I have written here is simplified into 2 dimensions and involves polygons and lines. You are asking me about cylinder-cylinder intersection in 3 dimensions. It is obvious that this is much more difficult. Unfortunately, it is not easy to adapt the code I have posted here to calculate the intersection of two cylinders. You will need much more advanced techniques. I am assuming that you have a strong mathematical background (if you don't, you will need it!). The following paper will be very useful to you:
http://www.magic-software.com/Documentation/IntersectionOfCylinders.pdf[^]
GeneralRe: helpmembertdtjuee12 Mar '04 - 1:53 
hi,john.thank you very much for your recommedation.
I am a graduate student and i think my math is not too bad .en....i suppose you are right .i need much more advaced technigues.
by the way ,why can't i open the page you gave ?
 
rainfield
GeneralRe: helpmember73Zeppelin12 Mar '04 - 2:06 
You will need Adobe Acrobat reader installed on your computer.
You can get it here:
http://www.adobe.com/products/acrobat/readstep2.html[^]
 
Hope that helps!
GeneralRe: helpmembertdtjuee12 Mar '04 - 4:32 
Smile | :)
i know what you mean .But i just want to know why can't i download it ?
Generali guess i found a problemmembermatthew_b06719 Feb '04 - 20:15 
hi,
imagine a rect topLeft = 0,0, bottomRight = 3587,2328
 
A line is plotted miles away(i guess)....(34504, 61046) & (34597, 61226)... the line is not touching the rect but ur algorithm shows sign-change.... D'Oh! | :doh: correct me if i'm wrong.
 
rgds
mathai___
GeneralRe: i guess i found a problemmember73Zeppelin19 Feb '04 - 21:56 
Hi,
 
Yes, I was aware of this problem, but had (I thought) fixed it in the latest update to this article. I think back in January...
 
I will try to repeat the problem with the data you provided. Thanks
for pointing this out.
GeneralRe: i guess i found a problemmembermatthew_b06720 Feb '04 - 6:10 
hi,
i require a fast algo that just checks(BOOL) if a line is passing through a rectangle... i'm trying to write a line latch algorithm...Sigh | :sigh: ... if u have some suggestion...great..
 

\
----\----
| \ |
| \ |
-------\-
\
 
regards
mathai___
GeneralRe: i guess i found a problemmember73Zeppelin20 Feb '04 - 7:36 
If a line passes through a polygon, or just a rectangle??
Generalthe fn is incompletemembermatthew_b06720 Feb '04 - 20:08 
#include
#include dy1*dx2)
return +1;

if (dx1*dy2 < dy1*dx2)
return -1;
if ((dx1*dx2 < 0) || (dy1*dy2 < 0))
return -1;
if ((dx1*dx1 + dy1*dy1) < (dx2*dx2 + dy2*dy2))
return +1;
return 0;
}
AND
/* Normalize rectangle */
if (rect.bottomRight.x < rect.topLeft.x) {
tmp = rect.bottomRight.x;
rect.bottomRight.x = rect.topLeft.x;
rect.topLeft.x = tmp;
}
if (rect.bottomRight.y = rect.topLeft.x && line.p1.x = rect.topLeft.y
&& line.p1.y <= rect.bottomRight.y);

}

GeneralRe: the fn is incompletemember73Zeppelin20 Feb '04 - 21:22 
Not sure what you mean, but okay...Hope it works for you!
GeneralRe: the fn is incompletemembermatthew_b06720 Feb '04 - 21:59 
this is the complete program u have posted. the bolded area is incomplete ( the function defenition if ccw...etc)
#include
#include dy1*dx2)
return +1;
if (dx1*dy2 < dy1*dx2)
return -1;
if ((dx1*dx2 < 0) || (dy1*dy2 < 0))
return -1;
if ((dx1*dx1 + dy1*dy1) < (dx2*dx2 + dy2*dy2))
return +1;
return 0;
}

 

/* Taken from Robert Sedgewick, Algoritthms in C++ */
 
bool intersect( Line line1, Line line2 )
{
return (( ccw(line1.p1, line1.p2, line2.p1)
* ccw(line1.p1, line1.p2, line2.p2)) <= 0)
&& (( ccw(line2.p1, line2.p2, line1.p1)
* ccw(line2.p1, line2.p2, line1.p2)) <= 0);
}
 

bool intersectRect( Rectangle rect, Line line )
{
Line line1, line2, line3, line4;
int tmp;

line1.p1 = rect.topLeft;
line1.p2 = line1.p1; line1.p2.x = rect.bottomRight.x;

line2.p1 = line1.p2;
line2.p2 = rect.bottomRight;

line3.p1 = line2.p2;
line3.p2 = rect.topLeft; line3.p2.y = rect.bottomRight.y;

line4.p1 = line3.p2;
line4.p2 = line1.p1;

if (intersect(line1, line) || intersect(line2, line)
|| intersect(line3, line) || intersect(line4, line))
return TRUE; /* line intersects outline of rectangle */

/* Now the line could still be completely within the rectangle.
This would also count as an intersection. */

/* Normalize rectangle */
if (rect.bottomRight.x < rect.topLeft.x) {
tmp = rect.bottomRight.x;
rect.bottomRight.x = rect.topLeft.x;
rect.topLeft.x = tmp;
}
if (rect.bottomRight.y = rect.topLeft.x && line.p1.x = rect.topLeft.y
&& line.p1.y <= rect.bottomRight.y);

}
 

int main( int argc, char* argv[] )
{
FILE* fin;
FILE* fout;
int n, dummy, i;
Rectangle rect;
Line line;

fin = fopen("intersection.in", "r");
assert( fin != 0 );
fout = fopen("intersection.out", "w");
assert( fout != 0 );

dummy = fscanf( fin, "%d", &n );
assert( dummy == 1 );

for (i=0; i < n; i++) {
dummy = fscanf( fin, "%d %d %d %d",
&line.p1.x, &line.p1.y,
&line.p2.x, &line.p2.y );
assert( dummy == 4 );

dummy = fscanf( fin, "%d %d %d %d",
&rect.topLeft.x, &rect.topLeft.y,
&rect.bottomRight.x, &rect.bottomRight.y );
assert( dummy == 4 );

fprintf( fout, "%c\n",
intersectRect( rect, line ) ? 'T' : 'F' );
}

fclose( fin );
fclose( fout );

return 0;
}
 


GeneralRe: the fn is incompletemember73Zeppelin21 Feb '04 - 1:34 
Here, try this: (forgot to enclose it in code tags...) Blush | :O
 
#include <stdio.h>
#include <assert.h>
 

typedef enum {
	FALSE = 0,
	TRUE = 1
} bool;
 
typedef struct {
	int x;
	int y;
} Point;
 
typedef struct {
	Point p1;
	Point p2;
} Line;
 
typedef struct {
	Point topLeft;
	Point bottomRight;
} Rectangle;
 

int ccw( Point p0, Point p1, Point p2 );
bool intersect( Line l1, Line l2 );
bool intersectRect( Rectangle r, Line l );
 

/* Taken from Robert Sedgewick, Algorithms in C++ */
 
/*  returns whether, in traveling from the first to the second
	to the third point, we turn counterclockwise (+1) or not (-1) */
 
int ccw( Point p0, Point p1, Point p2 )
{
	int dx1, dx2, dy1, dy2;
	
	dx1 = p1.x - p0.x; dy1 = p1.y - p0.y;
	dx2 = p2.x - p0.x; dy2 = p2.y - p0.y;
	
	if (dx1*dy2 > dy1*dx2)
		return +1;
	if (dx1*dy2 < dy1*dx2)
		return -1;
	if ((dx1*dx2 < 0) || (dy1*dy2 < 0))
		return -1;
	if ((dx1*dx1 + dy1*dy1) < (dx2*dx2 + dy2*dy2))
		return +1;
	return 0;
}
 

/* Taken from Robert Sedgewick, Algoritthms in C++ */
 
bool intersect( Line line1, Line line2 )
{
	return (( ccw(line1.p1, line1.p2, line2.p1)
			* ccw(line1.p1, line1.p2, line2.p2)) <= 0)
		&& (( ccw(line2.p1, line2.p2, line1.p1)
			* ccw(line2.p1, line2.p2, line1.p2)) <= 0);
}
 

bool intersectRect( Rectangle rect, Line line )
{
	Line line1, line2, line3, line4;
	int tmp;
	
	line1.p1 = rect.topLeft;
	line1.p2 = line1.p1; line1.p2.x = rect.bottomRight.x;
	
	line2.p1 = line1.p2;
	line2.p2 = rect.bottomRight;
	
	line3.p1 = line2.p2;
	line3.p2 = rect.topLeft; line3.p2.y = rect.bottomRight.y;
	
	line4.p1 = line3.p2;
	line4.p2 = line1.p1;
	
	if (intersect(line1, line) || intersect(line2, line)
				|| intersect(line3, line) || intersect(line4, line))
		return TRUE;	/* line intersects outline of rectangle */
	
	/*	Now the line could still be completely within the rectangle.
		This would also count as an intersection. */
	
	/* Normalize rectangle */
	if (rect.bottomRight.x < rect.topLeft.x) {
		tmp = rect.bottomRight.x;
		rect.bottomRight.x = rect.topLeft.x;
		rect.topLeft.x = tmp;
	}
	if (rect.bottomRight.y < rect.topLeft.y) {
		tmp = rect.bottomRight.y;
		rect.bottomRight.y = rect.topLeft.y;
		rect.topLeft.y = tmp;
	}
	
	/* Now we have for x and y: rect.bottomRight >= rect.topLeft */
	return (line.p1.x >= rect.topLeft.x && line.p1.x <= rect.bottomRight.x
		&& line.p1.y >= rect.topLeft.y && line.p1.y <= rect.bottomRight.y);
}
 

int main( int argc, char* argv[] )
{
	FILE*	fin;
	FILE*	fout;
	int		n, dummy, i;
	Rectangle	rect;
	Line		line;
	
	fin = fopen("intersection.in", "r");
	assert( fin != 0 );
	fout = fopen("intersection.out", "w");
	assert( fout != 0 );
	
	dummy = fscanf( fin, "%d", &n );
	assert( dummy == 1 );
	
	for (i=0; i < n; i++) {
		dummy = fscanf( fin, "%d %d %d %d",
			&line.p1.x, &line.p1.y,
			&line.p2.x, &line.p2.y );
		assert( dummy == 4 );
		
		dummy = fscanf( fin, "%d %d %d %d",
			&rect.topLeft.x, &rect.topLeft.y,
			&rect.bottomRight.x, &rect.bottomRight.y );
		assert( dummy == 4 );
		
		fprintf( fout, "%c\n",
			intersectRect( rect, line ) ? 'T' : 'F' );
	}
	
	fclose( fin );
	fclose( fout );
	
	return 0;
}
 

</assert.h></stdio.h>

Generaler....bugmembermatthew_b06721 Feb '04 - 21:29 
i'm sorry to be delivering the bad new but the 'bove code still has some bugz..... the following
 
chk out rect topLeft = 57400,32593, bottomRight = 60987, 34921
 
and the line (17711, 4217), (88995, 4217) D'Oh! | :doh:
 
gives a true
 

GeneralGreat article...one small thingmembercokeefe7 Feb '03 - 3:22 
Thanks, this is great article and it really helped me out a project I was working on. Fantastic approach!
 
I noticed a small memory leak in the CPolygonClip. The m_ppdTempIntrX and m_ppdTempIntrY members do not get cleaned up. Just add these lines to the destructor:
 
     for (unsigned int i = 0; i < m_nNumLines; i++)
     {
          delete[] m_ppdTempIntrX[i];
          delete[] m_ppdTempIntrY[i];
     }
 
     delete[] m_ppdTempIntrX;
     delete[] m_ppdTempIntrY;
 
Chris
GeneralRe: Great article...one small thingmember73Zeppelin7 Feb '03 - 16:01 
Hi.
Glad you could find this useful. It's nice to know that someone has a use for your hard work. Big Grin | :-D
I was aware of the memory leak issue. I have fixed that as well as a few other things that aren't present in the current release. These include a few potential problems with finite-sized lines. Unsure | :~
I was planning to send in the updated class in the next little while (once I get a few free moments).
 
Thanks for pointing out the leak though. I actually appreciate it. Sometimes it takes another person to see where you have gone wrong.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 29 Mar 2003
Article Copyright 2003 by 73Zeppelin
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid