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?
|
||||
return false;
|
||||
|
||||
// If there is a polygon specified, check the condition against that polygon
|
||||
if( aSubpolyIndex >= 0 )
|
||||
return containsSingle( aP, aSubpolyIndex );
|
||||
return containsSingle( aP, aSubpolyIndex, aIgnoreHoles );
|
||||
|
||||
// In any other case, check it against all polygons in the set
|
||||
for( int polygonIdx = 0; polygonIdx < OutlineCount(); polygonIdx++ )
|
||||
{
|
||||
if( containsSingle( aP, polygonIdx ) )
|
||||
if( containsSingle( aP, polygonIdx, aIgnoreHoles ) )
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1440,20 +1440,23 @@ 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
|
||||
if( pointInPolygon( aP, m_polys[aSubpolyIndex][0] ) )
|
||||
{
|
||||
// Check that the point is not in any of the holes
|
||||
for( int holeIdx = 0; holeIdx < HoleCount( aSubpolyIndex ); holeIdx++ )
|
||||
if( !aIgnoreHoles )
|
||||
{
|
||||
const SHAPE_LINE_CHAIN hole = CHole( aSubpolyIndex, holeIdx );
|
||||
// Check that the point is not in any of the holes
|
||||
for( int holeIdx = 0; holeIdx < HoleCount( aSubpolyIndex ); holeIdx++ )
|
||||
{
|
||||
const SHAPE_LINE_CHAIN hole = CHole( aSubpolyIndex, holeIdx );
|
||||
|
||||
// If the point is inside a hole (and not on its edge),
|
||||
// it is outside of the polygon
|
||||
if( pointInPolygon( aP, hole ) && !hole.PointOnEdge( aP ) )
|
||||
return false;
|
||||
// If the point is inside a hole (and not on its edge),
|
||||
// it is outside of the polygon
|
||||
if( pointInPolygon( aP, hole ) && !hole.PointOnEdge( aP ) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -933,9 +933,15 @@ class SHAPE_POLY_SET : public SHAPE
|
|||
bool CollideEdge( const VECTOR2I& aPoint, VERTEX_INDEX& aClosestVertex,
|
||||
int aClearance = 0 );
|
||||
|
||||
///> Returns true if a given subpolygon contains the point aP. If aSubpolyIndex < 0
|
||||
///> (default value), checks all polygons in the set
|
||||
bool Contains( const VECTOR2I& aP, int aSubpolyIndex = -1 ) const;
|
||||
/**
|
||||
* Returns true if a given subpolygon contains the point aP
|
||||
*
|
||||
* @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)
|
||||
bool IsEmpty() const
|
||||
|
@ -1112,10 +1118,11 @@ class SHAPE_POLY_SET : public SHAPE
|
|||
* the aSubpolyIndex-th polygon will be tested.
|
||||
* @param aSubpolyIndex is an integer specifying which polygon in the set has to be
|
||||
* 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
|
||||
* 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
|
||||
|
|
|
@ -138,7 +138,7 @@ void MODULE::TransformPadsShapesWithClearanceToPolygon( PCB_LAYER_ID aLayer,
|
|||
wxSize margin;
|
||||
for( ; pad != NULL; pad = pad->Next() )
|
||||
{
|
||||
if( !pad->IsOnLayer(aLayer) )
|
||||
if( aLayer != UNDEFINED_LAYER && !pad->IsOnLayer(aLayer) )
|
||||
continue;
|
||||
|
||||
// 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 aCircleToSegmentsCount,
|
||||
double aCorrectionFactor,
|
||||
int aCircleToSegmentsCountForTexts ) const
|
||||
int aCircleToSegmentsCountForTexts,
|
||||
bool aIncludeText ) const
|
||||
{
|
||||
std::vector<TEXTE_MODULE *> texts; // List of TEXTE_MODULE to convert
|
||||
EDGE_MODULE* outline;
|
||||
|
@ -219,7 +220,8 @@ void MODULE::TransformGraphicShapesWithClearanceToPolygonSet(
|
|||
{
|
||||
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 );
|
||||
|
||||
break;
|
||||
|
@ -228,7 +230,7 @@ void MODULE::TransformGraphicShapesWithClearanceToPolygonSet(
|
|||
case PCB_MODULE_EDGE_T:
|
||||
outline = (EDGE_MODULE*) item;
|
||||
|
||||
if( outline->GetLayer() != aLayer )
|
||||
if( aLayer != UNDEFINED_LAYER && outline->GetLayer() != aLayer )
|
||||
break;
|
||||
|
||||
outline->TransformShapeWithClearanceToPolygon( aCornerBuffer, 0,
|
||||
|
@ -240,6 +242,9 @@ void MODULE::TransformGraphicShapesWithClearanceToPolygonSet(
|
|||
}
|
||||
}
|
||||
|
||||
if( !aIncludeText )
|
||||
return;
|
||||
|
||||
// Convert texts sur modules
|
||||
if( Reference().GetLayer() == aLayer && Reference().IsVisible() )
|
||||
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 )
|
||||
{
|
||||
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
|
||||
{
|
||||
EDA_RECT arect = aRect;
|
||||
|
|
|
@ -148,6 +148,12 @@ public:
|
|||
*/
|
||||
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
|
||||
const EDA_RECT GetBoundingBox() const override;
|
||||
|
||||
|
@ -336,7 +342,7 @@ public:
|
|||
* and adds these polygons to aCornerBuffer
|
||||
* Useful to generate a polygonal representation of a footprint
|
||||
* 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 aInflateValue = an additionnal size to add to pad shapes
|
||||
* aInflateValue = 0 to have the exact pad size
|
||||
|
@ -366,7 +372,7 @@ public:
|
|||
* and adds these polygons to aCornerBuffer
|
||||
* Useful to generate a polygonal representation of a footprint
|
||||
* 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 aInflateValue = a value to inflate shapes
|
||||
* aInflateValue = 0 to have the exact shape size
|
||||
|
@ -385,7 +391,8 @@ public:
|
|||
int aInflateValue,
|
||||
int aCircleToSegmentsCount,
|
||||
double aCorrectionFactor,
|
||||
int aCircleToSegmentsCountForTexts = 0 ) const;
|
||||
int aCircleToSegmentsCountForTexts = 0,
|
||||
bool aIncludeText = true ) const;
|
||||
|
||||
/**
|
||||
* @brief TransformGraphicTextWithClearanceToPolygonSet
|
||||
|
@ -430,6 +437,17 @@ public:
|
|||
|
||||
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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -399,7 +399,8 @@ SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
|
|||
{
|
||||
if( item->HitTest( m_RefPos ) )
|
||||
{
|
||||
Append( item );
|
||||
if( !module || module->HitTestAccurate( m_RefPos ) )
|
||||
Append( item );
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue