DRC code cleaning, and added DRC tests for trapezoidal pads. Needs more tests.

This commit is contained in:
jean-pierre charras 2010-09-20 18:23:31 +02:00
commit d536f9d914
13 changed files with 1369 additions and 1141 deletions

View File

@ -96,6 +96,7 @@ set(PCBNEW_SRCS
dist.cpp dist.cpp
dragsegm.cpp dragsegm.cpp
drc.cpp drc.cpp
drc_clearance_test_functions.cpp
drc_marker_functions.cpp drc_marker_functions.cpp
edgemod.cpp edgemod.cpp
edit.cpp edit.cpp

View File

@ -764,17 +764,15 @@ bool D_PAD::IsOnLayer( int aLayer ) const
*/ */
bool D_PAD::HitTest( const wxPoint& ref_pos ) bool D_PAD::HitTest( const wxPoint& ref_pos )
{ {
int deltaX, deltaY;
int dx, dy; int dx, dy;
double dist; double dist;
wxPoint shape_pos = ReturnShapePos(); wxPoint shape_pos = ReturnShapePos();
deltaX = ref_pos.x - shape_pos.x; wxPoint delta = ref_pos - shape_pos;
deltaY = ref_pos.y - shape_pos.y;
/* Quick test: a test point must be inside the circle. */ /* Quick test: a test point must be inside the circle. */
if( ( abs( deltaX ) > m_ShapeMaxRadius ) || ( abs( deltaY ) > m_ShapeMaxRadius ) ) if( ( abs( delta.x ) > m_ShapeMaxRadius ) || ( abs( delta.y ) > m_ShapeMaxRadius ) )
return false; return false;
dx = m_Size.x >> 1; // dx also is the radius for rounded pads dx = m_Size.x >> 1; // dx also is the radius for rounded pads
@ -783,7 +781,7 @@ bool D_PAD::HitTest( const wxPoint& ref_pos )
switch( m_PadShape & 0x7F ) switch( m_PadShape & 0x7F )
{ {
case PAD_CIRCLE: case PAD_CIRCLE:
dist = hypot( deltaX, deltaY ); dist = hypot( delta.x, delta.y );
if( wxRound( dist ) <= dx ) if( wxRound( dist ) <= dx )
return true; return true;
break; break;
@ -792,22 +790,13 @@ bool D_PAD::HitTest( const wxPoint& ref_pos )
{ {
wxPoint poly[4]; wxPoint poly[4];
BuildPadPolygon( poly, wxSize(0,0), 0 ); BuildPadPolygon( poly, wxSize(0,0), 0 );
// Build the same polygon with CPolyPt corners, RotatePoint( &delta, -m_Orient );
// to use TestPointInsidePolygon return TestPointInsidePolygon( poly, 4, delta );
static std::vector <CPolyPt> polysList; // Is static to avoid memory reallocation
polysList.clear();
for(int ii= 0; ii < 4; ii++ )
{
CPolyPt corner(poly[ii].x, poly[ii].y);
polysList.push_back(corner);
}
RotatePoint( &deltaX, &deltaY, -m_Orient );
return TestPointInsidePolygon( polysList, 0, 3, deltaX, deltaY );
} }
default: default:
RotatePoint( &deltaX, &deltaY, -m_Orient ); RotatePoint( &delta, -m_Orient );
if( (abs( deltaX ) <= dx ) && (abs( deltaY ) <= dy) ) if( (abs( delta.x ) <= dx ) && (abs( delta.y ) <= dy) )
return true; return true;
break; break;
} }

View File

@ -148,7 +148,7 @@ public:
* Function GetShape * Function GetShape
* @return the shape of this pad. * @return the shape of this pad.
*/ */
int GetShape() { return m_PadShape & 0xFF; } int GetShape() const { return m_PadShape & 0xFF; }
/** /**
* Function GetPosition * Function GetPosition
@ -239,14 +239,26 @@ public:
void DrawShape( EDA_Rect* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo ); void DrawShape( EDA_Rect* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo );
/** function BuildPadPolygon /** function BuildPadPolygon
* Has meaning only for polygonal pads (trapeziod and rectangular) * Has meaning only for polygonal pads (trapezoid and rectangular)
* Build the Corner list of the polygonal shape, * Build the Corner list of the polygonal shape,
* depending on shape, extra size (clearance ...) and orientation * depending on shape, extra size (clearance ...) and orientation
* @param aCoord[4] = a buffer to fill. * @param aCoord[4] = a buffer to fill.
* @param aInflateValue = wxSize: the clearance or margin value. value > 0: inflate, < 0 deflate * @param aInflateValue = wxSize: the clearance or margin value. value > 0: inflate, < 0 deflate
* @param aRotation = full rotation of the polygon * @param aRotation = full rotation of the polygon
*/ */
void BuildPadPolygon( wxPoint aCoord[4], wxSize aInflateValue, int aRotation ); void BuildPadPolygon( wxPoint aCoord[4], wxSize aInflateValue, int aRotation ) const;
/** function BuildSegmentFromOvalShape
* Has meaning only for OVAL (and ROUND) pads
* Build an equivalent segment having the same shape as the OVAL shape,
* Useful in draw function and in DRC and HitTest functions,
* because segments are already well handled by track tests
* @param aSegStart = the starting point of the equivalent segment, relative to the shape position.
* @param aSegEnd = the ending point of the equivalent segment, relative to the shape position
* @param aRotation = full rotation of the segment
* @return the width of the segment
*/
int BuildSegmentFromOvalShape(wxPoint& aSegStart, wxPoint& aSegEnd, int aRotation) const;
// others // others
void SetPadName( const wxString& name ); // Change pad name void SetPadName( const wxString& name ); // Change pad name

View File

@ -357,9 +357,9 @@ void D_PAD::Draw( WinEDA_DrawPanel* aPanel, wxDC* aDC, int aDraw_mode,
void D_PAD::DrawShape( EDA_Rect* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo ) void D_PAD::DrawShape( EDA_Rect* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
{ {
wxPoint coord[4]; wxPoint coord[4];
int rotdx, int delta_cx, delta_cy;
delta_cx, delta_cy;
int angle = m_Orient; int angle = m_Orient;
int seg_width;
GRSetDrawMode( aDC, aDrawInfo.m_DrawMode ); GRSetDrawMode( aDC, aDrawInfo.m_DrawMode );
@ -392,44 +392,30 @@ void D_PAD::DrawShape( EDA_Rect* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
break; break;
case PAD_OVAL: case PAD_OVAL:
if( halfsize.x > halfsize.y ) /* horizontal */ {
{ wxPoint segStart, segEnd;
delta_cx = halfsize.x - halfsize.y; seg_width = BuildSegmentFromOvalShape(segStart, segEnd, angle);
delta_cy = 0; segStart += shape_pos;
rotdx = m_Size.y + ( aDrawInfo.m_Mask_margin.y * 2 ); segEnd += shape_pos;
}
else /* vertical */
{
delta_cx = 0;
delta_cy = halfsize.y - halfsize.x;
rotdx = m_Size.x + ( aDrawInfo.m_Mask_margin.x * 2 );
}
RotatePoint( &delta_cx, &delta_cy, angle );
if( aDrawInfo.m_ShowPadFilled ) if( aDrawInfo.m_ShowPadFilled )
{ {
GRFillCSegm( aClipBox, aDC, GRFillCSegm( aClipBox, aDC, segStart.x, segStart.y, segEnd.x, segEnd.y,
shape_pos.x + delta_cx, shape_pos.y + delta_cy, seg_width, aDrawInfo.m_Color );
shape_pos.x - delta_cx, shape_pos.y - delta_cy,
rotdx, aDrawInfo.m_Color );
} }
else else
{ {
GRCSegm( aClipBox, aDC, GRCSegm( aClipBox, aDC, segStart.x, segStart.y, segEnd.x, segEnd.y,
shape_pos.x + delta_cx, shape_pos.y + delta_cy, seg_width, m_PadSketchModePenSize, aDrawInfo.m_Color );
shape_pos.x - delta_cx, shape_pos.y - delta_cy,
rotdx, m_PadSketchModePenSize, aDrawInfo.m_Color );
} }
/* Draw the isolation line. */ /* Draw the isolation line. */
if( aDrawInfo.m_PadClearance ) if( aDrawInfo.m_PadClearance )
{ {
rotdx = rotdx + 2 * aDrawInfo.m_PadClearance; seg_width += 2 * aDrawInfo.m_PadClearance;
GRCSegm( aClipBox, aDC, segStart.x, segStart.y, segEnd.x, segEnd.y,
GRCSegm( aClipBox, aDC, shape_pos.x + delta_cx, shape_pos.y + delta_cy, seg_width, aDrawInfo.m_Color );
shape_pos.x - delta_cx, shape_pos.y - delta_cy,
rotdx, aDrawInfo.m_Color );
} }
}
break; break;
case PAD_RECT: case PAD_RECT:
@ -486,9 +472,6 @@ void D_PAD::DrawShape( EDA_Rect* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
#else #else
if( aDrawInfo.m_Scale * hole > 1 ) /* draw hole if its size is enough */ if( aDrawInfo.m_Scale * hole > 1 ) /* draw hole if its size is enough */
#endif #endif
GRFilledCircle( aClipBox, aDC, holepos.x, holepos.y, hole, 0, GRFilledCircle( aClipBox, aDC, holepos.x, holepos.y, hole, 0,
aDrawInfo.m_Color, aDrawInfo.m_HoleColor ); aDrawInfo.m_Color, aDrawInfo.m_HoleColor );
break; break;
@ -501,18 +484,18 @@ void D_PAD::DrawShape( EDA_Rect* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
{ {
delta_cx = halfsize.x - halfsize.y; delta_cx = halfsize.x - halfsize.y;
delta_cy = 0; delta_cy = 0;
rotdx = m_Drill.y; seg_width = m_Drill.y;
} }
else /* vertical */ else /* vertical */
{ {
delta_cx = 0; delta_cx = 0;
delta_cy = halfsize.y - halfsize.x; delta_cy = halfsize.y - halfsize.x;
rotdx = m_Drill.x; seg_width = m_Drill.x;
} }
RotatePoint( &delta_cx, &delta_cy, angle ); RotatePoint( &delta_cx, &delta_cy, angle );
GRFillCSegm( aClipBox, aDC, holepos.x + delta_cx, holepos.y + delta_cy, GRFillCSegm( aClipBox, aDC, holepos.x + delta_cx, holepos.y + delta_cy,
holepos.x - delta_cx, holepos.y - delta_cy, rotdx, holepos.x - delta_cx, holepos.y - delta_cy, seg_width,
aDrawInfo.m_HoleColor ); aDrawInfo.m_HoleColor );
break; break;
@ -637,6 +620,42 @@ void D_PAD::DrawShape( EDA_Rect* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
} }
} }
/** function BuildSegmentFromOvalShape
* Has meaning only for OVAL (and ROUND) pads.
* Build an equivalent segment having the same shape as the OVAL shape,
* aSegStart and aSegEnd are the ending points of the equivalent segment of the shape
* aRotation is the asked rotation of the segment (usually m_Orient)
*/
int D_PAD::BuildSegmentFromOvalShape(wxPoint& aSegStart, wxPoint& aSegEnd, int aRotation) const
{
int width;
if( m_Size.y < m_Size.x ) // Build an horizontal equiv segment
{
int delta = ( m_Size.x - m_Size.y ) / 2;
aSegStart.x = -delta;
aSegStart.y = 0;
aSegEnd.x = delta;
aSegEnd.y = 0;
width = m_Size.y;
}
else // Vertical oval: build a vertical equiv segment
{
int delta = ( m_Size.y -m_Size.x ) / 2;
aSegStart.x = 0;
aSegStart.y = -delta;
aSegEnd.x = 0;
aSegEnd.y = delta;
width = m_Size.x;
}
if( aRotation )
{
RotatePoint( &aSegStart, aRotation);
RotatePoint( &aSegEnd, aRotation);
}
return width;
}
/** function BuildPadPolygon /** function BuildPadPolygon
* Has meaning only for polygonal pads (trapeziod and rectangular) * Has meaning only for polygonal pads (trapeziod and rectangular)
@ -646,7 +665,7 @@ void D_PAD::DrawShape( EDA_Rect* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
* @param aInflateValue = wxSize: the clearance or margin value. value > 0: inflate, < 0 deflate * @param aInflateValue = wxSize: the clearance or margin value. value > 0: inflate, < 0 deflate
* @param aRotation = full rotation of the polygon, usually m_Orient * @param aRotation = full rotation of the polygon, usually m_Orient
*/ */
void D_PAD::BuildPadPolygon( wxPoint aCoord[4], wxSize aInflateValue, int aRotation ) void D_PAD::BuildPadPolygon( wxPoint aCoord[4], wxSize aInflateValue, int aRotation ) const
{ {
if( (GetShape() != PAD_RECT) && (GetShape() != PAD_TRAPEZOID) ) if( (GetShape() != PAD_RECT) && (GetShape() != PAD_TRAPEZOID) )
return; return;

View File

@ -44,21 +44,17 @@ bool DIALOG_DRC_CONTROL::Show( bool show )
{ {
bool ret; bool ret;
D(printf("%s %d\n", __func__, show );)
if( show ) if( show )
{ {
ret = DIALOG_DRC_CONTROL_BASE::Show( show ); ret = DIALOG_DRC_CONTROL_BASE::Show( show );
if( s_LastPos.x != -1 ) if( s_LastPos.x != -1 )
{ {
D(printf("setting window pos to (%d,%d)\n", s_LastPos.x, s_LastPos.y );)
//SetPosition( s_LastPos );
SetSize( s_LastPos.x, s_LastPos.y, s_LastSize.x, s_LastSize.y, 0 ); SetSize( s_LastPos.x, s_LastPos.y, s_LastSize.x, s_LastSize.y, 0 );
} }
else else
{ {
D(printf("not setting window pos (%d,%d)\n", s_LastPos.x, s_LastPos.y );) // Do nothing: last position not yet saved.
} }
} }
else else
@ -66,9 +62,6 @@ bool DIALOG_DRC_CONTROL::Show( bool show )
// Save the dialog's position before hiding // Save the dialog's position before hiding
s_LastPos = GetPosition(); s_LastPos = GetPosition();
s_LastSize = GetSize(); s_LastSize = GetSize();
D(printf("saving window pos as (%d,%d)\n", s_LastPos.x, s_LastPos.y );)
ret = DIALOG_DRC_CONTROL_BASE::Show( show ); ret = DIALOG_DRC_CONTROL_BASE::Show( show );
} }

View File

@ -195,8 +195,7 @@ void DIALOG_PAD_PROPERTIES::initValues()
{ {
SetFocus(); // Required under wxGTK if we want to demiss the dialog with the ESC key SetFocus(); // Required under wxGTK if we want to demiss the dialog with the ESC key
int tmp; int internalUnits = m_Parent->m_InternalUnits;
int internalUnits = m_Parent->m_InternalUnits;
wxString msg; wxString msg;
m_isFlipped = false; m_isFlipped = false;
if( m_CurrentPad ) if( m_CurrentPad )
@ -298,7 +297,7 @@ void DIALOG_PAD_PROPERTIES::initValues()
SetPadLayersList( m_dummyPad->m_Masque_Layer ); SetPadLayersList( m_dummyPad->m_Masque_Layer );
msg.Clear(); msg.Clear();
msg << tmp; msg << m_dummyPad->m_Orient;
m_PadOrientCtrl->SetValue( msg ); m_PadOrientCtrl->SetValue( msg );
// Pad Orient // Pad Orient
@ -350,11 +349,10 @@ void DIALOG_PAD_PROPERTIES::initValues()
m_PadOrientCtrl->SetValue( msg ); m_PadOrientCtrl->SetValue( msg );
// Selection du type // Selection du type
tmp = m_dummyPad->m_Attribut;
m_PadType->SetSelection( 0 ); m_PadType->SetSelection( 0 );
for( int ii = 0; ii < NBTYPES; ii++ ) for( int ii = 0; ii < NBTYPES; ii++ )
{ {
if( CodeType[ii] == tmp ) if( CodeType[ii] == m_dummyPad->m_Attribut )
{ {
m_PadType->SetSelection( ii ); m_PadType->SetSelection( ii );
break; break;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -173,10 +173,10 @@ private:
/* variables used in checkLine to test DRC segm to segm: /* variables used in checkLine to test DRC segm to segm:
* define the area relative to the ref segment that does not contains anu other segment * define the area relative to the ref segment that does not contains anu other segment
*/ */
int m_xcliplo; int m_xcliplo;
int m_ycliplo; int m_ycliplo;
int m_xcliphi; int m_xcliphi;
int m_ycliphi; int m_ycliphi;
WinEDA_PcbFrame* m_mainWindow; WinEDA_PcbFrame* m_mainWindow;
BOARD* m_pcb; BOARD* m_pcb;
@ -329,30 +329,27 @@ private:
/** /**
* Function checkMarginToCircle * Helper function checkMarginToCircle
* @todo this translation is no good, fix this: * Check the distance from a point to
* calculates the distance from a circle (via or round end of track) to the * a segment. the segment is expected starting at 0,0, and on the X axis
* segment of reference on the right hand side. * (used to test DRC between a segment and a round pad, via or round end of a track
* * @param aCentre The coordinate of the circle's center
* @param cx The x coordinate of the circle's center * @param aRadius A "keep out" radius centered over the circle
* @param cy The y coordinate of the circle's center * @param aLength The length of the segment (i.e. coordinate of end, becuase it is on the X axis)
* @param radius A "keep out" radius centered over the circle
* @param length The length of the segment (i.e. coordinate of end)
* @return bool - true if distance >= radius, else * @return bool - true if distance >= radius, else
* false when distance < radius * false when distance < aRadius
*/ */
static bool checkMarginToCircle( int cx, int cy, int radius, int length ); static bool checkMarginToCircle( wxPoint aCentre, int aRadius, int aLength );
/** /**
* Function checkLine * Function checkLine
* tests to see if one track is in contact with another track. * (helper function used in drc calculations to see if one track is in contact with another track).
* * Test if a line intersects a bounding box (a rectangle)
* Cette routine controle si la ligne (x1,y1 x2,y2) a une partie s'inscrivant * The rectangle is defined by m_xcliplo, m_ycliplo and m_xcliphi, m_ycliphi
* dans le cadre (xcliplo,ycliplo xcliphi,ycliphi) (variables globales, * return true if the line from aSegStart to aSegEnd is outside the bounding box
* locales a ce fichier)
*/ */
bool checkLine( int x1, int y1, int x2, int y2 ); bool checkLine( wxPoint aSegStart, wxPoint aSegEnd );
//-----</single tests>--------------------------------------------- //-----</single tests>---------------------------------------------

View File

@ -1,4 +1,4 @@
// math for graphics utility routines, from FreePCB // math for graphics utility routines and RC, from FreePCB
#include <vector> #include <vector>
@ -13,13 +13,14 @@
using namespace std; using namespace std;
// test for hit on line segment /** function TestLineHit
// i.e. cursor within a given distance from segment * test for hit on line segment i.e. a point within a given distance from segment
// enter with: x,y = cursor coords * @param x, y = cursor coords
// (xi,yi) and (xf,yf) are the end-points of the line segment * @param xi,yi and xf,yf = the end-points of the line segment
// dist = maximum distance for hit * @param dist = maximum distance for hit
// * return true if dist < distance between the point and the segment
int TestLineHit( int xi, int yi, int xf, int yf, int x, int y, double dist ) */
bool TestLineHit( int xi, int yi, int xf, int yf, int x, int y, double dist )
{ {
double dd; double dd;
@ -29,14 +30,14 @@ int TestLineHit( int xi, int yi, int xf, int yf, int x, int y, double dist )
// vertical segment // vertical segment
dd = fabs( (double)(x-xi) ); dd = fabs( (double)(x-xi) );
if( dd<dist && ( (yf>yi && y<yf && y>yi) || (yf<yi && y>yf && y<yi) ) ) if( dd<dist && ( (yf>yi && y<yf && y>yi) || (yf<yi && y>yf && y<yi) ) )
return 1; return true;
} }
else if( yf==yi ) else if( yf==yi )
{ {
// horizontal segment // horizontal segment
dd = fabs( (double)(y-yi) ); dd = fabs( (double)(y-yi) );
if( dd<dist && ( (xf>xi && x<xf && x>xi) || (xf<xi && x>xf && x<xi) ) ) if( dd<dist && ( (xf>xi && x<xf && x>xi) || (xf<xi && x>xf && x<xi) ) )
return 1; return true;
} }
else else
{ {
@ -62,10 +63,10 @@ int TestLineHit( int xi, int yi, int xf, int yf, int x, int y, double dist )
{ {
// line segment more horizontal than vertical // line segment more horizontal than vertical
if( dd<dist && ( (xf>xi && xp<xf && xp>xi) || (xf<xi && xp>xf && xp<xi) ) ) if( dd<dist && ( (xf>xi && xp<xf && xp>xi) || (xf<xi && xp>xf && xp<xi) ) )
return 1; return true;
} }
} }
return 0; // no hit return false; // no hit
} }
@ -482,12 +483,12 @@ int FindLineSegmentIntersection( double a, double b, int xi, int yi, int xf, int
return 1; return 1;
} }
// Test for intersection of line segments /** function TestForIntersectionOfStraightLineSegments
// If lines are parallel, returns false * Test for intersection of line segments
// If true, returns intersection coords in x, y * If lines are parallel, returns false
// if false, returns min. distance in dist (may be 0.0 if parallel) * If true, returns also intersection coords in x, y
// and coords on nearest point in one of the segments in (x,y) * if false, returns min. distance in dist (may be 0.0 if parallel)
// */
bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y1f, bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y1f,
int x2i, int y2i, int x2f, int y2f, int x2i, int y2i, int x2f, int y2f,
int * x, int * y, double * d ) int * x, int * y, double * d )

View File

@ -13,8 +13,6 @@ typedef struct PointTag
typedef struct EllipseTag typedef struct EllipseTag
{ {
PointT Center; /* ellipse center */ PointT Center; /* ellipse center */
// double MaxRad,MinRad; /* major and minor axis */
// double Phi; /* major axis rotation */
double xrad, yrad; // radii on x and y double xrad, yrad; // radii on x and y
double theta1, theta2; // start and end angle for arc double theta1, theta2; // start and end angle for arc
} EllipseKH; } EllipseKH;
@ -22,7 +20,16 @@ typedef struct EllipseTag
// math stuff for graphics // math stuff for graphics
bool Quadratic( double a, double b, double c, double *x1, double *x2 ); bool Quadratic( double a, double b, double c, double *x1, double *x2 );
int TestLineHit( int xi, int yi, int xf, int yf, int x, int y, double dist );
/** function TestLineHit
* test for hit on line segment i.e. a point within a given distance from segment
* @param xi,yi and xf,yf = the end-points of the line segment
* @param dist = maximum distance for hit
* @param x, y = point to test coords
* @return true if hit (i.e dist < distance between the point and the segment, false if not.
*/
bool TestLineHit( int xi, int yi, int xf, int yf, int x, int y, double dist );
int FindLineSegmentIntersection( double a, double b, int xi, int yi, int xf, int yf, int style, int FindLineSegmentIntersection( double a, double b, int xi, int yi, int xf, int yf, int style,
double * x1, double * y1, double * x2, double * y2, double * dist=NULL ); double * x1, double * y1, double * x2, double * y2, double * dist=NULL );
int FindSegmentIntersections( int xi, int yi, int xf, int yf, int style, int FindSegmentIntersections( int xi, int yi, int xf, int yf, int style,
@ -30,9 +37,23 @@ int FindSegmentIntersections( int xi, int yi, int xf, int yf, int style,
double x[]=NULL, double y[]=NULL ); double x[]=NULL, double y[]=NULL );
bool FindLineEllipseIntersections( double a, double b, double c, double d, double *x1, double *x2 ); bool FindLineEllipseIntersections( double a, double b, double c, double d, double *x1, double *x2 );
bool FindVerticalLineEllipseIntersections( double a, double b, double x, double *y1, double *y2 ); bool FindVerticalLineEllipseIntersections( double a, double b, double x, double *y1, double *y2 );
/** function TestForIntersectionOfStraightLineSegments
* Test for intersection of line segments
* If lines are parallel, returns false
* If true, returns also intersection coords in x, y
* if false, returns min. distance in dist (may be 0.0 if parallel)
* and coords on nearest point in one of the segments in (x,y)
* @param x1i, y1i, x1f, y1f = integer coordinates of the first segment
* @param x2i, y2i, x2f, y2f = integer coordinates of the other segment
* @param x, y = pointers on 2 integer to store the intersection coordinates (can be NULL)
* @param dist = pointeur on a double to store the dist.
* @return true if intersect.
*/
bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y1f, bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y1f,
int x2i, int y2i, int x2f, int y2f, int x2i, int y2i, int x2f, int y2f,
int * x=NULL, int * y=NULL, double * dist=NULL ); int * x=NULL, int * y=NULL, double * dist=NULL );
int GetClearanceBetweenSegments( int x1i, int y1i, int x1f, int y1f, int style1, int w1, int GetClearanceBetweenSegments( int x1i, int y1i, int x1f, int y1f, int style1, int w1,
int x2i, int y2i, int x2f, int y2f, int style2, int w2, int x2i, int y2i, int x2f, int y2f, int style2, int w2,
int max_cl, int * x, int * y ); int max_cl, int * x, int * y );

View File

@ -1,21 +1,18 @@
///////////////////////////////////////////////////////////////////////////// /**
* @file polygon_test_point_inside.cpp
// Name: polygon_test_point_inside.cpp */
/////////////////////////////////////////////////////////////////////////////
#include <math.h> #include <math.h>
#include <vector> #include <vector>
#include "PolyLine.h" #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: /* 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) * It run a semi-infinite line horizontally (increasing x, fixed y)
* out from the test point, and count how many edges it crosses. * out from the test point, and count how many edges it crosses.
* At each crossing, the ray switches between inside and outside. * At each crossing, the ray switches between inside and outside.
* If odd count, the test point is inside the polygon * If odd count, the test point is inside the polygon
* This is called the Jordan curve theorem, or sometimes referred to as the "even-odd" test. * This is called the Jordan curve theorem, or sometimes referred to as the "even-odd" test.
* Take care to starting and ending points of segments outlines, when the horizontal line crosses a segment outline * Take care to starting and ending points of segments outlines, when the horizontal line crosses a segment outline
* exactly on an ending point: * exactly on an ending point:
* Because the starting point of a segment is also the ending point of the previous, only one must be used. * Because the starting point of a segment is also the ending point of the previous, only one must be used.
* And we do no use twice the same segment, so we do NOT use both starting and ending points of these 2 segments. * And we do no use twice the same segment, so we do NOT use both starting and ending points of these 2 segments.
@ -30,16 +27,19 @@ using namespace std;
#define INSIDE true #define INSIDE true
bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList, bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList,
int istart, int iend, int refx, int refy ) int aIdxstart,
int aIdxend,
int aRefx,
int aRefy)
/** Function TestPointInsidePolygon /** Function TestPointInsidePolygon
* test if a point is inside or outside a polygon. * test if a point is inside or outside a polygon.
* the polygon must have only lines (not arcs) for outlines. * the polygon must have only lines (not arcs) for outlines.
* Use TestPointInside or TestPointInsideContour for more complex polygons * Use TestPointInside or TestPointInsideContour for more complex polygons
* @param aPolysList: the list of polygons * @param aPolysList: the list of polygons
* @param istart: the starting point of a given polygon in m_FilledPolysList. * @param aIdxstart: the starting point of a given polygon in m_FilledPolysList.
* @param iend: the ending point of the polygon in m_FilledPolysList. * @param aIdxend: the ending point of the polygon in m_FilledPolysList.
* @param refx,refy: the point coordinate to test * @param aRefx, aRefy: the point coordinate to test
* @return true if the point is inside, false for outside * @return true if the point is inside, false for outside
*/ */
{ {
@ -48,7 +48,7 @@ bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList,
int count = 0; int count = 0;
// find all intersection points of line with polyline sides // find all intersection points of line with polyline sides
for( ics = istart, ice = iend; ics <= iend; ice = ics++ ) for( ics = aIdxstart, ice = aIdxend; ics <= aIdxend; ice = ics++ )
{ {
int seg_startX = aPolysList[ics].x; int seg_startX = aPolysList[ics].x;
int seg_startY = aPolysList[ics].y; int seg_startY = aPolysList[ics].y;
@ -56,14 +56,14 @@ bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList,
int seg_endY = aPolysList[ice].y; int seg_endY = aPolysList[ice].y;
/* Trivial cases: skip if ref above or below the segment to test */ /* Trivial cases: skip if ref above or below the segment to test */
if( ( seg_startY > refy ) && (seg_endY > refy ) ) if( ( seg_startY > aRefy ) && (seg_endY > aRefy ) )
continue; continue;
// segment below ref point, or one of its ends has the same Y pos as the ref point: skip // segment below ref point, or one of its ends has the same Y pos as the ref point: skip
// So we eliminate one end point of 2 consecutive segments. // So we eliminate one end point of 2 consecutive segments.
// Note: also we skip horizontal segments if ref point is on this horizontal line // Note: also we skip horizontal segments if ref point is on this horizontal line
// So reference points on horizontal segments outlines always are seen as outside the polygon // So reference points on horizontal segments outlines always are seen as outside the polygon
if( ( seg_startY <= refy ) && (seg_endY <= refy ) ) if( ( seg_startY <= aRefy ) && (seg_endY <= aRefy ) )
continue; continue;
/* refy is between seg_startY and seg_endY. /* refy is between seg_startY and seg_endY.
@ -76,8 +76,63 @@ bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList,
// this is more easier if we move the X,Y axis origin to the segment start point: // this is more easier if we move the X,Y axis origin to the segment start point:
seg_endX -= seg_startX; seg_endX -= seg_startX;
seg_endY -= seg_startY; seg_endY -= seg_startY;
double newrefx = (double) (refx - seg_startX); double newrefx = (double) (aRefx - seg_startX);
double newrefy = (double) (refy - seg_startY); double newrefy = (double) (aRefy - seg_startY);
// Now calculate the x intersection coordinate of the line from (0,0) to (seg_endX,seg_endY)
// with the horizontal line at the new refy position
// the line slope = seg_endY/seg_endX;
// and the x pos relative to the new origin is intersec_x = refy/slope
// Note: because horizontal segments are skipped, 1/slope exists (seg_end_y never == O)
double intersec_x = newrefy * seg_endX / seg_endY;
if( newrefx < intersec_x ) // Intersection found with the semi-infinite line from refx to infinite
count++;
}
return count & 1 ? INSIDE : OUTSIDE;
}
/* Function TestPointInsidePolygon (overlaid)
* same as previous, but use wxPoint and aCount corners
*/
bool TestPointInsidePolygon( wxPoint *aPolysList, int aCount,wxPoint aRefPoint )
{
// count intersection points to right of (refx,refy). If odd number, point (refx,refy) is inside polyline
int ics, ice;
int count = 0;
// find all intersection points of line with polyline sides
for( ics = 0, ice = aCount-1; ics < aCount; ice = ics++ )
{
int seg_startX = aPolysList[ics].x;
int seg_startY = aPolysList[ics].y;
int seg_endX = aPolysList[ice].x;
int seg_endY = aPolysList[ice].y;
/* Trivial cases: skip if ref above or below the segment to test */
if( ( seg_startY > aRefPoint.y ) && (seg_endY > aRefPoint.y ) )
continue;
// segment below ref point, or one of its ends has the same Y pos as the ref point: skip
// So we eliminate one end point of 2 consecutive segments.
// Note: also we skip horizontal segments if ref point is on this horizontal line
// So reference points on horizontal segments outlines always are seen as outside the polygon
if( ( seg_startY <= aRefPoint.y ) && (seg_endY <= aRefPoint.y ) )
continue;
/* refy is between seg_startY and seg_endY.
* note: here: horizontal segments (seg_startY == seg_endY) are skipped,
* either by the first test or by the second test
* see if an horizontal semi infinite line from refx is intersecting the segment
*/
// calculate the x position of the intersection of this segment and the semi infinite line
// this is more easier if we move the X,Y axis origin to the segment start point:
seg_endX -= seg_startX;
seg_endY -= seg_startY;
double newrefx = (double) (aRefPoint.x - seg_startX);
double newrefy = (double) (aRefPoint.y - seg_startY);
// Now calculate the x intersection coordinate of the line from (0,0) to (seg_endX,seg_endY) // Now calculate the x intersection coordinate of the line from (0,0) to (seg_endX,seg_endY)
// with the horizontal line at the new refy position // with the horizontal line at the new refy position

View File

@ -2,18 +2,34 @@
// Name: polygon_test_point_inside.h // Name: polygon_test_point_inside.h
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
using namespace std; #ifndef __WXWINDOWS__
// define here wxPoint if we want to compile outside wxWidgets
class wxPoint
{
public:
int x, y;
};
#endif
/** Function TestPointInsidePolygon /** Function TestPointInsidePolygon
* test if a point is inside or outside a polygon. * test if a point is inside or outside a polygon.
* @param aPolysList: the list of polygons * @param aPolysList: the list of polygons
* @param istart: the starting point of a given polygon in m_FilledPolysList. * @param aIdxstart: the starting point of a given polygon in m_FilledPolysList.
* @param iend: the ending point of the polygon in m_FilledPolysList. * @param aIdxend: the ending point of the polygon in m_FilledPolysList.
* @param refx, refy: the point coordinate to test * @param aRefx, aRefy: the point coordinate to test
* @return true if the point is inside, false for outside * @return true if the point is inside, false for outside
*/ */
bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList, bool TestPointInsidePolygon( std::vector <CPolyPt> aPolysList,
int istart, int aIdxstart,
int iend, int aIdxend,
int refx, int aRefx,
int refy); int aRefy);
/** Function TestPointInsidePolygon (overlaid)
* same as previous, but mainly use wxPoint
* @param aPolysList: the list of polygons
* @param aCount: corners count in aPolysList.
* @param aRefPoint: the point coordinate to test
* @return true if the point is inside, false for outside
*/
bool TestPointInsidePolygon( wxPoint* aPolysList,
int aCount,
wxPoint aRefPoint );