Use polygonal hit testing for module selection
This commit is contained in:
parent
c8458bc8ed
commit
01ab8b0584
|
@ -1402,19 +1402,19 @@ bool SHAPE_POLY_SET::CollideEdge( const VECTOR2I& aPoint,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SHAPE_POLY_SET::Contains( const VECTOR2I& aP, int aSubpolyIndex ) const
|
bool SHAPE_POLY_SET::Contains( const VECTOR2I& aP, int aSubpolyIndex, bool aIgnoreHoles ) const
|
||||||
{
|
{
|
||||||
if( m_polys.size() == 0 ) // empty set?
|
if( m_polys.size() == 0 ) // empty set?
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// If there is a polygon specified, check the condition against that polygon
|
// If there is a polygon specified, check the condition against that polygon
|
||||||
if( aSubpolyIndex >= 0 )
|
if( aSubpolyIndex >= 0 )
|
||||||
return containsSingle( aP, aSubpolyIndex );
|
return containsSingle( aP, aSubpolyIndex, aIgnoreHoles );
|
||||||
|
|
||||||
// In any other case, check it against all polygons in the set
|
// In any other case, check it against all polygons in the set
|
||||||
for( int polygonIdx = 0; polygonIdx < OutlineCount(); polygonIdx++ )
|
for( int polygonIdx = 0; polygonIdx < OutlineCount(); polygonIdx++ )
|
||||||
{
|
{
|
||||||
if( containsSingle( aP, polygonIdx ) )
|
if( containsSingle( aP, polygonIdx, aIgnoreHoles ) )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1440,10 +1440,12 @@ void SHAPE_POLY_SET::RemoveVertex( VERTEX_INDEX aIndex )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SHAPE_POLY_SET::containsSingle( const VECTOR2I& aP, int aSubpolyIndex ) const
|
bool SHAPE_POLY_SET::containsSingle( const VECTOR2I& aP, int aSubpolyIndex, bool aIgnoreHoles ) const
|
||||||
{
|
{
|
||||||
// Check that the point is inside the outline
|
// Check that the point is inside the outline
|
||||||
if( pointInPolygon( aP, m_polys[aSubpolyIndex][0] ) )
|
if( pointInPolygon( aP, m_polys[aSubpolyIndex][0] ) )
|
||||||
|
{
|
||||||
|
if( !aIgnoreHoles )
|
||||||
{
|
{
|
||||||
// Check that the point is not in any of the holes
|
// Check that the point is not in any of the holes
|
||||||
for( int holeIdx = 0; holeIdx < HoleCount( aSubpolyIndex ); holeIdx++ )
|
for( int holeIdx = 0; holeIdx < HoleCount( aSubpolyIndex ); holeIdx++ )
|
||||||
|
@ -1455,6 +1457,7 @@ bool SHAPE_POLY_SET::containsSingle( const VECTOR2I& aP, int aSubpolyIndex ) con
|
||||||
if( pointInPolygon( aP, hole ) && !hole.PointOnEdge( aP ) )
|
if( pointInPolygon( aP, hole ) && !hole.PointOnEdge( aP ) )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -933,9 +933,15 @@ class SHAPE_POLY_SET : public SHAPE
|
||||||
bool CollideEdge( const VECTOR2I& aPoint, VERTEX_INDEX& aClosestVertex,
|
bool CollideEdge( const VECTOR2I& aPoint, VERTEX_INDEX& aClosestVertex,
|
||||||
int aClearance = 0 );
|
int aClearance = 0 );
|
||||||
|
|
||||||
///> Returns true if a given subpolygon contains the point aP. If aSubpolyIndex < 0
|
/**
|
||||||
///> (default value), checks all polygons in the set
|
* Returns true if a given subpolygon contains the point aP
|
||||||
bool Contains( const VECTOR2I& aP, int aSubpolyIndex = -1 ) const;
|
*
|
||||||
|
* @param aP is the point to check
|
||||||
|
* @param aSubpolyIndex is the subpolygon to check, or -1 to check all
|
||||||
|
* @param aIgnoreHoles controls whether or not internal holes are considered
|
||||||
|
* @return true if the polygon contains the point
|
||||||
|
*/
|
||||||
|
bool Contains( const VECTOR2I& aP, int aSubpolyIndex = -1, bool aIgnoreHoles = false ) const;
|
||||||
|
|
||||||
///> Returns true if the set is empty (no polygons at all)
|
///> Returns true if the set is empty (no polygons at all)
|
||||||
bool IsEmpty() const
|
bool IsEmpty() const
|
||||||
|
@ -1112,10 +1118,11 @@ class SHAPE_POLY_SET : public SHAPE
|
||||||
* the aSubpolyIndex-th polygon will be tested.
|
* the aSubpolyIndex-th polygon will be tested.
|
||||||
* @param aSubpolyIndex is an integer specifying which polygon in the set has to be
|
* @param aSubpolyIndex is an integer specifying which polygon in the set has to be
|
||||||
* checked.
|
* checked.
|
||||||
|
* @param aIgnoreHoles can be set to true to ignore internal holes in the polygon
|
||||||
* @return bool - true if aP is inside aSubpolyIndex-th polygon; false in any other
|
* @return bool - true if aP is inside aSubpolyIndex-th polygon; false in any other
|
||||||
* case.
|
* case.
|
||||||
*/
|
*/
|
||||||
bool containsSingle( const VECTOR2I& aP, int aSubpolyIndex ) const;
|
bool containsSingle( const VECTOR2I& aP, int aSubpolyIndex, bool aIgnoreHoles = false ) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Operations ChamferPolygon and FilletPolygon are computed under the private chamferFillet
|
* Operations ChamferPolygon and FilletPolygon are computed under the private chamferFillet
|
||||||
|
|
|
@ -138,7 +138,7 @@ void MODULE::TransformPadsShapesWithClearanceToPolygon( PCB_LAYER_ID aLayer,
|
||||||
wxSize margin;
|
wxSize margin;
|
||||||
for( ; pad != NULL; pad = pad->Next() )
|
for( ; pad != NULL; pad = pad->Next() )
|
||||||
{
|
{
|
||||||
if( !pad->IsOnLayer(aLayer) )
|
if( aLayer != UNDEFINED_LAYER && !pad->IsOnLayer(aLayer) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// NPTH pads are not drawn on layers if the shape size and pos is the same
|
// NPTH pads are not drawn on layers if the shape size and pos is the same
|
||||||
|
@ -206,7 +206,8 @@ void MODULE::TransformGraphicShapesWithClearanceToPolygonSet(
|
||||||
int aInflateValue,
|
int aInflateValue,
|
||||||
int aCircleToSegmentsCount,
|
int aCircleToSegmentsCount,
|
||||||
double aCorrectionFactor,
|
double aCorrectionFactor,
|
||||||
int aCircleToSegmentsCountForTexts ) const
|
int aCircleToSegmentsCountForTexts,
|
||||||
|
bool aIncludeText ) const
|
||||||
{
|
{
|
||||||
std::vector<TEXTE_MODULE *> texts; // List of TEXTE_MODULE to convert
|
std::vector<TEXTE_MODULE *> texts; // List of TEXTE_MODULE to convert
|
||||||
EDGE_MODULE* outline;
|
EDGE_MODULE* outline;
|
||||||
|
@ -219,7 +220,8 @@ void MODULE::TransformGraphicShapesWithClearanceToPolygonSet(
|
||||||
{
|
{
|
||||||
TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( item );
|
TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( item );
|
||||||
|
|
||||||
if( text->GetLayer() == aLayer && text->IsVisible() )
|
if( ( aLayer != UNDEFINED_LAYER && text->GetLayer() == aLayer )
|
||||||
|
&& text->IsVisible() )
|
||||||
texts.push_back( text );
|
texts.push_back( text );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -228,7 +230,7 @@ void MODULE::TransformGraphicShapesWithClearanceToPolygonSet(
|
||||||
case PCB_MODULE_EDGE_T:
|
case PCB_MODULE_EDGE_T:
|
||||||
outline = (EDGE_MODULE*) item;
|
outline = (EDGE_MODULE*) item;
|
||||||
|
|
||||||
if( outline->GetLayer() != aLayer )
|
if( aLayer != UNDEFINED_LAYER && outline->GetLayer() != aLayer )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
outline->TransformShapeWithClearanceToPolygon( aCornerBuffer, 0,
|
outline->TransformShapeWithClearanceToPolygon( aCornerBuffer, 0,
|
||||||
|
@ -240,6 +242,9 @@ void MODULE::TransformGraphicShapesWithClearanceToPolygonSet(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( !aIncludeText )
|
||||||
|
return;
|
||||||
|
|
||||||
// Convert texts sur modules
|
// Convert texts sur modules
|
||||||
if( Reference().GetLayer() == aLayer && Reference().IsVisible() )
|
if( Reference().GetLayer() == aLayer && Reference().IsVisible() )
|
||||||
texts.push_back( &Reference() );
|
texts.push_back( &Reference() );
|
||||||
|
|
|
@ -512,6 +512,25 @@ const EDA_RECT MODULE::GetBoundingBox() const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SHAPE_POLY_SET MODULE::GetBoundingPoly() const
|
||||||
|
{
|
||||||
|
const int segcountforcircle = 8;
|
||||||
|
double correctionFactor = 1.0 / cos( M_PI / (segcountforcircle * 2) );
|
||||||
|
SHAPE_POLY_SET poly;
|
||||||
|
|
||||||
|
TransformPadsShapesWithClearanceToPolygon( UNDEFINED_LAYER,
|
||||||
|
poly, 0, segcountforcircle, correctionFactor );
|
||||||
|
|
||||||
|
TransformGraphicShapesWithClearanceToPolygonSet( UNDEFINED_LAYER,
|
||||||
|
poly, 0, segcountforcircle, correctionFactor, 0, false );
|
||||||
|
|
||||||
|
poly.NormalizeAreaOutlines();
|
||||||
|
poly.Inflate( Millimeter2iu( 0.01 ), segcountforcircle );
|
||||||
|
|
||||||
|
return poly;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void MODULE::GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList )
|
void MODULE::GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList )
|
||||||
{
|
{
|
||||||
int nbpad;
|
int nbpad;
|
||||||
|
@ -607,6 +626,13 @@ bool MODULE::HitTest( const wxPoint& aPosition ) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MODULE::HitTestAccurate( const wxPoint& aPosition ) const
|
||||||
|
{
|
||||||
|
auto shape = GetBoundingPoly();
|
||||||
|
return shape.Contains( aPosition, -1, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool MODULE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
|
bool MODULE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
|
||||||
{
|
{
|
||||||
EDA_RECT arect = aRect;
|
EDA_RECT arect = aRect;
|
||||||
|
|
|
@ -148,6 +148,12 @@ public:
|
||||||
*/
|
*/
|
||||||
EDA_RECT GetFootprintRect() const;
|
EDA_RECT GetFootprintRect() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a bounding polygon for the shapes and pads in the module
|
||||||
|
* This operation is slower but more accurate than calculating a bounding box
|
||||||
|
*/
|
||||||
|
SHAPE_POLY_SET GetBoundingPoly() const;
|
||||||
|
|
||||||
// Virtual function
|
// Virtual function
|
||||||
const EDA_RECT GetBoundingBox() const override;
|
const EDA_RECT GetBoundingBox() const override;
|
||||||
|
|
||||||
|
@ -336,7 +342,7 @@ public:
|
||||||
* and adds these polygons to aCornerBuffer
|
* and adds these polygons to aCornerBuffer
|
||||||
* Useful to generate a polygonal representation of a footprint
|
* Useful to generate a polygonal representation of a footprint
|
||||||
* in 3D view and plot functions, when a full polygonal approach is needed
|
* in 3D view and plot functions, when a full polygonal approach is needed
|
||||||
* @param aLayer = the current layer: pads on this layer are considered
|
* @param aLayer = the layer to consider, or UNDEFINED_LAYER to consider all
|
||||||
* @param aCornerBuffer = the buffer to store polygons
|
* @param aCornerBuffer = the buffer to store polygons
|
||||||
* @param aInflateValue = an additionnal size to add to pad shapes
|
* @param aInflateValue = an additionnal size to add to pad shapes
|
||||||
* aInflateValue = 0 to have the exact pad size
|
* aInflateValue = 0 to have the exact pad size
|
||||||
|
@ -366,7 +372,7 @@ public:
|
||||||
* and adds these polygons to aCornerBuffer
|
* and adds these polygons to aCornerBuffer
|
||||||
* Useful to generate a polygonal representation of a footprint
|
* Useful to generate a polygonal representation of a footprint
|
||||||
* in 3D view and plot functions, when a full polygonal approach is needed
|
* in 3D view and plot functions, when a full polygonal approach is needed
|
||||||
* @param aLayer = the current layer: items on this layer are considered
|
* @param aLayer = the layer to consider, or UNDEFINED_LAYER to consider all
|
||||||
* @param aCornerBuffer = the buffer to store polygons
|
* @param aCornerBuffer = the buffer to store polygons
|
||||||
* @param aInflateValue = a value to inflate shapes
|
* @param aInflateValue = a value to inflate shapes
|
||||||
* aInflateValue = 0 to have the exact shape size
|
* aInflateValue = 0 to have the exact shape size
|
||||||
|
@ -385,7 +391,8 @@ public:
|
||||||
int aInflateValue,
|
int aInflateValue,
|
||||||
int aCircleToSegmentsCount,
|
int aCircleToSegmentsCount,
|
||||||
double aCorrectionFactor,
|
double aCorrectionFactor,
|
||||||
int aCircleToSegmentsCountForTexts = 0 ) const;
|
int aCircleToSegmentsCountForTexts = 0,
|
||||||
|
bool aIncludeText = true ) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief TransformGraphicTextWithClearanceToPolygonSet
|
* @brief TransformGraphicTextWithClearanceToPolygonSet
|
||||||
|
@ -430,6 +437,17 @@ public:
|
||||||
|
|
||||||
bool HitTest( const wxPoint& aPosition ) const override;
|
bool HitTest( const wxPoint& aPosition ) const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if a point is inside the bounding polygon of the module
|
||||||
|
*
|
||||||
|
* The other hit test methods are just checking the bounding box, which
|
||||||
|
* can be quite inaccurate for rotated or oddly-shaped footprints.
|
||||||
|
*
|
||||||
|
* @param aPosition is the point to test
|
||||||
|
* @return true if aPosition is inside the bounding polygon
|
||||||
|
*/
|
||||||
|
bool HitTestAccurate( const wxPoint& aPosition ) const;
|
||||||
|
|
||||||
bool HitTest( const EDA_RECT& aRect, bool aContained = true, int aAccuracy = 0 ) const override;
|
bool HitTest( const EDA_RECT& aRect, bool aContained = true, int aAccuracy = 0 ) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -399,6 +399,7 @@ SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
|
||||||
{
|
{
|
||||||
if( item->HitTest( m_RefPos ) )
|
if( item->HitTest( m_RefPos ) )
|
||||||
{
|
{
|
||||||
|
if( !module || module->HitTestAccurate( m_RefPos ) )
|
||||||
Append( item );
|
Append( item );
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue