updating polygon lib code. A bug removed.
This commit is contained in:
parent
7c5feb61e7
commit
b7db0ef850
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,10 +30,11 @@ CPolyLine::CPolyLine()
|
||||||
CPolyLine::~CPolyLine()
|
CPolyLine::~CPolyLine()
|
||||||
{
|
{
|
||||||
Undraw();
|
Undraw();
|
||||||
if ( m_Kbool_Poly_Engine )
|
if( m_Kbool_Poly_Engine )
|
||||||
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
|
||||||
|
@ -83,8 +84,8 @@ int CPolyLine::NormalizeWithKbool( std::vector<CPolyLine*> * aExtraPolyList, boo
|
||||||
hole_array.push_back( hole );
|
hole_array.push_back( hole );
|
||||||
while( m_Kbool_Poly_Engine->PolygonHasMorePoints() ) // store hole
|
while( m_Kbool_Poly_Engine->PolygonHasMorePoints() ) // store hole
|
||||||
{
|
{
|
||||||
int x = (int)m_Kbool_Poly_Engine->GetPolygonXPoint();
|
int x = (int) m_Kbool_Poly_Engine->GetPolygonXPoint();
|
||||||
int y = (int)m_Kbool_Poly_Engine->GetPolygonYPoint();
|
int y = (int) m_Kbool_Poly_Engine->GetPolygonYPoint();
|
||||||
hole->push_back( x );
|
hole->push_back( x );
|
||||||
hole->push_back( y );
|
hole->push_back( y );
|
||||||
}
|
}
|
||||||
|
@ -99,8 +100,8 @@ int CPolyLine::NormalizeWithKbool( std::vector<CPolyLine*> * aExtraPolyList, boo
|
||||||
bool first = true;
|
bool first = true;
|
||||||
while( m_Kbool_Poly_Engine->PolygonHasMorePoints() )
|
while( m_Kbool_Poly_Engine->PolygonHasMorePoints() )
|
||||||
{ // foreach point in the polygon
|
{ // foreach point in the polygon
|
||||||
int x = (int)m_Kbool_Poly_Engine->GetPolygonXPoint();
|
int x = (int) m_Kbool_Poly_Engine->GetPolygonXPoint();
|
||||||
int y = (int)m_Kbool_Poly_Engine->GetPolygonYPoint();
|
int y = (int) m_Kbool_Poly_Engine->GetPolygonYPoint();
|
||||||
if( first )
|
if( first )
|
||||||
{
|
{
|
||||||
first = false;
|
first = false;
|
||||||
|
@ -116,13 +117,13 @@ int CPolyLine::NormalizeWithKbool( std::vector<CPolyLine*> * aExtraPolyList, boo
|
||||||
}
|
}
|
||||||
else if( aExtraPolyList ) // a new outside contour is found: create a new CPolyLine
|
else if( aExtraPolyList ) // a new outside contour is found: create a new CPolyLine
|
||||||
{
|
{
|
||||||
polyline = new CPolyLine; // create new poly
|
polyline = new CPolyLine; // create new poly
|
||||||
aExtraPolyList->push_back( polyline ); // put it in array
|
aExtraPolyList->push_back( polyline ); // put it in array
|
||||||
bool first = true;
|
bool first = true;
|
||||||
while( m_Kbool_Poly_Engine->PolygonHasMorePoints() ) // read next external contour
|
while( m_Kbool_Poly_Engine->PolygonHasMorePoints() ) // read next external contour
|
||||||
{
|
{
|
||||||
int x = (int)m_Kbool_Poly_Engine->GetPolygonXPoint();
|
int x = (int) m_Kbool_Poly_Engine->GetPolygonXPoint();
|
||||||
int y = (int)m_Kbool_Poly_Engine->GetPolygonYPoint();
|
int y = (int) m_Kbool_Poly_Engine->GetPolygonYPoint();
|
||||||
if( first )
|
if( first )
|
||||||
{
|
{
|
||||||
first = false;
|
first = false;
|
||||||
|
@ -227,8 +228,8 @@ int CPolyLine::AddPolygonsToBoolEng( Bool_Engine* aBooleng,
|
||||||
{
|
{
|
||||||
while( m_Kbool_Poly_Engine->PolygonHasMorePoints() )
|
while( m_Kbool_Poly_Engine->PolygonHasMorePoints() )
|
||||||
{
|
{
|
||||||
int x = (int)m_Kbool_Poly_Engine->GetPolygonXPoint();
|
int x = (int) m_Kbool_Poly_Engine->GetPolygonXPoint();
|
||||||
int y = (int)m_Kbool_Poly_Engine->GetPolygonYPoint();
|
int y = (int) m_Kbool_Poly_Engine->GetPolygonYPoint();
|
||||||
aBooleng->AddPoint( x, y );
|
aBooleng->AddPoint( x, y );
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
@ -259,7 +260,7 @@ int CPolyLine::AddPolygonsToBoolEng( Bool_Engine* aBooleng,
|
||||||
* @return error: 0 if Ok, 1 if error
|
* @return error: 0 if Ok, 1 if error
|
||||||
*/
|
*/
|
||||||
int CPolyLine::MakeKboolPoly( int aStart_contour, int aEnd_contour, std::vector<CArc> * arc_array,
|
int CPolyLine::MakeKboolPoly( int aStart_contour, int aEnd_contour, std::vector<CArc> * arc_array,
|
||||||
bool aConvertHoles )
|
bool aConvertHoles )
|
||||||
{
|
{
|
||||||
if( m_Kbool_Poly_Engine )
|
if( m_Kbool_Poly_Engine )
|
||||||
{
|
{
|
||||||
|
@ -300,8 +301,8 @@ int CPolyLine::MakeKboolPoly( int aStart_contour, int aEnd_contour, std::vector<
|
||||||
{
|
{
|
||||||
while( m_Kbool_Poly_Engine->PolygonHasMorePoints() )
|
while( m_Kbool_Poly_Engine->PolygonHasMorePoints() )
|
||||||
{
|
{
|
||||||
int x = (int)m_Kbool_Poly_Engine->GetPolygonXPoint();
|
int x = (int) m_Kbool_Poly_Engine->GetPolygonXPoint();
|
||||||
int y = (int)m_Kbool_Poly_Engine->GetPolygonYPoint();
|
int y = (int) m_Kbool_Poly_Engine->GetPolygonYPoint();
|
||||||
booleng->AddPoint( x, y );
|
booleng->AddPoint( x, y );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
//
|
//
|
||||||
|
@ -1215,20 +1216,20 @@ void CPolyLine::Hatch()
|
||||||
if( corner[ic].end_contour || ( ic == (int) (corner.size() - 1) ) )
|
if( corner[ic].end_contour || ( ic == (int) (corner.size() - 1) ) )
|
||||||
{
|
{
|
||||||
ok = FindLineSegmentIntersection( a, slope,
|
ok = FindLineSegmentIntersection( a, slope,
|
||||||
corner[ic].x, corner[ic].y,
|
corner[ic].x, corner[ic].y,
|
||||||
corner[i_start_contour].x,
|
corner[i_start_contour].x,
|
||||||
corner[i_start_contour].y,
|
corner[i_start_contour].y,
|
||||||
side_style[ic],
|
side_style[ic],
|
||||||
&x, &y, &x2, &y2 );
|
&x, &y, &x2, &y2 );
|
||||||
i_start_contour = ic + 1;
|
i_start_contour = ic + 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ok = FindLineSegmentIntersection( a, slope,
|
ok = FindLineSegmentIntersection( a, slope,
|
||||||
corner[ic].x, corner[ic].y,
|
corner[ic].x, corner[ic].y,
|
||||||
corner[ic + 1].x, corner[ic + 1].y,
|
corner[ic + 1].x, corner[ic + 1].y,
|
||||||
side_style[ic],
|
side_style[ic],
|
||||||
&x, &y, &x2, &y2 );
|
&x, &y, &x2, &y2 );
|
||||||
}
|
}
|
||||||
if( ok )
|
if( ok )
|
||||||
{
|
{
|
||||||
|
@ -1302,7 +1303,7 @@ void CPolyLine::Hatch()
|
||||||
double y2 = yy[ip + 1] - dx * slope;
|
double y2 = yy[ip + 1] - dx * slope;
|
||||||
m_HatchLines.push_back( CSegment( xx[ip], yy[ip], to_int( x1 ), to_int( y1 ) ) );
|
m_HatchLines.push_back( CSegment( xx[ip], yy[ip], to_int( x1 ), to_int( y1 ) ) );
|
||||||
m_HatchLines.push_back( CSegment( xx[ip + 1], yy[ip + 1], to_int( x2 ),
|
m_HatchLines.push_back( CSegment( xx[ip + 1], yy[ip + 1], to_int( x2 ),
|
||||||
to_int( y2 ) ) );
|
to_int( y2 ) ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 );
|
||||||
|
@ -1345,29 +1345,35 @@ bool CPolyLine::TestPointInside( int x, int y )
|
||||||
int ok;
|
int ok;
|
||||||
if( ic == istart )
|
if( ic == istart )
|
||||||
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,
|
||||||
corner[ic - 1].x, corner[ic - 1].y,
|
corner[ic - 1].x, corner[ic - 1].y,
|
||||||
corner[ic].x, corner[ic].y,
|
corner[ic].x, corner[ic].y,
|
||||||
side_style[ic - 1],
|
side_style[ic - 1],
|
||||||
&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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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++ )
|
||||||
|
@ -1429,29 +1420,35 @@ bool CPolyLine::TestPointInsideContour( int icont, int x, int y )
|
||||||
int ok;
|
int ok;
|
||||||
if( ic == istart )
|
if( ic == istart )
|
||||||
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,
|
||||||
corner[ic - 1].x, corner[ic - 1].y,
|
corner[ic - 1].x, corner[ic - 1].y,
|
||||||
corner[ic].x, corner[ic].y,
|
corner[ic].x, corner[ic].y,
|
||||||
side_style[ic - 1],
|
side_style[ic - 1],
|
||||||
&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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 )
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,355 @@
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 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
|
|
@ -0,0 +1,19 @@
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Name: polygon_test_point_inside.h
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
/** 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
|
||||||
|
*/
|
||||||
|
bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList,
|
||||||
|
int istart,
|
||||||
|
int iend,
|
||||||
|
int refx,
|
||||||
|
int refy);
|
Loading…
Reference in New Issue