Loading pcbnew/zones_test_and_combine_areas.cpp +2 −14 Original line number Original line Diff line number Diff line Loading @@ -169,16 +169,8 @@ int BOARD::TestAreaPolygon( ZONE_CONTAINER* CurrArea ) int y2i = p->GetY( is2 ); int y2i = p->GetY( is2 ); int x2f = p->GetX( is2_next ); int x2f = p->GetX( is2_next ); int y2f = p->GetY( is2_next ); int y2f = p->GetY( is2_next ); int ret = FindSegmentIntersections( x1i, int ret = FindSegmentIntersections( x1i, y1i, x1f, y1f, style, y1i, x2i, y2i, x2f, y2f, style2 ); x1f, y1f, style, x2i, y2i, x2f, y2f, style2 ); if( ret ) if( ret ) { { // intersection between non-adjacent sides // intersection between non-adjacent sides Loading Loading @@ -246,8 +238,6 @@ int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea, str += wxT( "such as adding cutouts. It can't be fixed automatically.\n" ); str += wxT( "such as adding cutouts. It can't be fixed automatically.\n" ); str += wxT( "Manual correction is recommended." ); str += wxT( "Manual correction is recommended." ); wxMessageBox( str ); wxMessageBox( str ); // bDontShowSelfIntersectionArcsWarning = dlg.bDontShowBoxState; } } return -1; // arcs intersect with other sides, error return -1; // arcs intersect with other sides, error } } Loading Loading @@ -427,8 +417,6 @@ int BOARD::CombineAllAreasInNet( int aNetCode, bool bMessageBox, bool bUseUtilit curr_area->m_Netname.GetData() ); curr_area->m_Netname.GetData() ); str += wxT( "Therefore, these areas can't be combined." ); str += wxT( "Therefore, these areas can't be combined." ); wxMessageBox( str ); wxMessageBox( str ); // bDontShowIntersectionArcsWarning = dlg.bDontShowBoxState; } } } } } } Loading polygon/PolyLine.cpp +83 −100 Original line number Original line Diff line number Diff line Loading @@ -34,6 +34,7 @@ CPolyLine::~CPolyLine() delete m_Kbool_Poly_Engine; delete m_Kbool_Poly_Engine; } } /** Function NormalizeWithKbool /** Function NormalizeWithKbool * Use the Kbool Library to clip contours: if outlines are crossing, the self-crossing polygon * Use the Kbool Library to clip contours: if outlines are crossing, the self-crossing polygon * is converted to non self-crossing polygon by adding extra points at the crossing locations * is converted to non self-crossing polygon by adding extra points at the crossing locations Loading Loading @@ -563,12 +564,12 @@ void ArmBoolEng( Bool_Engine* aBooleng, bool aConvertHoles ) } } int CPolyLine::NormalizeAreaOutlines( std::vector<CPolyLine*> * pa, bool bRetainArcs ) int CPolyLine::NormalizeAreaOutlines( std::vector<CPolyLine*> * pa, bool bRetainArcs ) { { return NormalizeWithKbool( pa, bRetainArcs ); return NormalizeWithKbool( pa, bRetainArcs ); } } // Restore arcs to a polygon where they were replaced with steps // Restore arcs to a polygon where they were replaced with steps // If pa != NULL, also use polygons in pa array // If pa != NULL, also use polygons in pa array // // Loading Loading @@ -1314,27 +1315,26 @@ void CPolyLine::Hatch() // test to see if a point is inside polyline // test to see if a point is inside polyline // // bool CPolyLine::TestPointInside( int x, int y ) bool CPolyLine::TestPointInside( int px, int py ) { { enum { MAXPTS = 100 }; if( !GetClosed() ) if( !GetClosed() ) wxASSERT( 0 ); wxASSERT( 0 ); // define line passing through (x,y), with slope = 2/3; // define line passing through (x,y), with slope = 2/3; // get intersection points // get intersection points double xx[MAXPTS], yy[MAXPTS]; int xx, yy; double slope = (double) 2.0 / 3.0; double slope = (double) 2.0 / 3.0; double a = y - slope * x; double a = py - slope * px; int nloops = 0; int nloops = 0; int npts; int npts; bool inside = false; // make this a loop so if my homebrew algorithm screws up, we try it again // make this a loop so if my homebrew algorithm screws up, we try it again do do { { // now find all intersection points of line with polyline sides // now find all intersection points of line with polyline sides npts = 0; npts = 0; inside = false; for( int icont = 0; icont<GetNumContours(); icont++ ) for( int icont = 0; icont<GetNumContours(); icont++ ) { { int istart = GetContourStart( icont ); int istart = GetContourStart( icont ); Loading @@ -1347,7 +1347,7 @@ bool CPolyLine::TestPointInside( int x, int y ) ok = FindLineSegmentIntersection( a, slope, ok = FindLineSegmentIntersection( a, slope, corner[iend].x, corner[iend].y, corner[iend].x, corner[iend].y, corner[istart].x, corner[istart].y, corner[istart].x, corner[istart].y, side_style[corner.size() - 1], side_style[iend], &x, &y, &x2, &y2 ); &x, &y, &x2, &y2 ); else else ok = FindLineSegmentIntersection( a, slope, ok = FindLineSegmentIntersection( a, slope, Loading @@ -1357,17 +1357,23 @@ bool CPolyLine::TestPointInside( int x, int y ) &x, &y, &x2, &y2 ); &x, &y, &x2, &y2 ); if( ok ) if( ok ) { { xx[npts] = (int) x; xx = (int) x; yy[npts] = (int) y; yy = (int) y; if( xx == px && yy == py ) return FALSE; // (x,y) is on a side, call it outside else if( xx > px ) inside = not inside; npts++; npts++; wxASSERT( npts<MAXPTS ); // overflow } } if( ok == 2 ) if( ok == 2 ) { { xx[npts] = (int) x2; xx = (int) x2; yy[npts] = (int) y2; yy = (int) y2; if( xx == px && yy == py ) return FALSE; // (x,y) is on a side, call it outside else if( xx > px ) inside = not inside; npts++; npts++; wxASSERT( npts<MAXPTS ); // overflow } } } } } } Loading @@ -1378,49 +1384,34 @@ bool CPolyLine::TestPointInside( int x, int y ) wxASSERT( npts % 2==0 ); // odd number of intersection points, error wxASSERT( npts % 2==0 ); // odd number of intersection points, error // count intersection points to right of (x,y), if odd (x,y) is inside polyline return inside; int ncount = 0; for( int ip = 0; ip<npts; ip++ ) { if( xx[ip] == x && yy[ip] == y ) return FALSE; // (x,y) is on a side, call it outside else if( xx[ip] > x ) ncount++; } if( ncount % 2 ) return TRUE; else return FALSE; } } // test to see if a point is inside polyline contour // test to see if a point is inside polyline contour // // bool CPolyLine::TestPointInsideContour( int icont, int x, int y ) bool CPolyLine::TestPointInsideContour( int icont, int px, int py ) { { if( icont >= GetNumContours() ) if( icont >= GetNumContours() ) return FALSE; return FALSE; enum { MAXPTS = 100 }; if( !GetClosed() ) if( !GetClosed() ) wxASSERT( 0 ); wxASSERT( 0 ); // define line passing through (x,y), with slope = 2/3; // define line passing through (x,y), with slope = 2/3; // get intersection points // get intersection points double xx[MAXPTS], yy[MAXPTS]; int xx, yy; double slope = (double) 2.0 / 3.0; double slope = (double) 2.0 / 3.0; double a = y - slope * x; double a = py - slope * px; int nloops = 0; int nloops = 0; int npts; int npts; bool inside = false; // make this a loop so if my homebrew algorithm screws up, we try it again // make this a loop so if my homebrew algorithm screws up, we try it again do do { { // now find all intersection points of line with polyline sides // now find all intersection points of line with polyline sides npts = 0; npts = 0; inside = false; int istart = GetContourStart( icont ); int istart = GetContourStart( icont ); int iend = GetContourEnd( icont ); int iend = GetContourEnd( icont ); for( int ic = istart; ic<=iend; ic++ ) for( int ic = istart; ic<=iend; ic++ ) Loading @@ -1431,7 +1422,7 @@ bool CPolyLine::TestPointInsideContour( int icont, int x, int y ) ok = FindLineSegmentIntersection( a, slope, ok = FindLineSegmentIntersection( a, slope, corner[iend].x, corner[iend].y, corner[iend].x, corner[iend].y, corner[istart].x, corner[istart].y, corner[istart].x, corner[istart].y, side_style[corner.size() - 1], side_style[iend], &x, &y, &x2, &y2 ); &x, &y, &x2, &y2 ); else else ok = FindLineSegmentIntersection( a, slope, ok = FindLineSegmentIntersection( a, slope, Loading @@ -1441,17 +1432,23 @@ bool CPolyLine::TestPointInsideContour( int icont, int x, int y ) &x, &y, &x2, &y2 ); &x, &y, &x2, &y2 ); if( ok ) if( ok ) { { xx[npts] = (int) x; xx = (int) x; yy[npts] = (int) y; yy = (int) y; npts++; npts++; wxASSERT( npts<MAXPTS ); // overflow if( xx == px && yy == py ) return FALSE; // (x,y) is on a side, call it outside else if( xx > px ) inside = not inside; } } if( ok == 2 ) if( ok == 2 ) { { xx[npts] = (int) x2; xx = (int) x2; yy[npts] = (int) y2; yy = (int) y2; npts++; npts++; wxASSERT( npts<MAXPTS ); // overflow if( xx == px && yy == py ) return FALSE; // (x,y) is on a side, call it outside else if( xx > px ) inside = not inside; } } } } Loading @@ -1461,20 +1458,7 @@ bool CPolyLine::TestPointInsideContour( int icont, int x, int y ) wxASSERT( npts % 2==0 ); // odd number of intersection points, error wxASSERT( npts % 2==0 ); // odd number of intersection points, error // count intersection points to right of (x,y), if odd (x,y) is inside polyline return inside; int ncount = 0; for( int ip = 0; ip<npts; ip++ ) { if( xx[ip] == x && yy[ip] == y ) return FALSE; // (x,y) is on a side, call it outside else if( xx[ip] > x ) ncount++; } if( ncount % 2 ) return TRUE; else return FALSE; } } Loading Loading @@ -1545,7 +1529,6 @@ void CPolyLine::SetEndContour( int ic, bool end_contour ) } } void CPolyLine::AppendArc( int xi, int yi, int xf, int yf, int xc, int yc, int num ) void CPolyLine::AppendArc( int xi, int yi, int xf, int yf, int xc, int yc, int num ) { { // get radius // get radius Loading polygon/PolyLine.h +2 −2 Original line number Original line Diff line number Diff line Loading @@ -47,10 +47,10 @@ void ArmBoolEng( Bool_Engine* aBooleng, bool aConvertHoles = false ); #define to_int( x ) (int) round( (x) ) #define to_int( x ) (int) round( (x) ) #ifndef min #ifndef min #define min( x1, x2 ) ( (x1) > (x2) ) ? (x2) : (x1) #define min( x1, x2 ) ( (x1) > (x2) ? (x2) : (x1) ) #endif #endif #ifndef max #ifndef max #define max( x1, x2 ) ( (x1) > (x2) ) ? (x1) : (x2) #define max( x1, x2 ) ( (x1) > (x2) ? (x1) : (x2) ) #endif #endif class CRect class CRect Loading polygon/math_for_graphics.cpp +0 −1 Original line number Original line Diff line number Diff line Loading @@ -639,7 +639,6 @@ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y int * x, int * y, double * d ) int * x, int * y, double * d ) { { double a, b, dist; double a, b, dist; // first, test for intersection // first, test for intersection if( x1i == x1f && x2i == x2f ) if( x1i == x1f && x2i == x2f ) { { Loading polygon/polygon_test_point_inside.cpp 0 → 100644 +355 −0 Original line number Original line Diff line number Diff line ///////////////////////////////////////////////////////////////////////////// // Name: polygon_test_point_inside.cpp ///////////////////////////////////////////////////////////////////////////// #include <math.h> #include <vector> #include "PolyLine.h" using namespace std; /* this algo uses the the Jordan curve theorem to find if a point is inside or outside a polygon: * It run a semi-infinite line horizontally (increasing x, fixed y) * out from the test point, and count how many edges it crosses. * At each crossing, the ray switches between inside and outside. * If odd nimber, the test point is inside the polygon * This is called the Jordan curve theorem, or sometimes referred to as the "even-odd" test. */ /* 2 versions are given. * the second version is GPL (currently used) * the first version is for explanations and tests (used to test the second version) * both use the same algorithm. */ #if 0 /* This text and the algorithm come from http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html * * PNPOLY - Point Inclusion in Polygon Test * W. Randolph Franklin (WRF) * * Table of Contents * * 1. The C Code <#The C Code> * 2. The Method <#The Method> * 3. Originality <#Originality> * 4. The Inequality Tests are Tricky <#The Inequality Tests are Tricky> * 5. C Semantics <#C Semantics> * 6. Point on a (Boundary) Edge <#Point on an Edge> * 7. Multiple Components and Holes <#Listing the Vertices> * 8. Testing Which One of Many Polygons Contains the Point <#Testing a * Point Against Many Polygons> * 9. Explanation of /"for (i = 0, j = nvert-1; i < nvert; j = i++)"/ * <#Explanation> * 10. Fortran Code for the Point in Polygon Test <#Fortran Code for the * Point in Polygon Test> * 11. Converting the Code to All Integers <#Converting the Code to All * Integers> * 12. License to Use <#License to Use> * * The C Code * * Here is the code, for reference. Excluding lines with only braces, there * are only /7 lines/ of code. * * int pnpoly(int nvert, float *vertx, float *verty, float ref_pointX, float ref_pointY) * { * int i, j, c = 0; * for (i = 0, j = nvert-1; i < nvert; j = i++) { * if ( ((verty[i]>ref_pointY) != (verty[j]>ref_pointY)) && * (ref_pointX < (vertx[j]-vertx[i]) * (ref_pointY-verty[i]) / (verty[j]-verty[i]) + vertx[i]) ) * c = !c; * } * return c; * } * * Argument Meaning * nvert Number of vertices in the polygon. Whether to repeat the first * vertex at the end is discussed below. * vertx, verty Arrays containing the x- and y-coordinates of the * polygon's vertices. * ref_pointX, ref_pointY X- and y-coordinate of the test point. * * * The Method * * I run a semi-infinite ray horizontally (increasing x, fixed y) out from * the test point, and count how many edges it crosses. At each crossing, * the ray switches between inside and outside. This is called the /Jordan * curve theorem/. * * The case of the ray going thru a vertex is handled correctly via a * careful selection of inequalities. Don't mess with this code unless * you're familiar with the idea of /Simulation of Simplicity/. This * pretends to shift the ray infinitesimally to one side so that it either * clearly intersects, or clearly doesn't touch. Since this is merely a * conceptual, infinitesimal, shift, it never creates an intersection that * didn't exist before, and never destroys an intersection that clearly * existed before. * * The ray is tested against each edge thus: * * 1. Is the point in the half-plane below the extended edge? and * 2. Is the point's X coordinate within the edge's X-range? * * Handling endpoints here is tricky. * * * Originality * * I make no claim to having invented the idea. However in 1970, I did * produce the Fortran code given below on my own, and include it in a * package of cartographic SW publicly-distributed by David Douglas, Dept * of Geography, Simon Fraser U and U of Ottawa. * * Earlier implementations of point-in-polygon testing presumably exist, * tho the code might never have been released. Pointers to prior art, * especially publicly available code, are welcome. One early publication, * which doesn't handle the point on an edge, and has a typo, is this: * * M Shimrat, "Algorithm 112, Position of Point Relative to Polygon", * /Comm. ACM/ 5(8), Aug 1962, p 434. * * A well-written recent summary is this: * * E Haines, /Point in Polygon Strategies/, * http://www.acm.org/pubs/tog/editors/erich/ptinpoly/, 1994. * * * The Inequality Tests are Tricky * * If translating the program to another language, be sure to get the * inequalities in the conditional correct. They were carefully chosen to * make the program work correctly when the point is vertically below a vertex. * * Several people have thought that my program was wrong, when really * /they/ had gotten the inequalities wrong. * * * C Semantics * * My code uses the fact that, in the C language, when executing the code |a&&b|, if |a| is false, then |b| must not be evaluated. If your * compiler doesn't do this, then it's not implementing C, and you will get * a divide-by-zero, i.a., when the test point is vertically in line with a * vertical edge. When translating this code to another language with * different semantics, then you must implement this test explicitly. * * * Point on a (Boundary) Edge * * PNPOLY partitions the plane into points inside the polygon and points * outside the polygon. Points that are on the boundary are classified as * either inside or outside. * * 1. * * Any particular point is always classified consistently the same * way. In the following figure, consider what PNPOLY would say when * the red point, /P/, is tested against the two triangles, /T_L / * and /T_R /. Depending on internal roundoff errors, PNPOLY may say * that /P/ is in /T_L / or in /T_R /. However it will always give * the same answer when /P/ is tested against those triangles. That * is, if PNPOLY finds that /P/ is in /T_L /, then it will find that * /P/ is not /T_R /. If PNPOLY finds that /P/ is not in /T_L /, then * it will find that /P/ is in /T_R /. * * 2. If you want to know when a point is exactly on the boundary, you * need another program. This is only one of many functions that * PNPOLY lacks; it also doesn't predict tomorrow's weather. You are * free to extend PNPOLY's source code. * * 3. The first reason for this is the numerical analysis position that * you should not be testing exact equality unless your input is * exact. Even then, computational roundoff error would often make * the result wrong. * * 4. The second reason is that, if you partition a region of the plane * into polygons, i.e., form a planar graph, then PNPOLY will locate * each point into exactly one polygon. In other words, PNPOLY * considers each polygon to be topologically a semi-open set. This * makes things simpler, i.e., causes fewer special cases, if you use * PNPOLY as part of a larger system. Examples of this include * locating a point in a planar graph, and intersecting two planar * graphs. * * * Explanation of /"for (i = 0, j = nvert-1; i < nvert; j = i++)"/ * * The intention is to execute the loop for each i from 0 to nvert-1. For * each iteration, j is i-1. However that wraps, so if i=0 then j=nvert-1. * Therefore the current edge runs between verts j and i, and the loop is * done once per edge. In detail: * * 1. Start by setting i and j: * i = 0 * j = nvert-1 * 2. If i<nvert is false then exit the loop. * 3. Do the loop body. * 4. Set j=i and then * add 1 to i and then * 5. Go back to step 2. * * * * Converting the Code to All Integers * * If you want to convert the code from floats to integers, consider these * issues. * * 1. On many current processors floats are at least as fast as ints. * 2. If you move the denominator over to the other side of the * inequality, remember that, when the denominator is negative, the * inequality will flip. * 3. If coordinates are large enough, the multiplication will silently * overflow. * * * License to Use * Copyright (c) 1970-2003, Wm. Randolph Franklin * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimers. * 2. Redistributions in binary form must reproduce the above copyright * notice in the documentation and/or other materials provided with * the distribution. * 3. The name of W. Randolph Franklin may not be used to endorse or * promote products derived from this Software without specific prior * written permission. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * * Copyright © 1994-2006, W Randolph Franklin (WRF) * <http://wrfranklin.org/> You may use my material for non-profit research * and education, provided that you credit me, and link back to my home page. * http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html, * 05/20/2008 20:36:42 */ bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList, int istart, int iend, int refx, int refy ) /** Function TestPointInsidePolygon * test if a point is inside or outside a polygon. * @param aPolysList: the list of polygons * @param istart: the starting point of a given polygon in m_FilledPolysList. * @param iend: the ending point of the polygon in m_FilledPolysList. * @param refx, refy: the point coordinate to test * @return true if the point is inside, false for outside */ { double ref_pointX = refx; double ref_pointY = refy; bool inside = false; for( int ii = istart, jj = iend; ii <= iend; jj = ii++ ) { double seg_startX, seg_startY; // starting point for the segment to test seg_startX = aPolysList[ii].x; seg_startY = aPolysList[ii].y; double seg_endX, seg_endY; // ending point for the segment to test seg_endX = aPolysList[jj].x; seg_endY = aPolysList[jj].y; if( ( ( seg_startY > ref_pointY ) != (seg_endY > ref_pointY ) ) && (ref_pointX < (seg_endX - seg_startX) * (ref_pointY - seg_startY) / (seg_endY - seg_startY) + seg_startX) ) inside = not inside; } return inside; } #else /* this algo come from freePCB. */ bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList, int istart, int iend, int refx, int refy ) /** Function TestPointInsidePolygon * test if a point is inside or outside a polygon. * if a point is on a outline segment, it is considered outside the polygon * @param aPolysList: the list of polygons * @param istart: the starting point of a given polygon in m_FilledPolysList. * @param iend: the ending point of the polygon in m_FilledPolysList. * @param refx,refy: the point coordinate to test * @return true if the point is inside, false for outside * this algorithm come from FreePCB. */ { #define OUTSIDE_IF_ON_SIDE 0 // = 1 if we consider point on a side outside the polygon // define line passing through (x,y), with slope = 0 (horizontal line) // get intersection points // count intersection points to right of (x,y), if odd (x,y) is inside polyline int xx, yy; double slope = 0; double a = refy - slope * refx; int ics, ice; bool inside = false; // find all intersection points of line with polyline sides for( ics = istart, ice = iend; ics <= iend; ice = ics++ ) { double x, y, x2, y2; int ok = FindLineSegmentIntersection( a, slope, aPolysList[ics].x, aPolysList[ics].y, aPolysList[ice].x, aPolysList[ice].y, 0, &x, &y, &x2, &y2 ); if( ok ) { xx = (int) x; yy = (int) y; #if OUTSIDE_IF_ON_SIDE if( xx == refx && yy == refy ) return false; // (x,y) is on a side, call it outside else #endif if( xx > refx ) inside = not inside; } if( ok == 2 ) { xx = (int) x2; yy = (int) y2; #if OUTSIDE_IF_ON_SIDE if( xx == refx && yy == refy ) return false; // (x,y) is on a side, call it outside else #endif if( xx > refx ) inside = not inside; } } return inside; } #endif Loading
pcbnew/zones_test_and_combine_areas.cpp +2 −14 Original line number Original line Diff line number Diff line Loading @@ -169,16 +169,8 @@ int BOARD::TestAreaPolygon( ZONE_CONTAINER* CurrArea ) int y2i = p->GetY( is2 ); int y2i = p->GetY( is2 ); int x2f = p->GetX( is2_next ); int x2f = p->GetX( is2_next ); int y2f = p->GetY( is2_next ); int y2f = p->GetY( is2_next ); int ret = FindSegmentIntersections( x1i, int ret = FindSegmentIntersections( x1i, y1i, x1f, y1f, style, y1i, x2i, y2i, x2f, y2f, style2 ); x1f, y1f, style, x2i, y2i, x2f, y2f, style2 ); if( ret ) if( ret ) { { // intersection between non-adjacent sides // intersection between non-adjacent sides Loading Loading @@ -246,8 +238,6 @@ int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea, str += wxT( "such as adding cutouts. It can't be fixed automatically.\n" ); str += wxT( "such as adding cutouts. It can't be fixed automatically.\n" ); str += wxT( "Manual correction is recommended." ); str += wxT( "Manual correction is recommended." ); wxMessageBox( str ); wxMessageBox( str ); // bDontShowSelfIntersectionArcsWarning = dlg.bDontShowBoxState; } } return -1; // arcs intersect with other sides, error return -1; // arcs intersect with other sides, error } } Loading Loading @@ -427,8 +417,6 @@ int BOARD::CombineAllAreasInNet( int aNetCode, bool bMessageBox, bool bUseUtilit curr_area->m_Netname.GetData() ); curr_area->m_Netname.GetData() ); str += wxT( "Therefore, these areas can't be combined." ); str += wxT( "Therefore, these areas can't be combined." ); wxMessageBox( str ); wxMessageBox( str ); // bDontShowIntersectionArcsWarning = dlg.bDontShowBoxState; } } } } } } Loading
polygon/PolyLine.cpp +83 −100 Original line number Original line Diff line number Diff line Loading @@ -34,6 +34,7 @@ CPolyLine::~CPolyLine() delete m_Kbool_Poly_Engine; delete m_Kbool_Poly_Engine; } } /** Function NormalizeWithKbool /** Function NormalizeWithKbool * Use the Kbool Library to clip contours: if outlines are crossing, the self-crossing polygon * Use the Kbool Library to clip contours: if outlines are crossing, the self-crossing polygon * is converted to non self-crossing polygon by adding extra points at the crossing locations * is converted to non self-crossing polygon by adding extra points at the crossing locations Loading Loading @@ -563,12 +564,12 @@ void ArmBoolEng( Bool_Engine* aBooleng, bool aConvertHoles ) } } int CPolyLine::NormalizeAreaOutlines( std::vector<CPolyLine*> * pa, bool bRetainArcs ) int CPolyLine::NormalizeAreaOutlines( std::vector<CPolyLine*> * pa, bool bRetainArcs ) { { return NormalizeWithKbool( pa, bRetainArcs ); return NormalizeWithKbool( pa, bRetainArcs ); } } // Restore arcs to a polygon where they were replaced with steps // Restore arcs to a polygon where they were replaced with steps // If pa != NULL, also use polygons in pa array // If pa != NULL, also use polygons in pa array // // Loading Loading @@ -1314,27 +1315,26 @@ void CPolyLine::Hatch() // test to see if a point is inside polyline // test to see if a point is inside polyline // // bool CPolyLine::TestPointInside( int x, int y ) bool CPolyLine::TestPointInside( int px, int py ) { { enum { MAXPTS = 100 }; if( !GetClosed() ) if( !GetClosed() ) wxASSERT( 0 ); wxASSERT( 0 ); // define line passing through (x,y), with slope = 2/3; // define line passing through (x,y), with slope = 2/3; // get intersection points // get intersection points double xx[MAXPTS], yy[MAXPTS]; int xx, yy; double slope = (double) 2.0 / 3.0; double slope = (double) 2.0 / 3.0; double a = y - slope * x; double a = py - slope * px; int nloops = 0; int nloops = 0; int npts; int npts; bool inside = false; // make this a loop so if my homebrew algorithm screws up, we try it again // make this a loop so if my homebrew algorithm screws up, we try it again do do { { // now find all intersection points of line with polyline sides // now find all intersection points of line with polyline sides npts = 0; npts = 0; inside = false; for( int icont = 0; icont<GetNumContours(); icont++ ) for( int icont = 0; icont<GetNumContours(); icont++ ) { { int istart = GetContourStart( icont ); int istart = GetContourStart( icont ); Loading @@ -1347,7 +1347,7 @@ bool CPolyLine::TestPointInside( int x, int y ) ok = FindLineSegmentIntersection( a, slope, ok = FindLineSegmentIntersection( a, slope, corner[iend].x, corner[iend].y, corner[iend].x, corner[iend].y, corner[istart].x, corner[istart].y, corner[istart].x, corner[istart].y, side_style[corner.size() - 1], side_style[iend], &x, &y, &x2, &y2 ); &x, &y, &x2, &y2 ); else else ok = FindLineSegmentIntersection( a, slope, ok = FindLineSegmentIntersection( a, slope, Loading @@ -1357,17 +1357,23 @@ bool CPolyLine::TestPointInside( int x, int y ) &x, &y, &x2, &y2 ); &x, &y, &x2, &y2 ); if( ok ) if( ok ) { { xx[npts] = (int) x; xx = (int) x; yy[npts] = (int) y; yy = (int) y; if( xx == px && yy == py ) return FALSE; // (x,y) is on a side, call it outside else if( xx > px ) inside = not inside; npts++; npts++; wxASSERT( npts<MAXPTS ); // overflow } } if( ok == 2 ) if( ok == 2 ) { { xx[npts] = (int) x2; xx = (int) x2; yy[npts] = (int) y2; yy = (int) y2; if( xx == px && yy == py ) return FALSE; // (x,y) is on a side, call it outside else if( xx > px ) inside = not inside; npts++; npts++; wxASSERT( npts<MAXPTS ); // overflow } } } } } } Loading @@ -1378,49 +1384,34 @@ bool CPolyLine::TestPointInside( int x, int y ) wxASSERT( npts % 2==0 ); // odd number of intersection points, error wxASSERT( npts % 2==0 ); // odd number of intersection points, error // count intersection points to right of (x,y), if odd (x,y) is inside polyline return inside; int ncount = 0; for( int ip = 0; ip<npts; ip++ ) { if( xx[ip] == x && yy[ip] == y ) return FALSE; // (x,y) is on a side, call it outside else if( xx[ip] > x ) ncount++; } if( ncount % 2 ) return TRUE; else return FALSE; } } // test to see if a point is inside polyline contour // test to see if a point is inside polyline contour // // bool CPolyLine::TestPointInsideContour( int icont, int x, int y ) bool CPolyLine::TestPointInsideContour( int icont, int px, int py ) { { if( icont >= GetNumContours() ) if( icont >= GetNumContours() ) return FALSE; return FALSE; enum { MAXPTS = 100 }; if( !GetClosed() ) if( !GetClosed() ) wxASSERT( 0 ); wxASSERT( 0 ); // define line passing through (x,y), with slope = 2/3; // define line passing through (x,y), with slope = 2/3; // get intersection points // get intersection points double xx[MAXPTS], yy[MAXPTS]; int xx, yy; double slope = (double) 2.0 / 3.0; double slope = (double) 2.0 / 3.0; double a = y - slope * x; double a = py - slope * px; int nloops = 0; int nloops = 0; int npts; int npts; bool inside = false; // make this a loop so if my homebrew algorithm screws up, we try it again // make this a loop so if my homebrew algorithm screws up, we try it again do do { { // now find all intersection points of line with polyline sides // now find all intersection points of line with polyline sides npts = 0; npts = 0; inside = false; int istart = GetContourStart( icont ); int istart = GetContourStart( icont ); int iend = GetContourEnd( icont ); int iend = GetContourEnd( icont ); for( int ic = istart; ic<=iend; ic++ ) for( int ic = istart; ic<=iend; ic++ ) Loading @@ -1431,7 +1422,7 @@ bool CPolyLine::TestPointInsideContour( int icont, int x, int y ) ok = FindLineSegmentIntersection( a, slope, ok = FindLineSegmentIntersection( a, slope, corner[iend].x, corner[iend].y, corner[iend].x, corner[iend].y, corner[istart].x, corner[istart].y, corner[istart].x, corner[istart].y, side_style[corner.size() - 1], side_style[iend], &x, &y, &x2, &y2 ); &x, &y, &x2, &y2 ); else else ok = FindLineSegmentIntersection( a, slope, ok = FindLineSegmentIntersection( a, slope, Loading @@ -1441,17 +1432,23 @@ bool CPolyLine::TestPointInsideContour( int icont, int x, int y ) &x, &y, &x2, &y2 ); &x, &y, &x2, &y2 ); if( ok ) if( ok ) { { xx[npts] = (int) x; xx = (int) x; yy[npts] = (int) y; yy = (int) y; npts++; npts++; wxASSERT( npts<MAXPTS ); // overflow if( xx == px && yy == py ) return FALSE; // (x,y) is on a side, call it outside else if( xx > px ) inside = not inside; } } if( ok == 2 ) if( ok == 2 ) { { xx[npts] = (int) x2; xx = (int) x2; yy[npts] = (int) y2; yy = (int) y2; npts++; npts++; wxASSERT( npts<MAXPTS ); // overflow if( xx == px && yy == py ) return FALSE; // (x,y) is on a side, call it outside else if( xx > px ) inside = not inside; } } } } Loading @@ -1461,20 +1458,7 @@ bool CPolyLine::TestPointInsideContour( int icont, int x, int y ) wxASSERT( npts % 2==0 ); // odd number of intersection points, error wxASSERT( npts % 2==0 ); // odd number of intersection points, error // count intersection points to right of (x,y), if odd (x,y) is inside polyline return inside; int ncount = 0; for( int ip = 0; ip<npts; ip++ ) { if( xx[ip] == x && yy[ip] == y ) return FALSE; // (x,y) is on a side, call it outside else if( xx[ip] > x ) ncount++; } if( ncount % 2 ) return TRUE; else return FALSE; } } Loading Loading @@ -1545,7 +1529,6 @@ void CPolyLine::SetEndContour( int ic, bool end_contour ) } } void CPolyLine::AppendArc( int xi, int yi, int xf, int yf, int xc, int yc, int num ) void CPolyLine::AppendArc( int xi, int yi, int xf, int yf, int xc, int yc, int num ) { { // get radius // get radius Loading
polygon/PolyLine.h +2 −2 Original line number Original line Diff line number Diff line Loading @@ -47,10 +47,10 @@ void ArmBoolEng( Bool_Engine* aBooleng, bool aConvertHoles = false ); #define to_int( x ) (int) round( (x) ) #define to_int( x ) (int) round( (x) ) #ifndef min #ifndef min #define min( x1, x2 ) ( (x1) > (x2) ) ? (x2) : (x1) #define min( x1, x2 ) ( (x1) > (x2) ? (x2) : (x1) ) #endif #endif #ifndef max #ifndef max #define max( x1, x2 ) ( (x1) > (x2) ) ? (x1) : (x2) #define max( x1, x2 ) ( (x1) > (x2) ? (x1) : (x2) ) #endif #endif class CRect class CRect Loading
polygon/math_for_graphics.cpp +0 −1 Original line number Original line Diff line number Diff line Loading @@ -639,7 +639,6 @@ bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y int * x, int * y, double * d ) int * x, int * y, double * d ) { { double a, b, dist; double a, b, dist; // first, test for intersection // first, test for intersection if( x1i == x1f && x2i == x2f ) if( x1i == x1f && x2i == x2f ) { { Loading
polygon/polygon_test_point_inside.cpp 0 → 100644 +355 −0 Original line number Original line Diff line number Diff line ///////////////////////////////////////////////////////////////////////////// // Name: polygon_test_point_inside.cpp ///////////////////////////////////////////////////////////////////////////// #include <math.h> #include <vector> #include "PolyLine.h" using namespace std; /* this algo uses the the Jordan curve theorem to find if a point is inside or outside a polygon: * It run a semi-infinite line horizontally (increasing x, fixed y) * out from the test point, and count how many edges it crosses. * At each crossing, the ray switches between inside and outside. * If odd nimber, the test point is inside the polygon * This is called the Jordan curve theorem, or sometimes referred to as the "even-odd" test. */ /* 2 versions are given. * the second version is GPL (currently used) * the first version is for explanations and tests (used to test the second version) * both use the same algorithm. */ #if 0 /* This text and the algorithm come from http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html * * PNPOLY - Point Inclusion in Polygon Test * W. Randolph Franklin (WRF) * * Table of Contents * * 1. The C Code <#The C Code> * 2. The Method <#The Method> * 3. Originality <#Originality> * 4. The Inequality Tests are Tricky <#The Inequality Tests are Tricky> * 5. C Semantics <#C Semantics> * 6. Point on a (Boundary) Edge <#Point on an Edge> * 7. Multiple Components and Holes <#Listing the Vertices> * 8. Testing Which One of Many Polygons Contains the Point <#Testing a * Point Against Many Polygons> * 9. Explanation of /"for (i = 0, j = nvert-1; i < nvert; j = i++)"/ * <#Explanation> * 10. Fortran Code for the Point in Polygon Test <#Fortran Code for the * Point in Polygon Test> * 11. Converting the Code to All Integers <#Converting the Code to All * Integers> * 12. License to Use <#License to Use> * * The C Code * * Here is the code, for reference. Excluding lines with only braces, there * are only /7 lines/ of code. * * int pnpoly(int nvert, float *vertx, float *verty, float ref_pointX, float ref_pointY) * { * int i, j, c = 0; * for (i = 0, j = nvert-1; i < nvert; j = i++) { * if ( ((verty[i]>ref_pointY) != (verty[j]>ref_pointY)) && * (ref_pointX < (vertx[j]-vertx[i]) * (ref_pointY-verty[i]) / (verty[j]-verty[i]) + vertx[i]) ) * c = !c; * } * return c; * } * * Argument Meaning * nvert Number of vertices in the polygon. Whether to repeat the first * vertex at the end is discussed below. * vertx, verty Arrays containing the x- and y-coordinates of the * polygon's vertices. * ref_pointX, ref_pointY X- and y-coordinate of the test point. * * * The Method * * I run a semi-infinite ray horizontally (increasing x, fixed y) out from * the test point, and count how many edges it crosses. At each crossing, * the ray switches between inside and outside. This is called the /Jordan * curve theorem/. * * The case of the ray going thru a vertex is handled correctly via a * careful selection of inequalities. Don't mess with this code unless * you're familiar with the idea of /Simulation of Simplicity/. This * pretends to shift the ray infinitesimally to one side so that it either * clearly intersects, or clearly doesn't touch. Since this is merely a * conceptual, infinitesimal, shift, it never creates an intersection that * didn't exist before, and never destroys an intersection that clearly * existed before. * * The ray is tested against each edge thus: * * 1. Is the point in the half-plane below the extended edge? and * 2. Is the point's X coordinate within the edge's X-range? * * Handling endpoints here is tricky. * * * Originality * * I make no claim to having invented the idea. However in 1970, I did * produce the Fortran code given below on my own, and include it in a * package of cartographic SW publicly-distributed by David Douglas, Dept * of Geography, Simon Fraser U and U of Ottawa. * * Earlier implementations of point-in-polygon testing presumably exist, * tho the code might never have been released. Pointers to prior art, * especially publicly available code, are welcome. One early publication, * which doesn't handle the point on an edge, and has a typo, is this: * * M Shimrat, "Algorithm 112, Position of Point Relative to Polygon", * /Comm. ACM/ 5(8), Aug 1962, p 434. * * A well-written recent summary is this: * * E Haines, /Point in Polygon Strategies/, * http://www.acm.org/pubs/tog/editors/erich/ptinpoly/, 1994. * * * The Inequality Tests are Tricky * * If translating the program to another language, be sure to get the * inequalities in the conditional correct. They were carefully chosen to * make the program work correctly when the point is vertically below a vertex. * * Several people have thought that my program was wrong, when really * /they/ had gotten the inequalities wrong. * * * C Semantics * * My code uses the fact that, in the C language, when executing the code |a&&b|, if |a| is false, then |b| must not be evaluated. If your * compiler doesn't do this, then it's not implementing C, and you will get * a divide-by-zero, i.a., when the test point is vertically in line with a * vertical edge. When translating this code to another language with * different semantics, then you must implement this test explicitly. * * * Point on a (Boundary) Edge * * PNPOLY partitions the plane into points inside the polygon and points * outside the polygon. Points that are on the boundary are classified as * either inside or outside. * * 1. * * Any particular point is always classified consistently the same * way. In the following figure, consider what PNPOLY would say when * the red point, /P/, is tested against the two triangles, /T_L / * and /T_R /. Depending on internal roundoff errors, PNPOLY may say * that /P/ is in /T_L / or in /T_R /. However it will always give * the same answer when /P/ is tested against those triangles. That * is, if PNPOLY finds that /P/ is in /T_L /, then it will find that * /P/ is not /T_R /. If PNPOLY finds that /P/ is not in /T_L /, then * it will find that /P/ is in /T_R /. * * 2. If you want to know when a point is exactly on the boundary, you * need another program. This is only one of many functions that * PNPOLY lacks; it also doesn't predict tomorrow's weather. You are * free to extend PNPOLY's source code. * * 3. The first reason for this is the numerical analysis position that * you should not be testing exact equality unless your input is * exact. Even then, computational roundoff error would often make * the result wrong. * * 4. The second reason is that, if you partition a region of the plane * into polygons, i.e., form a planar graph, then PNPOLY will locate * each point into exactly one polygon. In other words, PNPOLY * considers each polygon to be topologically a semi-open set. This * makes things simpler, i.e., causes fewer special cases, if you use * PNPOLY as part of a larger system. Examples of this include * locating a point in a planar graph, and intersecting two planar * graphs. * * * Explanation of /"for (i = 0, j = nvert-1; i < nvert; j = i++)"/ * * The intention is to execute the loop for each i from 0 to nvert-1. For * each iteration, j is i-1. However that wraps, so if i=0 then j=nvert-1. * Therefore the current edge runs between verts j and i, and the loop is * done once per edge. In detail: * * 1. Start by setting i and j: * i = 0 * j = nvert-1 * 2. If i<nvert is false then exit the loop. * 3. Do the loop body. * 4. Set j=i and then * add 1 to i and then * 5. Go back to step 2. * * * * Converting the Code to All Integers * * If you want to convert the code from floats to integers, consider these * issues. * * 1. On many current processors floats are at least as fast as ints. * 2. If you move the denominator over to the other side of the * inequality, remember that, when the denominator is negative, the * inequality will flip. * 3. If coordinates are large enough, the multiplication will silently * overflow. * * * License to Use * Copyright (c) 1970-2003, Wm. Randolph Franklin * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimers. * 2. Redistributions in binary form must reproduce the above copyright * notice in the documentation and/or other materials provided with * the distribution. * 3. The name of W. Randolph Franklin may not be used to endorse or * promote products derived from this Software without specific prior * written permission. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * * Copyright © 1994-2006, W Randolph Franklin (WRF) * <http://wrfranklin.org/> You may use my material for non-profit research * and education, provided that you credit me, and link back to my home page. * http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html, * 05/20/2008 20:36:42 */ bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList, int istart, int iend, int refx, int refy ) /** Function TestPointInsidePolygon * test if a point is inside or outside a polygon. * @param aPolysList: the list of polygons * @param istart: the starting point of a given polygon in m_FilledPolysList. * @param iend: the ending point of the polygon in m_FilledPolysList. * @param refx, refy: the point coordinate to test * @return true if the point is inside, false for outside */ { double ref_pointX = refx; double ref_pointY = refy; bool inside = false; for( int ii = istart, jj = iend; ii <= iend; jj = ii++ ) { double seg_startX, seg_startY; // starting point for the segment to test seg_startX = aPolysList[ii].x; seg_startY = aPolysList[ii].y; double seg_endX, seg_endY; // ending point for the segment to test seg_endX = aPolysList[jj].x; seg_endY = aPolysList[jj].y; if( ( ( seg_startY > ref_pointY ) != (seg_endY > ref_pointY ) ) && (ref_pointX < (seg_endX - seg_startX) * (ref_pointY - seg_startY) / (seg_endY - seg_startY) + seg_startX) ) inside = not inside; } return inside; } #else /* this algo come from freePCB. */ bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList, int istart, int iend, int refx, int refy ) /** Function TestPointInsidePolygon * test if a point is inside or outside a polygon. * if a point is on a outline segment, it is considered outside the polygon * @param aPolysList: the list of polygons * @param istart: the starting point of a given polygon in m_FilledPolysList. * @param iend: the ending point of the polygon in m_FilledPolysList. * @param refx,refy: the point coordinate to test * @return true if the point is inside, false for outside * this algorithm come from FreePCB. */ { #define OUTSIDE_IF_ON_SIDE 0 // = 1 if we consider point on a side outside the polygon // define line passing through (x,y), with slope = 0 (horizontal line) // get intersection points // count intersection points to right of (x,y), if odd (x,y) is inside polyline int xx, yy; double slope = 0; double a = refy - slope * refx; int ics, ice; bool inside = false; // find all intersection points of line with polyline sides for( ics = istart, ice = iend; ics <= iend; ice = ics++ ) { double x, y, x2, y2; int ok = FindLineSegmentIntersection( a, slope, aPolysList[ics].x, aPolysList[ics].y, aPolysList[ice].x, aPolysList[ice].y, 0, &x, &y, &x2, &y2 ); if( ok ) { xx = (int) x; yy = (int) y; #if OUTSIDE_IF_ON_SIDE if( xx == refx && yy == refy ) return false; // (x,y) is on a side, call it outside else #endif if( xx > refx ) inside = not inside; } if( ok == 2 ) { xx = (int) x2; yy = (int) y2; #if OUTSIDE_IF_ON_SIDE if( xx == refx && yy == refy ) return false; // (x,y) is on a side, call it outside else #endif if( xx > refx ) inside = not inside; } } return inside; } #endif