diff --git a/libs/kimath/include/geometry/shape.h b/libs/kimath/include/geometry/shape.h index 129e742b9e..056ceb3b9c 100644 --- a/libs/kimath/include/geometry/shape.h +++ b/libs/kimath/include/geometry/shape.h @@ -104,7 +104,7 @@ public: virtual size_t GetIndexableSubshapeCount() const { return 0; } - virtual void GetIndexableSubshapes( std::vector& aSubshapes ) { } + virtual void GetIndexableSubshapes( std::vector& aSubshapes ) const { } protected: ///< type of our shape @@ -143,6 +143,13 @@ public: return nullptr; }; + /** + * Return the actual minimum distance between two shapes + * + * @retval distance in IU + */ + int GetClearance( const SHAPE* aOther ) const; + /** * Return true if the shape is a null shape. * diff --git a/libs/kimath/include/geometry/shape_compound.h b/libs/kimath/include/geometry/shape_compound.h index 337632403b..7f80b0e7a2 100644 --- a/libs/kimath/include/geometry/shape_compound.h +++ b/libs/kimath/include/geometry/shape_compound.h @@ -82,10 +82,10 @@ public: // Don't make clients deal with nested SHAPE_COMPOUNDs if( aShape->HasIndexableSubshapes() ) { - std::vector subshapes; + std::vector subshapes; aShape->GetIndexableSubshapes( subshapes ); - for( SHAPE* subshape : subshapes ) + for( const SHAPE* subshape : subshapes ) m_shapes.push_back( subshape->Clone() ); delete aShape; @@ -127,9 +127,11 @@ public: return m_shapes.size(); } - virtual void GetIndexableSubshapes( std::vector& aSubshapes ) override + virtual void GetIndexableSubshapes( std::vector& aSubshapes ) const override { - aSubshapes = m_shapes; + aSubshapes.clear(); + aSubshapes.reserve( m_shapes.size() ); + std::copy( m_shapes.begin(), m_shapes.end(), std::back_inserter( aSubshapes ) ); } bool ConvertToSimplePolygon( SHAPE_SIMPLE* aOut ) const; diff --git a/libs/kimath/include/geometry/shape_poly_set.h b/libs/kimath/include/geometry/shape_poly_set.h index 7b6e826762..7e2c695d47 100644 --- a/libs/kimath/include/geometry/shape_poly_set.h +++ b/libs/kimath/include/geometry/shape_poly_set.h @@ -517,7 +517,7 @@ public: virtual size_t GetIndexableSubshapeCount() const override; - virtual void GetIndexableSubshapes( std::vector& aSubshapes ) override; + virtual void GetIndexableSubshapes( std::vector& aSubshapes ) const override; /** * Convert a global vertex index ---i.e., a number that globally identifies a vertex in a diff --git a/libs/kimath/src/geometry/shape.cpp b/libs/kimath/src/geometry/shape.cpp index e40c0beaa6..fa50bfea73 100644 --- a/libs/kimath/src/geometry/shape.cpp +++ b/libs/kimath/src/geometry/shape.cpp @@ -24,6 +24,12 @@ #include +#include +#include +#include +#include +#include +#include bool SHAPE::Parse( std::stringstream& aStream ) { @@ -37,3 +43,36 @@ const std::string SHAPE::Format() const assert( false ); return std::string( "" ); } + + +int SHAPE::GetClearance( const SHAPE* aOther ) const +{ + int actual_clearance = std::numeric_limits::max(); + std::vector a_shapes; + std::vector b_shapes; + + GetIndexableSubshapes( a_shapes ); + aOther->GetIndexableSubshapes( b_shapes ); + + if( GetIndexableSubshapeCount() == 0 ) + a_shapes.push_back( this ); + + if( aOther->GetIndexableSubshapeCount() == 0 ) + b_shapes.push_back( aOther ); + + // Clearance gets the distance to the centerline. We add in the additional size + // after to get the true clearance + for( const SHAPE* a : a_shapes ) + { + for( const SHAPE* b : b_shapes ) + { + int temp_dist = 0; + a->Collide( b, std::numeric_limits::max() / 2, &temp_dist ); + + if( temp_dist < actual_clearance ) + actual_clearance = temp_dist; + } + } + + return actual_clearance; +} diff --git a/libs/kimath/src/geometry/shape_poly_set.cpp b/libs/kimath/src/geometry/shape_poly_set.cpp index 1d9a756b23..7a290c278f 100644 --- a/libs/kimath/src/geometry/shape_poly_set.cpp +++ b/libs/kimath/src/geometry/shape_poly_set.cpp @@ -2526,7 +2526,7 @@ size_t SHAPE_POLY_SET::GetIndexableSubshapeCount() const } -void SHAPE_POLY_SET::GetIndexableSubshapes( std::vector& aSubshapes ) +void SHAPE_POLY_SET::GetIndexableSubshapes( std::vector& aSubshapes ) const { aSubshapes.reserve( GetIndexableSubshapeCount() ); diff --git a/pcbnew/drc/drc_rtree.h b/pcbnew/drc/drc_rtree.h index cb6f721eef..4aea5c6464 100644 --- a/pcbnew/drc/drc_rtree.h +++ b/pcbnew/drc/drc_rtree.h @@ -51,7 +51,7 @@ public: struct ITEM_WITH_SHAPE { - ITEM_WITH_SHAPE( BOARD_ITEM *aParent, SHAPE* aShape, + ITEM_WITH_SHAPE( BOARD_ITEM *aParent, const SHAPE* aShape, std::shared_ptr aParentShape = nullptr ) : parent ( aParent ), shape ( aShape ), @@ -59,7 +59,7 @@ public: {}; BOARD_ITEM* parent; - SHAPE* shape; + const SHAPE* shape; std::shared_ptr parentShape; }; @@ -108,7 +108,7 @@ public: if( aItem->Type() == PCB_FP_TEXT_T && !static_cast( aItem )->IsVisible() ) return; - std::vector subshapes; + std::vector subshapes; std::shared_ptr shape = aItem->GetEffectiveShape( aRefLayer ); subshapes.clear(); @@ -128,9 +128,9 @@ public: } } - for( SHAPE* subshape : subshapes ) + for( const SHAPE* subshape : subshapes ) { - if( dynamic_cast( subshape ) ) + if( dynamic_cast( subshape ) ) continue; BOX2I bbox = subshape->BBox(); @@ -336,9 +336,9 @@ public: auto polyVisitor = [&]( ITEM_WITH_SHAPE* aItem ) -> bool { - SHAPE* shape = aItem->shape; - wxASSERT( dynamic_cast( shape ) ); - auto tri = static_cast( shape ); + const SHAPE* shape = aItem->shape; + wxASSERT( dynamic_cast( shape ) ); + auto tri = static_cast( shape ); const SHAPE_LINE_CHAIN& outline = poly->Outline( 0 ); diff --git a/pcbnew/router/pns_kicad_iface.cpp b/pcbnew/router/pns_kicad_iface.cpp index 93454fcc35..c8d0e36fe1 100644 --- a/pcbnew/router/pns_kicad_iface.cpp +++ b/pcbnew/router/pns_kicad_iface.cpp @@ -937,7 +937,7 @@ std::unique_ptr PNS_KICAD_IFACE_BASE::syncPad( PAD* aPad ) if( shape->HasIndexableSubshapes() && shape->GetIndexableSubshapeCount() == 1 ) { - std::vector subshapes; + std::vector subshapes; shape->GetIndexableSubshapes( subshapes ); solid->SetShape( subshapes[0]->Clone() ); diff --git a/pcbnew/router/router_preview_item.cpp b/pcbnew/router/router_preview_item.cpp index db5f17511a..c247ffe5a4 100644 --- a/pcbnew/router/router_preview_item.cpp +++ b/pcbnew/router/router_preview_item.cpp @@ -450,10 +450,10 @@ void ROUTER_PREVIEW_ITEM::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const if( m_shape->HasIndexableSubshapes() ) { - std::vector subshapes; + std::vector subshapes; m_shape->GetIndexableSubshapes( subshapes ); - for( SHAPE* shape : subshapes ) + for( const SHAPE* shape : subshapes ) drawShape( shape, gal ); } else diff --git a/pcbnew/tools/pcb_control.cpp b/pcbnew/tools/pcb_control.cpp index 099a9685cb..4888e4e802 100644 --- a/pcbnew/tools/pcb_control.cpp +++ b/pcbnew/tools/pcb_control.cpp @@ -1276,8 +1276,20 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent ) constraint = drcEngine->EvalRules( CLEARANCE_CONSTRAINT, a, b, overlap.CuStack().front() ); + std::shared_ptr a_shape( a_conn->GetEffectiveShape( overlap.CuStack().front() ) ); + std::shared_ptr b_shape( b_conn->GetEffectiveShape( overlap.CuStack().front() ) ); + + int actual_clearance = a_shape->GetClearance( b_shape.get() ); + msgItems.emplace_back( MSG_PANEL_ITEM( _( "Resolved clearance" ), clearanceString( constraint ) ) ); + + if( actual_clearance > -1 && actual_clearance < std::numeric_limits::max() ) + { + msgItems.emplace_back( + MSG_PANEL_ITEM( _( "Actual clearance" ), + StringFromValue( units, actual_clearance, true ) ) ); + } } }