Creepage : add minimum slot width

This commit is contained in:
Fabien Corona 2024-10-21 21:49:09 +02:00
parent 6be6680d8c
commit 6d85853365
11 changed files with 716 additions and 331 deletions

View File

@ -94,6 +94,7 @@
#define LEGACY_COPPEREDGECLEARANCE -0.01 // A flag to indicate the legacy method (based #define LEGACY_COPPEREDGECLEARANCE -0.01 // A flag to indicate the legacy method (based
// on edge cut line thicknesses) should be used. // on edge cut line thicknesses) should be used.
#define DEFAULT_SILKCLEARANCE 0.0 #define DEFAULT_SILKCLEARANCE 0.0
#define DEFAULT_MINGROOVEWIDTH 0.0
#define DEFAULT_MINRESOLVEDSPOKES 2 // Fewer resolved spokes indicates a starved thermal #define DEFAULT_MINRESOLVEDSPOKES 2 // Fewer resolved spokes indicates a starved thermal
@ -687,7 +688,8 @@ public:
// connected track // connected track
bool m_TempOverrideTrackWidth; // use selected track width temporarily even when bool m_TempOverrideTrackWidth; // use selected track width temporarily even when
// using connected track width // using connected track width
int m_MinClearance; // overall min clearance int m_MinClearance; // overall min
int m_MinGrooveWidth; // Minimum groove width for creepage checks
int m_MinConn; // overall min connection width int m_MinConn; // overall min connection width
int m_TrackMinWidth; // overall min track width int m_TrackMinWidth; // overall min track width
int m_ViasMinAnnularWidth; // overall minimum width of the via copper ring int m_ViasMinAnnularWidth; // overall minimum width of the via copper ring

View File

@ -156,6 +156,7 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std:
m_MinResolvedSpokes = DEFAULT_MINRESOLVEDSPOKES; m_MinResolvedSpokes = DEFAULT_MINRESOLVEDSPOKES;
m_MinSilkTextHeight = pcbIUScale.mmToIU( DEFAULT_SILK_TEXT_SIZE * 0.8 ); m_MinSilkTextHeight = pcbIUScale.mmToIU( DEFAULT_SILK_TEXT_SIZE * 0.8 );
m_MinSilkTextThickness= pcbIUScale.mmToIU( DEFAULT_SILK_TEXT_WIDTH * 0.8 ); m_MinSilkTextThickness= pcbIUScale.mmToIU( DEFAULT_SILK_TEXT_WIDTH * 0.8 );
m_MinGrooveWidth = pcbIUScale.mmToIU( DEFAULT_MINGROOVEWIDTH );
for( int errorCode = DRCE_FIRST; errorCode <= DRCE_LAST; ++errorCode ) for( int errorCode = DRCE_FIRST; errorCode <= DRCE_LAST; ++errorCode )
m_DRCSeverities[ errorCode ] = RPT_SEVERITY_ERROR; m_DRCSeverities[ errorCode ] = RPT_SEVERITY_ERROR;
@ -283,6 +284,10 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std:
&m_SilkClearance, pcbIUScale.mmToIU( DEFAULT_SILKCLEARANCE ), &m_SilkClearance, pcbIUScale.mmToIU( DEFAULT_SILKCLEARANCE ),
pcbIUScale.mmToIU( 0.00 ), pcbIUScale.mmToIU( 100.0 ), pcbIUScale.MM_PER_IU ) ); pcbIUScale.mmToIU( 0.00 ), pcbIUScale.mmToIU( 100.0 ), pcbIUScale.MM_PER_IU ) );
m_params.emplace_back( new PARAM_SCALED<int>( "rules.min_groove_width",
&m_MinGrooveWidth, pcbIUScale.mmToIU( DEFAULT_MINGROOVEWIDTH ),
pcbIUScale.mmToIU( 0.00 ), pcbIUScale.mmToIU( 25.0 ), pcbIUScale.MM_PER_IU ) );
// While the maximum *effective* value is 4, we've had users interpret this as the count on // While the maximum *effective* value is 4, we've had users interpret this as the count on
// all layers, and enter something like 10. They'll figure it out soon enough *unless* we // all layers, and enter something like 10. They'll figure it out soon enough *unless* we
// enforce a max of 4 (and therefore reset it back to the default of 2), at which point it // enforce a max of 4 (and therefore reset it back to the default of 2), at which point it
@ -934,6 +939,7 @@ void BOARD_DESIGN_SETTINGS::initFromOther( const BOARD_DESIGN_SETTINGS& aOther )
m_UseConnectedTrackWidth = aOther.m_UseConnectedTrackWidth; m_UseConnectedTrackWidth = aOther.m_UseConnectedTrackWidth;
m_TempOverrideTrackWidth = aOther.m_TempOverrideTrackWidth; m_TempOverrideTrackWidth = aOther.m_TempOverrideTrackWidth;
m_MinClearance = aOther.m_MinClearance; m_MinClearance = aOther.m_MinClearance;
m_MinGrooveWidth = aOther.m_MinGrooveWidth;
m_MinConn = aOther.m_MinConn; m_MinConn = aOther.m_MinConn;
m_TrackMinWidth = aOther.m_TrackMinWidth; m_TrackMinWidth = aOther.m_TrackMinWidth;
m_ViasMinAnnularWidth = aOther.m_ViasMinAnnularWidth; m_ViasMinAnnularWidth = aOther.m_ViasMinAnnularWidth;
@ -1024,6 +1030,7 @@ bool BOARD_DESIGN_SETTINGS::operator==( const BOARD_DESIGN_SETTINGS& aOther ) co
if( m_UseConnectedTrackWidth != aOther.m_UseConnectedTrackWidth ) return false; if( m_UseConnectedTrackWidth != aOther.m_UseConnectedTrackWidth ) return false;
if( m_TempOverrideTrackWidth != aOther.m_TempOverrideTrackWidth ) return false; if( m_TempOverrideTrackWidth != aOther.m_TempOverrideTrackWidth ) return false;
if( m_MinClearance != aOther.m_MinClearance ) return false; if( m_MinClearance != aOther.m_MinClearance ) return false;
if( m_MinGrooveWidth != aOther.m_MinGrooveWidth ) return false;
if( m_MinConn != aOther.m_MinConn ) return false; if( m_MinConn != aOther.m_MinConn ) return false;
if( m_TrackMinWidth != aOther.m_TrackMinWidth ) return false; if( m_TrackMinWidth != aOther.m_TrackMinWidth ) return false;
if( m_ViasMinAnnularWidth != aOther.m_ViasMinAnnularWidth ) return false; if( m_ViasMinAnnularWidth != aOther.m_ViasMinAnnularWidth ) return false;

View File

@ -32,6 +32,7 @@
#include <widgets/paged_dialog.h> #include <widgets/paged_dialog.h>
#include <wx/treebook.h> #include <wx/treebook.h>
#include <bitmaps.h> #include <bitmaps.h>
#include <advanced_config.h>
PANEL_SETUP_CONSTRAINTS::PANEL_SETUP_CONSTRAINTS( wxWindow* aParentWindow, PCB_EDIT_FRAME* aFrame ) : PANEL_SETUP_CONSTRAINTS::PANEL_SETUP_CONSTRAINTS( wxWindow* aParentWindow, PCB_EDIT_FRAME* aFrame ) :
@ -48,6 +49,7 @@ PANEL_SETUP_CONSTRAINTS::PANEL_SETUP_CONSTRAINTS( wxWindow* aParentWindow, PCB_E
m_holeClearance( aFrame, m_HoleClearanceLabel, m_HoleClearanceCtrl, m_HoleClearanceUnits ), m_holeClearance( aFrame, m_HoleClearanceLabel, m_HoleClearanceCtrl, m_HoleClearanceUnits ),
m_edgeClearance( aFrame, m_EdgeClearanceLabel, m_EdgeClearanceCtrl, m_EdgeClearanceUnits ), m_edgeClearance( aFrame, m_EdgeClearanceLabel, m_EdgeClearanceCtrl, m_EdgeClearanceUnits ),
m_silkClearance( aFrame, m_silkClearanceLabel, m_silkClearanceCtrl, m_silkClearanceUnits ), m_silkClearance( aFrame, m_silkClearanceLabel, m_silkClearanceCtrl, m_silkClearanceUnits ),
m_minGrooveWidth( aFrame, m_minGrooveWidthLabel, m_minGrooveWidthCtrl, m_minGrooveWidthUnits ),
m_minTextHeight( aFrame, m_textHeightLabel, m_textHeightCtrl, m_textHeightUnits ), m_minTextHeight( aFrame, m_textHeightLabel, m_textHeightCtrl, m_textHeightUnits ),
m_minTextThickness( aFrame, m_textThicknessLabel, m_textThicknessCtrl, m_textThicknessUnits ), m_minTextThickness( aFrame, m_textThicknessLabel, m_textThicknessCtrl, m_textThicknessUnits ),
m_maxError( aFrame, m_maxErrorTitle, m_maxErrorCtrl, m_maxErrorUnits ) m_maxError( aFrame, m_maxErrorTitle, m_maxErrorCtrl, m_maxErrorUnits )
@ -74,6 +76,13 @@ PANEL_SETUP_CONSTRAINTS::PANEL_SETUP_CONSTRAINTS( wxWindow* aParentWindow, PCB_E
wxSize ctrlSize = m_minResolvedSpokeCountCtrl->GetSize(); wxSize ctrlSize = m_minResolvedSpokeCountCtrl->GetSize();
ctrlSize.x = KIUI::GetTextSize( wxT( "XXX" ), m_minResolvedSpokeCountCtrl ).x; ctrlSize.x = KIUI::GetTextSize( wxT( "XXX" ), m_minResolvedSpokeCountCtrl ).x;
m_minResolvedSpokeCountCtrl->SetSize( ctrlSize ); m_minResolvedSpokeCountCtrl->SetSize( ctrlSize );
if( !ADVANCED_CFG::GetCfg().m_EnableCreepageDRC )
{
m_minGrooveWidthCtrl->Show( false );
m_minGrooveWidthUnits->Show( false );
m_minGrooveWidthLabel->Show( false );
}
} }
@ -97,6 +106,7 @@ bool PANEL_SETUP_CONSTRAINTS::TransferDataToWindow()
m_viaMinSize.SetValue(m_BrdSettings->m_ViasMinSize ); m_viaMinSize.SetValue(m_BrdSettings->m_ViasMinSize );
m_holeClearance.SetValue( m_BrdSettings->m_HoleClearance ); m_holeClearance.SetValue( m_BrdSettings->m_HoleClearance );
m_edgeClearance.SetValue( m_BrdSettings->m_CopperEdgeClearance ); m_edgeClearance.SetValue( m_BrdSettings->m_CopperEdgeClearance );
m_minGrooveWidth.SetValue( m_BrdSettings->m_MinGrooveWidth );
m_throughHoleMin.SetValue( m_BrdSettings->m_MinThroughDrill ); m_throughHoleMin.SetValue( m_BrdSettings->m_MinThroughDrill );
m_holeToHoleMin.SetValue( m_BrdSettings->m_HoleToHoleMin ); m_holeToHoleMin.SetValue( m_BrdSettings->m_HoleToHoleMin );
@ -135,6 +145,9 @@ bool PANEL_SETUP_CONSTRAINTS::TransferDataFromWindow()
if( !m_edgeClearance.Validate( 0, 10, EDA_UNITS::INCHES ) ) if( !m_edgeClearance.Validate( 0, 10, EDA_UNITS::INCHES ) )
return false; return false;
if( !m_minGrooveWidth.Validate( 0, 10, EDA_UNITS::INCHES ) )
return false;
if( !m_throughHoleMin.Validate( 2, 1000, EDA_UNITS::MILS ) ) // #107 to 1 inch if( !m_throughHoleMin.Validate( 2, 1000, EDA_UNITS::MILS ) ) // #107 to 1 inch
return false; return false;
@ -159,6 +172,7 @@ bool PANEL_SETUP_CONSTRAINTS::TransferDataFromWindow()
m_BrdSettings->m_ViasMinSize = m_viaMinSize.GetValue(); m_BrdSettings->m_ViasMinSize = m_viaMinSize.GetValue();
m_BrdSettings->m_HoleClearance = m_holeClearance.GetValue(); m_BrdSettings->m_HoleClearance = m_holeClearance.GetValue();
m_BrdSettings->m_CopperEdgeClearance = m_edgeClearance.GetValue(); m_BrdSettings->m_CopperEdgeClearance = m_edgeClearance.GetValue();
m_BrdSettings->m_MinGrooveWidth = m_minGrooveWidth.GetValue();
m_BrdSettings->m_MinThroughDrill = m_throughHoleMin.GetValue(); m_BrdSettings->m_MinThroughDrill = m_throughHoleMin.GetValue();
m_BrdSettings->m_HoleToHoleMin = m_holeToHoleMin.GetValue(); m_BrdSettings->m_HoleToHoleMin = m_holeToHoleMin.GetValue();

View File

@ -60,6 +60,7 @@ public:
UNIT_BINDER m_holeClearance; UNIT_BINDER m_holeClearance;
UNIT_BINDER m_edgeClearance; UNIT_BINDER m_edgeClearance;
UNIT_BINDER m_silkClearance; UNIT_BINDER m_silkClearance;
UNIT_BINDER m_minGrooveWidth;
UNIT_BINDER m_minTextHeight; UNIT_BINDER m_minTextHeight;
UNIT_BINDER m_minTextThickness; UNIT_BINDER m_minTextThickness;
UNIT_BINDER m_maxError; UNIT_BINDER m_maxError;

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.0.0-0-g0efcecf) // C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
// http://www.wxformbuilder.org/ // http://www.wxformbuilder.org/
// //
// PLEASE DO *NOT* EDIT THIS FILE! // PLEASE DO *NOT* EDIT THIS FILE!
@ -154,6 +154,22 @@ PANEL_SETUP_CONSTRAINTS_BASE::PANEL_SETUP_CONSTRAINTS_BASE( wxWindow* parent, wx
m_EdgeClearanceUnits->Wrap( -1 ); m_EdgeClearanceUnits->Wrap( -1 );
fgFeatureConstraints->Add( m_EdgeClearanceUnits, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 ); fgFeatureConstraints->Add( m_EdgeClearanceUnits, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
m_bitmapMinGrooveWidth = new wxStaticBitmap( m_scrolledWindow, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
fgFeatureConstraints->Add( m_bitmapMinGrooveWidth, 0, wxALL, 5 );
m_minGrooveWidthLabel = new wxStaticText( m_scrolledWindow, wxID_ANY, _("Minimum groove for creepage:"), wxDefaultPosition, wxDefaultSize, 0 );
m_minGrooveWidthLabel->Wrap( -1 );
fgFeatureConstraints->Add( m_minGrooveWidthLabel, 0, wxALL, 5 );
m_minGrooveWidthCtrl = new wxTextCtrl( m_scrolledWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_minGrooveWidthCtrl->SetToolTip( _("The minimum slot width from DRC creepage checks") );
fgFeatureConstraints->Add( m_minGrooveWidthCtrl, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxEXPAND|wxTOP, 5 );
m_minGrooveWidthUnits = new wxStaticText( m_scrolledWindow, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 );
m_minGrooveWidthUnits->Wrap( -1 );
fgFeatureConstraints->Add( m_minGrooveWidthUnits, 0, wxALL, 5 );
m_staticline3 = new wxStaticLine( m_scrolledWindow, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); m_staticline3 = new wxStaticLine( m_scrolledWindow, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
fgFeatureConstraints->Add( m_staticline3, 0, wxTOP|wxEXPAND, 10 ); fgFeatureConstraints->Add( m_staticline3, 0, wxTOP|wxEXPAND, 10 );

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.0.0-0-g0efcecf) // C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
// http://www.wxformbuilder.org/ // http://www.wxformbuilder.org/
// //
// PLEASE DO *NOT* EDIT THIS FILE! // PLEASE DO *NOT* EDIT THIS FILE!
@ -68,6 +68,10 @@ class PANEL_SETUP_CONSTRAINTS_BASE : public wxPanel
wxStaticText* m_EdgeClearanceLabel; wxStaticText* m_EdgeClearanceLabel;
wxTextCtrl* m_EdgeClearanceCtrl; wxTextCtrl* m_EdgeClearanceCtrl;
wxStaticText* m_EdgeClearanceUnits; wxStaticText* m_EdgeClearanceUnits;
wxStaticBitmap* m_bitmapMinGrooveWidth;
wxStaticText* m_minGrooveWidthLabel;
wxTextCtrl* m_minGrooveWidthCtrl;
wxStaticText* m_minGrooveWidthUnits;
wxStaticLine* m_staticline3; wxStaticLine* m_staticline3;
wxStaticLine* m_staticline4; wxStaticLine* m_staticline4;
wxStaticLine* m_staticline5; wxStaticLine* m_staticline5;

View File

@ -25,16 +25,15 @@
#include <geometry/intersection.h> #include <geometry/intersection.h>
extern bool SegmentIntersectsBoard( const VECTOR2I& aP1, const VECTOR2I& aP2,
const std::vector<BOARD_ITEM*>& aBe,
const std::vector<const BOARD_ITEM*>& aDontTestAgainst );
extern bool segmentIntersectsArc( const VECTOR2I& p1, const VECTOR2I& p2, const VECTOR2I& center, extern bool segmentIntersectsArc( const VECTOR2I& p1, const VECTOR2I& p2, const VECTOR2I& center,
double radius, EDA_ANGLE startAngle, EDA_ANGLE endAngle ); double radius, EDA_ANGLE startAngle, EDA_ANGLE endAngle,
std::vector<VECTOR2I>* aIntersectPoints );
//Check if line segments 'p1q1' and 'p2q2' intersect, excluding endpoint overlap //Check if line segments 'p1q1' and 'p2q2' intersect, excluding endpoint overlap
bool segments_intersect( VECTOR2I p1, VECTOR2I q1, VECTOR2I p2, VECTOR2I q2 ) bool segments_intersect( VECTOR2I p1, VECTOR2I q1, VECTOR2I p2, VECTOR2I q2,
std::vector<VECTOR2I>* aIntersectPoints )
{ {
if( p1 == p2 || p1 == q2 || q1 == p2 || q1 == q2 ) if( p1 == p2 || p1 == q2 || q1 == p2 || q1 == q2 )
return false; return false;
@ -52,6 +51,13 @@ bool segments_intersect( VECTOR2I p1, VECTOR2I q1, VECTOR2I p2, VECTOR2I q2 )
std::visit( visitor, geom1 ); std::visit( visitor, geom1 );
if( aIntersectPoints )
{
for( VECTOR2I& point : intersectionPoints )
aIntersectPoints->push_back( point );
}
return intersectionPoints.size() > 0; return intersectionPoints.size() > 0;
} }
@ -332,7 +338,7 @@ std::vector<path_connection> BE_SHAPE_CIRCLE::Paths( const BE_SHAPE_ARC& aS2, do
for( path_connection pc : this->Paths( csp, aMaxWeight, aMaxSquaredWeight ) ) for( path_connection pc : this->Paths( csp, aMaxWeight, aMaxSquaredWeight ) )
{ {
if( !segmentIntersectsArc( pc.a1, pc.a2, arcCenter, arcRadius, arcStartAngle, if( !segmentIntersectsArc( pc.a1, pc.a2, arcCenter, arcRadius, arcStartAngle,
arcEndAngle ) ) arcEndAngle, nullptr ) )
result.push_back( pc ); result.push_back( pc );
} }
} }
@ -797,7 +803,7 @@ void BE_SHAPE_ARC::ConnectChildren( GraphNode* a1, GraphNode* a2, CreepageGraph&
double weight = abs( m_radius * ( angle2 - angle1 ).AsRadians() ); double weight = abs( m_radius * ( angle2 - angle1 ).AsRadians() );
if( aG.m_minGrooveWidth <= 0 ) if( true || aG.m_minGrooveWidth <= 0 )
{ {
if( ( weight > aG.GetTarget() ) ) if( ( weight > aG.GetTarget() ) )
return; return;
@ -824,7 +830,8 @@ void CreepageGraph::SetTarget( double aTarget )
} }
bool segmentIntersectsArc( const VECTOR2I& p1, const VECTOR2I& p2, const VECTOR2I& center, bool segmentIntersectsArc( const VECTOR2I& p1, const VECTOR2I& p2, const VECTOR2I& center,
double radius, EDA_ANGLE startAngle, EDA_ANGLE endAngle ) double radius, EDA_ANGLE startAngle, EDA_ANGLE endAngle,
std::vector<VECTOR2I>* aIntersectPoints )
{ {
SEG segment( p1, p2 ); SEG segment( p1, p2 );
@ -840,6 +847,12 @@ bool segmentIntersectsArc( const VECTOR2I& p1, const VECTOR2I& p2, const VECTOR2
INTERSECTION_VISITOR visitor( geom2, intersectionPoints ); INTERSECTION_VISITOR visitor( geom2, intersectionPoints );
std::visit( visitor, geom1 ); std::visit( visitor, geom1 );
if( aIntersectPoints )
{
for( VECTOR2I& point : intersectionPoints )
aIntersectPoints->push_back( point );
}
return intersectionPoints.size() > 0; return intersectionPoints.size() > 0;
} }
@ -1054,12 +1067,12 @@ std::vector<path_connection> CU_SHAPE_SEGMENT::Paths( const BE_SHAPE_ARC& aS2, d
for( auto& pc : this->Paths( bsp1, aMaxWeight, aMaxSquaredWeight ) ) for( auto& pc : this->Paths( bsp1, aMaxWeight, aMaxSquaredWeight ) )
if( !segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle, if( !segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle,
beArcEndAngle ) ) beArcEndAngle, nullptr ) )
result.push_back( pc ); result.push_back( pc );
for( auto& pc : this->Paths( bsp2, aMaxWeight, aMaxSquaredWeight ) ) for( auto& pc : this->Paths( bsp2, aMaxWeight, aMaxSquaredWeight ) )
if( !segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle, if( !segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle,
beArcEndAngle ) ) beArcEndAngle, nullptr ) )
result.push_back( pc ); result.push_back( pc );
} }
@ -1095,12 +1108,12 @@ std::vector<path_connection> CU_SHAPE_CIRCLE::Paths( const BE_SHAPE_ARC& aS2, do
for( auto& pc : this->Paths( bsp1, aMaxWeight, aMaxSquaredWeight ) ) for( auto& pc : this->Paths( bsp1, aMaxWeight, aMaxSquaredWeight ) )
if( !segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle, if( !segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle,
beArcEndAngle ) ) beArcEndAngle, nullptr ) )
result.push_back( pc ); result.push_back( pc );
for( auto& pc : this->Paths( bsp2, aMaxWeight, aMaxSquaredWeight ) ) for( auto& pc : this->Paths( bsp2, aMaxWeight, aMaxSquaredWeight ) )
if( !segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle, if( !segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle,
beArcEndAngle ) ) beArcEndAngle, nullptr ) )
result.push_back( pc ); result.push_back( pc );
} }
return result; return result;
@ -1167,12 +1180,12 @@ std::vector<path_connection> CU_SHAPE_ARC::Paths( const BE_SHAPE_ARC& aS2, doubl
for( auto& pc : this->Paths( bsp1, aMaxWeight, aMaxSquaredWeight ) ) for( auto& pc : this->Paths( bsp1, aMaxWeight, aMaxSquaredWeight ) )
if( !segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle, if( !segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle,
beArcEndAngle ) ) beArcEndAngle, nullptr ) )
result.push_back( pc ); result.push_back( pc );
for( auto& pc : this->Paths( bsp2, aMaxWeight, aMaxSquaredWeight ) ) for( auto& pc : this->Paths( bsp2, aMaxWeight, aMaxSquaredWeight ) )
if( !segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle, if( !segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle,
beArcEndAngle ) ) beArcEndAngle, nullptr ) )
result.push_back( pc ); result.push_back( pc );
} }
@ -1718,7 +1731,8 @@ std::vector<path_connection> CU_SHAPE_ARC::Paths( const CU_SHAPE_ARC& aS2, doubl
} }
bool segmentIntersectsCircle( VECTOR2I p1, VECTOR2I p2, VECTOR2I center, double radius ) bool segmentIntersectsCircle( VECTOR2I p1, VECTOR2I p2, VECTOR2I center, double radius,
std::vector<VECTOR2I>* aIntersectPoints )
{ {
SEG segment( p1, p2 ); SEG segment( p1, p2 );
CIRCLE circle( center, radius ); CIRCLE circle( center, radius );
@ -1730,13 +1744,26 @@ bool segmentIntersectsCircle( VECTOR2I p1, VECTOR2I p2, VECTOR2I center, double
INTERSECTION_VISITOR visitor( geom2, intersectionPoints ); INTERSECTION_VISITOR visitor( geom2, intersectionPoints );
std::visit( visitor, geom1 ); std::visit( visitor, geom1 );
if( aIntersectPoints )
{
for( VECTOR2I& point : intersectionPoints )
{
aIntersectPoints->push_back( point );
}
}
return intersectionPoints.size() > 0; return intersectionPoints.size() > 0;
} }
bool SegmentIntersectsBoard( const VECTOR2I& aP1, const VECTOR2I& aP2, bool SegmentIntersectsBoard( const VECTOR2I& aP1, const VECTOR2I& aP2,
const std::vector<BOARD_ITEM*>& aBe, const std::vector<BOARD_ITEM*>& aBe,
const std::vector<const BOARD_ITEM*>& aDontTestAgainst ) const std::vector<const BOARD_ITEM*>& aDontTestAgainst,
int aMinGrooveWidth )
{ {
std::vector<VECTOR2I> intersectionPoints;
std::cout << "Path validation: " << ( (float) aMinGrooveWidth ) / 1e6 << std::endl;
bool TestGrooveWidth = aMinGrooveWidth > 0;
for( BOARD_ITEM* be : aBe ) for( BOARD_ITEM* be : aBe )
{ {
if( count( aDontTestAgainst.begin(), aDontTestAgainst.end(), be ) > 0 ) if( count( aDontTestAgainst.begin(), aDontTestAgainst.end(), be ) > 0 )
@ -1749,10 +1776,14 @@ bool SegmentIntersectsBoard( const VECTOR2I& aP1, const VECTOR2I& aP2,
switch( d->GetShape() ) switch( d->GetShape() )
{ {
case SHAPE_T::SEGMENT: case SHAPE_T::SEGMENT:
if( segments_intersect( aP1, aP2, d->GetStart(), d->GetEnd() ) ) {
bool intersects =
segments_intersect( aP1, aP2, d->GetStart(), d->GetEnd(), &intersectionPoints );
if( intersects && !TestGrooveWidth )
return false; return false;
break; break;
}
case SHAPE_T::RECTANGLE: case SHAPE_T::RECTANGLE:
{ {
VECTOR2I c1 = d->GetStart(); VECTOR2I c1 = d->GetStart();
@ -1760,9 +1791,13 @@ bool SegmentIntersectsBoard( const VECTOR2I& aP1, const VECTOR2I& aP2,
VECTOR2I c3 = d->GetEnd(); VECTOR2I c3 = d->GetEnd();
VECTOR2I c4( d->GetEnd().x, d->GetStart().y ); VECTOR2I c4( d->GetEnd().x, d->GetStart().y );
if( segments_intersect( aP1, aP2, c1, c2 ) || segments_intersect( aP1, aP2, c2, c3 ) bool intersects = false;
|| segments_intersect( aP1, aP2, c3, c4 ) intersects |= segments_intersect( aP1, aP2, c1, c2, &intersectionPoints );
|| segments_intersect( aP1, aP2, c4, c1 ) ) intersects |= segments_intersect( aP1, aP2, c2, c3, &intersectionPoints );
intersects |= segments_intersect( aP1, aP2, c3, c4, &intersectionPoints );
intersects |= segments_intersect( aP1, aP2, c4, c1, &intersectionPoints );
if( intersects && !TestGrooveWidth )
{ {
return false; return false;
} }
@ -1777,12 +1812,17 @@ bool SegmentIntersectsBoard( const VECTOR2I& aP1, const VECTOR2I& aP2,
break; break;
VECTOR2I prevPoint = points.back(); VECTOR2I prevPoint = points.back();
bool intersects = false;
for( auto p : points ) for( auto p : points )
{ {
if( segments_intersect( aP1, aP2, prevPoint, p ) ) intersects |= segments_intersect( aP1, aP2, prevPoint, p, &intersectionPoints );
return false;
prevPoint = p; prevPoint = p;
} }
if( intersects && !TestGrooveWidth )
{
return false;
}
break; break;
} }
case SHAPE_T::CIRCLE: case SHAPE_T::CIRCLE:
@ -1790,7 +1830,10 @@ bool SegmentIntersectsBoard( const VECTOR2I& aP1, const VECTOR2I& aP2,
VECTOR2I center = d->GetCenter(); VECTOR2I center = d->GetCenter();
double radius = d->GetRadius(); double radius = d->GetRadius();
if( segmentIntersectsCircle( aP1, aP2, center, radius ) ) bool intersects =
segmentIntersectsCircle( aP1, aP2, center, radius, &intersectionPoints );
if( intersects && !TestGrooveWidth )
return false; return false;
break; break;
@ -1805,7 +1848,10 @@ bool SegmentIntersectsBoard( const VECTOR2I& aP1, const VECTOR2I& aP2,
EDA_ANGLE A, B; EDA_ANGLE A, B;
d->CalcArcAngles( A, B ); d->CalcArcAngles( A, B );
if( segmentIntersectsArc( aP1, aP2, center, radius, A, B ) ) bool intersects =
segmentIntersectsArc( aP1, aP2, center, radius, A, B, &intersectionPoints );
if( intersects && !TestGrooveWidth )
return false; return false;
break; break;
@ -1815,6 +1861,51 @@ bool SegmentIntersectsBoard( const VECTOR2I& aP1, const VECTOR2I& aP2,
default: break; default: break;
} }
} }
if( intersectionPoints.size() <= 0 )
return true;
if( intersectionPoints.size() % 2 != 0 )
return false; // Should not happen if the start and end are both on the board
int minx = intersectionPoints[0].x;
int maxx = intersectionPoints[0].x;
int miny = intersectionPoints[0].y;
int maxy = intersectionPoints[0].y;
for( VECTOR2I v : intersectionPoints )
{
minx = v.x < minx ? v.x : minx;
maxx = v.x > maxx ? v.x : maxx;
miny = v.x < miny ? v.x : miny;
maxy = v.x > maxy ? v.x : maxy;
}
if( abs( maxx - minx ) > abs( maxy - miny ) )
{
std::sort( intersectionPoints.begin(), intersectionPoints.end(),
[]( VECTOR2I a, VECTOR2I b )
{
return a.x > b.x;
} );
}
else
{
std::sort( intersectionPoints.begin(), intersectionPoints.end(),
[]( VECTOR2I a, VECTOR2I b )
{
return a.y > b.y;
} );
}
int GVSquared = aMinGrooveWidth * aMinGrooveWidth;
for( size_t i = 0; i < intersectionPoints.size(); i += 2 )
{
if( intersectionPoints[i].Distance( intersectionPoints[i + 1] ) > aMinGrooveWidth )
{
return false;
}
}
return true; return true;
} }
@ -2225,7 +2316,7 @@ void CreepageGraph::GeneratePaths( double aMaxWeight, PCB_LAYER_ID aLayer,
IgnoreForTest.push_back( gn2->m_parent->GetParent() ); IgnoreForTest.push_back( gn2->m_parent->GetParent() );
if( !pc.isValid( m_board, aLayer, m_boardEdge, IgnoreForTest, m_boardOutline, if( !pc.isValid( m_board, aLayer, m_boardEdge, IgnoreForTest, m_boardOutline,
{ false, true } ) ) { false, true }, m_minGrooveWidth ) )
continue; continue;
GraphNode* connect1; GraphNode* connect1;

View File

@ -47,9 +47,8 @@
extern bool SegmentIntersectsBoard( const VECTOR2I& aP1, const VECTOR2I& aP2, extern bool SegmentIntersectsBoard( const VECTOR2I& aP1, const VECTOR2I& aP2,
const std::vector<BOARD_ITEM*>& aBe, const std::vector<BOARD_ITEM*>& aBe,
const std::vector<const BOARD_ITEM*>& aDontTestAgainst ); const std::vector<const BOARD_ITEM*>& aDontTestAgainst,
bool segmentIntersectsArc( const VECTOR2I& p1, const VECTOR2I& p2, const VECTOR2I& center, int aMinGrooveWidth );
double radius, double startAngle, double endAngle );
struct path_connection struct path_connection
{ {
@ -69,12 +68,12 @@ struct path_connection
bool isValid( const BOARD& aBoard, PCB_LAYER_ID aLayer, bool isValid( const BOARD& aBoard, PCB_LAYER_ID aLayer,
const std::vector<BOARD_ITEM*>& aBoardEdges, const std::vector<BOARD_ITEM*>& aBoardEdges,
const std::vector<const BOARD_ITEM*>& aIgnoreForTest, SHAPE_POLY_SET* aOutline, const std::vector<const BOARD_ITEM*>& aIgnoreForTest, SHAPE_POLY_SET* aOutline,
const std::pair<bool, bool>& aTestLocalConcavity ) const std::pair<bool, bool>& aTestLocalConcavity, int aMinGrooveWidth )
{ {
if( !aOutline ) if( !aOutline )
return true; // We keep the segment if there is a problem return true; // We keep the segment if there is a problem
if( !SegmentIntersectsBoard( a1, a2, aBoardEdges, aIgnoreForTest ) ) if( !SegmentIntersectsBoard( a1, a2, aBoardEdges, aIgnoreForTest, aMinGrooveWidth ) )
return false; return false;
// The mid point should be inside the board. // The mid point should be inside the board.

View File

@ -54,7 +54,7 @@ protected:
BOARD* m_board; BOARD* m_board;
bool m_boardOutlineValid; bool m_boardOutlineValid;
void ReportAndShowPathCuToCu( std::shared_ptr<DRC_ITEM>& item, const VECTOR2I& aMarkerPos, void ReportAndShowPathCuToCu( std::shared_ptr<DRC_ITEM>& aDrce, const VECTOR2I& aMarkerPos,
int aMarkerLayer, const BOARD_ITEM* aItem1, int aMarkerLayer, const BOARD_ITEM* aItem1,
const BOARD_ITEM* aItem2, PCB_LAYER_ID layer, int aDistance ); const BOARD_ITEM* aItem2, PCB_LAYER_ID layer, int aDistance );

View File

@ -344,6 +344,7 @@ int DRC_TEST_PROVIDER_CREEPAGE::testCreepage()
const DRAWINGS drawings = m_board->Drawings(); const DRAWINGS drawings = m_board->Drawings();
CreepageGraph graph( *m_board ); CreepageGraph graph( *m_board );
graph.m_minGrooveWidth = m_board->GetDesignSettings().m_MinGrooveWidth;
graph.m_boardOutline = &outline; graph.m_boardOutline = &outline;
this->CollectBoardEdges( graph.m_boardEdge ); this->CollectBoardEdges( graph.m_boardEdge );