Browse Source

Simplify annotation graphics for DRC markers.

Also includes some performance tweaks, mostly around
not copying large structures.
master
Jeff Young 2 weeks ago
parent
commit
ac775e716f
  1. 3
      common/layer_id.cpp
  2. 3
      common/lset.cpp
  3. 4
      include/layer_ids.h
  4. 6
      libs/kimath/include/geometry/shape.h
  5. 7
      libs/kimath/include/geometry/shape_arc.h
  6. 2
      libs/kimath/include/geometry/shape_line_chain.h
  7. 2
      libs/kimath/include/geometry/shape_rect.h
  8. 7
      libs/kimath/include/geometry/shape_segment.h
  9. 502
      pcbnew/drc/drc_creepage_utils.cpp
  10. 56
      pcbnew/drc/drc_creepage_utils.h
  11. 4
      pcbnew/drc/drc_engine.cpp
  12. 11
      pcbnew/drc/drc_engine.h
  13. 4
      pcbnew/drc/drc_test_provider.cpp
  14. 3
      pcbnew/drc/drc_test_provider.h
  15. 88
      pcbnew/drc/drc_test_provider_clearance_base.cpp
  16. 5
      pcbnew/drc/drc_test_provider_clearance_base.h
  17. 72
      pcbnew/drc/drc_test_provider_creepage.cpp
  18. 17
      pcbnew/pcb_draw_panel_gal.cpp
  19. 14
      pcbnew/pcb_marker.cpp
  20. 13
      pcbnew/pcb_marker.h
  21. 64
      pcbnew/pcb_painter.cpp
  22. 5
      pcbnew/pcbnew_jobs_handler.cpp
  23. 3
      pcbnew/pcbnew_printout.cpp
  24. 4
      pcbnew/python/scripting/pcbnew_scripting_helpers.cpp
  25. 7
      pcbnew/tools/drc_tool.cpp
  26. 4
      qa/tests/pcbnew/drc/test_custom_rule_severities.cpp
  27. 4
      qa/tests/pcbnew/drc/test_drc_component_classes.cpp
  28. 4
      qa/tests/pcbnew/drc/test_drc_copper_conn.cpp
  29. 4
      qa/tests/pcbnew/drc/test_drc_copper_graphics.cpp
  30. 4
      qa/tests/pcbnew/drc/test_drc_copper_sliver.cpp
  31. 4
      qa/tests/pcbnew/drc/test_drc_courtyard_invalid.cpp
  32. 4
      qa/tests/pcbnew/drc/test_drc_courtyard_overlap.cpp
  33. 4
      qa/tests/pcbnew/drc/test_drc_incorrect_text_mirror.cpp
  34. 4
      qa/tests/pcbnew/drc/test_drc_lengths.cpp
  35. 4
      qa/tests/pcbnew/drc/test_drc_multi_netclasses.cpp
  36. 4
      qa/tests/pcbnew/drc/test_drc_orientation.cpp
  37. 8
      qa/tests/pcbnew/drc/test_drc_regressions.cpp
  38. 4
      qa/tests/pcbnew/drc/test_drc_skew.cpp
  39. 4
      qa/tests/pcbnew/drc/test_drc_starved_thermal.cpp
  40. 4
      qa/tests/pcbnew/drc/test_drc_via_dangling.cpp
  41. 4
      qa/tests/pcbnew/drc/test_solder_mask_bridging.cpp
  42. 4
      qa/tests/pcbnew/test_tracks_cleaner.cpp
  43. 12
      qa/tests/pcbnew/test_zone_filler.cpp
  44. 4
      qa/tools/drc_proto/drc_proto.cpp

3
common/layer_id.cpp

@ -137,8 +137,7 @@ wxString LayerName( int aLayer )
case LAYER_RATSNEST: return _( "Ratsnest" );
case LAYER_DRC_WARNING: return _( "DRC warnings" );
case LAYER_DRC_ERROR: return _( "DRC errors" );
case LAYER_DRC_SHAPE1: return _( "DRC shape 1" );
case LAYER_DRC_SHAPE2: return _( "DRC shape 2" );
case LAYER_DRC_SHAPES: return _( "DRC shapes" );
case LAYER_DRC_EXCLUSION: return _( "DRC exclusions" );
case LAYER_MARKER_SHADOWS: return _( "DRC marker shadows" );
case LAYER_ANCHOR: return _( "Anchors" );

3
common/lset.cpp

@ -791,8 +791,7 @@ GAL_SET GAL_SET::DefaultVisible()
LAYER_VIA_HOLEWALLS,
LAYER_DRC_ERROR,
LAYER_DRC_WARNING,
LAYER_DRC_SHAPE1,
LAYER_DRC_SHAPE2,
LAYER_DRC_SHAPES,
// LAYER_DRC_EXCLUSION, // DRC exclusions hidden by default
LAYER_DRAWINGSHEET,
LAYER_GP_OVERLAY,

4
include/layer_ids.h

@ -311,8 +311,8 @@ enum GAL_LAYER_ID: int
/// Copper graphic shape opacity/visibility (color ignored).
LAYER_FILLED_SHAPES = GAL_LAYER_ID_START + 41,
LAYER_DRC_SHAPE1 = GAL_LAYER_ID_START + 42, ///< Custom shape for DRC marker.
LAYER_DRC_SHAPE2 = GAL_LAYER_ID_START + 43, ///< Custom shape for DRC marker.
LAYER_DRC_SHAPES = GAL_LAYER_ID_START + 42, ///< Custom shapes for DRC markers.
// LAYER_DRC_SHAPE2 = GAL_LAYER_ID_START + 43, ///< Deprecated since 10.0
LAYER_BOARD_OUTLINE_AREA = GAL_LAYER_ID_START + 44, ///< PCB board outline

6
libs/kimath/include/geometry/shape.h

@ -283,6 +283,12 @@ public:
*/
virtual void Rotate( const EDA_ANGLE& aAngle, const VECTOR2I& aCenter = { 0, 0 } ) = 0;
virtual VECTOR2I GetStart() const { return {}; }
virtual VECTOR2I GetEnd() const { return {}; }
virtual int GetWidth() const { return 0; }
virtual void SetWidth( int aWidth ) {}
virtual void Move( const VECTOR2I& aVector ) = 0;
virtual bool IsSolid() const = 0;

7
libs/kimath/include/geometry/shape_arc.h

@ -202,12 +202,15 @@ public:
*/
int Intersect( const SHAPE_ARC& aArc, std::vector<VECTOR2I>* aIpsBuffer ) const;
void SetWidth( int aWidth )
VECTOR2I GetStart() const override { return m_start; }
VECTOR2I GetEnd() const override { return m_end; }
void SetWidth( int aWidth ) override
{
m_width = aWidth;
}
int GetWidth() const
int GetWidth() const override
{
return m_width;
}

2
libs/kimath/include/geometry/shape_line_chain.h

@ -308,7 +308,7 @@ public:
*
* @param aWidth is the width in internal units.
*/
void SetWidth( int aWidth )
void SetWidth( int aWidth ) override
{
m_width = aWidth;
}

2
libs/kimath/include/geometry/shape_rect.h

@ -182,7 +182,7 @@ public:
/**
* @return the width of the rectangle.
*/
int GetWidth() const
int GetWidth() const override
{
return m_w;
}

7
libs/kimath/include/geometry/shape_segment.h

@ -132,12 +132,15 @@ public:
return m_seg;
}
void SetWidth( int aWidth )
VECTOR2I GetStart() const override { return m_seg.A; }
VECTOR2I GetEnd() const override { return m_seg.B; }
void SetWidth( int aWidth ) override
{
m_width = aWidth;
}
int GetWidth() const
int GetWidth() const override
{
return m_width;
}

502
pcbnew/drc/drc_creepage_utils.cpp

@ -25,15 +25,42 @@
#include <thread_pool.h>
extern bool segmentIntersectsArc( const VECTOR2I& p1, const VECTOR2I& p2, const VECTOR2I& center,
double radius, EDA_ANGLE startAngle, EDA_ANGLE endAngle,
std::vector<VECTOR2I>* aIntersectPoints );
bool segmentIntersectsArc( const VECTOR2I& p1, const VECTOR2I& p2, const VECTOR2I& center,
double radius, EDA_ANGLE startAngle, EDA_ANGLE endAngle,
std::vector<VECTOR2I>* aIntersectionPoints = nullptr )
{
SEG segment( p1, p2 );
VECTOR2I startPoint( radius * cos( startAngle.AsRadians() ), radius * sin( startAngle.AsRadians() ) );
SHAPE_ARC arc( center, startPoint + center, endAngle - startAngle );
INTERSECTABLE_GEOM geom1 = segment;
INTERSECTABLE_GEOM geom2 = arc;
if( aIntersectionPoints )
{
size_t startCount = aIntersectionPoints->size();
INTERSECTION_VISITOR visitor( geom2, *aIntersectionPoints );
std::visit( visitor, geom1 );
return aIntersectionPoints->size() > startCount;
}
else
{
std::vector<VECTOR2I> intersectionPoints;
INTERSECTION_VISITOR visitor( geom2, intersectionPoints );
std::visit( visitor, geom1 );
return intersectionPoints.size() > 0;
}
}
//Check if line segments 'p1q1' and 'p2q2' intersect, excluding endpoint overlap
bool segments_intersect( VECTOR2I p1, VECTOR2I q1, VECTOR2I p2, VECTOR2I q2,
std::vector<VECTOR2I>* aIntersectPoints )
bool segments_intersect( const VECTOR2I& p1, const VECTOR2I& q1, const VECTOR2I& p2, const VECTOR2I& q2,
std::vector<VECTOR2I>& aIntersectionPoints )
{
if( p1 == p2 || p1 == q2 || q1 == p2 || q1 == q2 )
return false;
@ -41,24 +68,15 @@ bool segments_intersect( VECTOR2I p1, VECTOR2I q1, VECTOR2I p2, VECTOR2I q2,
SEG segment1( p1, q1 );
SEG segment2( p2, q2 );
std::vector<VECTOR2I> intersectionPoints;
INTERSECTABLE_GEOM geom1 = segment1;
INTERSECTABLE_GEOM geom2 = segment2;
INTERSECTION_VISITOR visitor( geom2, intersectionPoints );
size_t startCount = aIntersectionPoints.size();
INTERSECTION_VISITOR visitor( geom2, aIntersectionPoints );
std::visit( visitor, geom1 );
if( aIntersectPoints )
{
for( VECTOR2I& point : intersectionPoints )
aIntersectPoints->push_back( point );
}
return intersectionPoints.size() > 0;
return aIntersectionPoints.size() > startCount;
}
@ -66,53 +84,43 @@ bool compareShapes( const CREEP_SHAPE* a, const CREEP_SHAPE* b )
{
if( !a )
return true;
if( !b )
return false;
if( a->GetType() != b->GetType() )
{
return a->GetType() < b->GetType();
}
if( a->GetType() == CREEP_SHAPE::TYPE::UNDEFINED )
return true;
auto posA = a->GetPos();
auto posB = b->GetPos();
if( a->GetPos() != b->GetPos() )
return a->GetPos() < b->GetPos();
if( posA != posB )
{
return posA < posB;
}
if( a->GetType() == CREEP_SHAPE::TYPE::CIRCLE )
{
return a->GetRadius() < b->GetRadius();
}
return false;
}
bool areEquivalent( const CREEP_SHAPE* a, const CREEP_SHAPE* b )
{
if( !a && !b )
{
return true;
}
if( ( !a && b ) || ( a && !b ) )
{
if( !a || !b )
return false;
}
if( a->GetType() != b->GetType() )
{
return false;
}
if( a->GetType() == CREEP_SHAPE::TYPE::POINT )
{
return a->GetPos() == b->GetPos();
}
if( a->GetType() == CREEP_SHAPE::TYPE::CIRCLE )
{
return a->GetPos() == b->GetPos() && ( a->GetRadius() == b->GetRadius() );
}
return false;
}
@ -136,6 +144,7 @@ std::vector<PATH_CONNECTION> BE_SHAPE_POINT::Paths( const BE_SHAPE_POINT& aS2, d
return result;
}
std::vector<PATH_CONNECTION> BE_SHAPE_POINT::Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const
{
@ -145,9 +154,7 @@ std::vector<PATH_CONNECTION> BE_SHAPE_POINT::Paths( const BE_SHAPE_CIRCLE& aS2,
VECTOR2I circleCenter = aS2.GetPos();
if( radius <= 0 )
{
return result;
}
double pointToCenterDistanceSquared = ( pointPos - circleCenter ).SquaredEuclideanNorm();
double weightSquared = pointToCenterDistanceSquared - (float) radius * (float) radius;
@ -155,7 +162,6 @@ std::vector<PATH_CONNECTION> BE_SHAPE_POINT::Paths( const BE_SHAPE_CIRCLE& aS2,
if( weightSquared > aMaxSquaredWeight )
return result;
VECTOR2D direction1 = VECTOR2D( pointPos.x - circleCenter.x, pointPos.y - circleCenter.y );
direction1 = direction1.Resize( 1 );
@ -186,8 +192,8 @@ std::vector<PATH_CONNECTION> BE_SHAPE_POINT::Paths( const BE_SHAPE_CIRCLE& aS2,
return result;
}
std::pair<bool, bool>
BE_SHAPE_ARC::IsThereATangentPassingThroughPoint( const BE_SHAPE_POINT aPoint ) const
std::pair<bool, bool> BE_SHAPE_ARC::IsThereATangentPassingThroughPoint( const BE_SHAPE_POINT aPoint ) const
{
std::pair<bool, bool> result;
double R = m_radius;
@ -219,23 +225,21 @@ BE_SHAPE_ARC::IsThereATangentPassingThroughPoint( const BE_SHAPE_POINT aPoint )
connectToEndPoint |= ( cos( endAngle ) * newPoint.x + sin( endAngle ) * newPoint.y <= R )
&& ( pointAngle >= endAngle || pointAngle <= startAngle );
result.first = !connectToEndPoint;
connectToEndPoint = ( cos( endAngle ) * newPoint.x + sin( endAngle ) * newPoint.y >= R );
if( greaterThan180 )
connectToEndPoint &=
( cos( startAngle ) * newPoint.x + sin( startAngle ) * newPoint.y <= R );
connectToEndPoint &= ( cos( startAngle ) * newPoint.x + sin( startAngle ) * newPoint.y <= R );
connectToEndPoint |= ( cos( startAngle ) * newPoint.x + sin( startAngle ) * newPoint.y <= R )
&& ( pointAngle >= endAngle || pointAngle <= startAngle );
result.second = !connectToEndPoint;
return result;
}
std::vector<PATH_CONNECTION> BE_SHAPE_POINT::Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const
{
@ -269,15 +273,14 @@ std::vector<PATH_CONNECTION> BE_SHAPE_POINT::Paths( const BE_SHAPE_ARC& aS2, dou
for( const PATH_CONNECTION& pc : this->Paths( csp1, aMaxWeight, aMaxSquaredWeight ) )
result.push_back( pc );
}
if( behavesLikeCircle.second )
{
BE_SHAPE_CIRCLE csc( center, radius );
std::vector<PATH_CONNECTION> paths = this->Paths( csc, aMaxWeight, aMaxSquaredWeight );
if( paths.size() > 1 ) // Point to circle creates either 0 or 2 connections
{
result.push_back( paths[0] );
}
}
else
{
@ -286,6 +289,7 @@ std::vector<PATH_CONNECTION> BE_SHAPE_POINT::Paths( const BE_SHAPE_ARC& aS2, dou
for( const PATH_CONNECTION& pc : this->Paths( csp1, aMaxWeight, aMaxSquaredWeight ) )
result.push_back( pc );
}
return result;
}
@ -312,7 +316,6 @@ std::vector<PATH_CONNECTION> BE_SHAPE_CIRCLE::Paths( const BE_SHAPE_ARC& aS2, do
BE_SHAPE_POINT csp2( aS2.GetEndPoint() );
BE_SHAPE_CIRCLE csc( arcCenter, arcRadius );
for( const PATH_CONNECTION& pc : this->Paths( csc, aMaxWeight, aMaxSquaredWeight ) )
{
EDA_ANGLE pointAngle = aS2.AngleBetweenStartAndEnd( pc.a2 - arcCenter );
@ -329,17 +332,13 @@ std::vector<PATH_CONNECTION> BE_SHAPE_CIRCLE::Paths( const BE_SHAPE_ARC& aS2, do
for( const BE_SHAPE_POINT& csp : { csp1, csp2 } )
{
for( PATH_CONNECTION pc : this->Paths( csp, aMaxWeight, aMaxSquaredWeight ) )
for( const PATH_CONNECTION& pc : this->Paths( csp, aMaxWeight, aMaxSquaredWeight ) )
{
if( !segmentIntersectsArc( pc.a1, pc.a2, arcCenter, arcRadius, arcStartAngle,
arcEndAngle, nullptr ) )
{
if( !segmentIntersectsArc( pc.a1, pc.a2, arcCenter, arcRadius, arcStartAngle, arcEndAngle ) )
result.push_back( pc );
}
}
}
return result;
}
@ -585,24 +584,20 @@ void CREEPAGE_GRAPH::TransformEdgeToCreepShapes()
}
std::vector<PCB_SHAPE> GRAPH_CONNECTION::GetShapes()
void GRAPH_CONNECTION::GetShapes( std::vector<PCB_SHAPE>& aShapes )
{
std::vector<PCB_SHAPE> shapes = std::vector<PCB_SHAPE>();
int lineWidth = 0;
if( !m_path.m_show )
return shapes;
return;
if( !n1 || !n2 )
return shapes;
return;
if( n1->m_type == GRAPH_NODE::TYPE::VIRTUAL || n2->m_type == GRAPH_NODE::TYPE::VIRTUAL )
{
return shapes;
}
return;
if( !m_forceStraightLine && n1->m_parent && ( n1->m_parent == n2->m_parent )
&& ( n1->m_parent->GetType() == CREEP_SHAPE::TYPE::CIRCLE ) )
if( !m_forceStraightLine && n1->m_parent
&& n1->m_parent == n2->m_parent
&& n1->m_parent->GetType() == CREEP_SHAPE::TYPE::CIRCLE )
{
VECTOR2I center = n1->m_parent->GetPos();
VECTOR2I R1 = n1->m_pos - center;
@ -619,84 +614,61 @@ std::vector<PCB_SHAPE> GRAPH_CONNECTION::GetShapes()
s.SetStart( n2->m_pos );
s.SetEnd( n1->m_pos );
}
s.SetCenter( center );
s.SetWidth( lineWidth );
s.SetLayer( Eco1_User );
shapes.push_back( s );
return shapes;
s.SetCenter( center );
aShapes.push_back( s );
return;
}
else if( !m_forceStraightLine && n1->m_parent && ( n1->m_parent == n2->m_parent )
&& n1->m_parent->GetType() == CREEP_SHAPE::TYPE::ARC )
if( !m_forceStraightLine && n1->m_parent
&& n1->m_parent == n2->m_parent
&& n1->m_parent->GetType() == CREEP_SHAPE::TYPE::ARC )
{
BE_SHAPE_ARC* arc = dynamic_cast<BE_SHAPE_ARC*>( n1->m_parent );
if( !arc )
if( BE_SHAPE_ARC* arc = dynamic_cast<BE_SHAPE_ARC*>( n1->m_parent ) )
{
PCB_SHAPE s;
s.SetStart( m_path.a1 );
s.SetEnd( m_path.a2 );
s.SetWidth( lineWidth );
s.SetLayer( Eco1_User );
shapes.push_back( s );
return shapes;
}
VECTOR2I center = arc->GetPos();
VECTOR2I R1 = n1->m_pos - center;
VECTOR2I R2 = n2->m_pos - center;
PCB_SHAPE s( nullptr, SHAPE_T::ARC );
VECTOR2I center = arc->GetPos();
VECTOR2I R1 = n1->m_pos - center;
VECTOR2I R2 = n2->m_pos - center;
PCB_SHAPE s( nullptr, SHAPE_T::ARC );
if( R1.Cross( R2 ) > 0 )
{
s.SetStart( n1->m_pos );
s.SetEnd( n2->m_pos );
}
else
{
s.SetStart( n2->m_pos );
s.SetEnd( n1->m_pos );
}
if( R1.Cross( R2 ) > 0 )
{
s.SetStart( n1->m_pos );
s.SetEnd( n2->m_pos );
}
else
{
s.SetStart( n2->m_pos );
s.SetEnd( n1->m_pos );
}
s.SetCenter( center );
s.SetCenter( center );
//Check that we are on the correct side of the arc.
VECTOR2I mid = s.GetArcMid();
EDA_ANGLE midAngle = arc->AngleBetweenStartAndEnd( mid );
//Check that we are on the correct side of the arc.
VECTOR2I mid = s.GetArcMid();
EDA_ANGLE midAngle = arc->AngleBetweenStartAndEnd( mid );
if( midAngle > arc->GetEndAngle() )
{
VECTOR2I tmp;
tmp = s.GetStart();
s.SetStart( s.GetEnd() );
s.SetEnd( tmp );
s.SetCenter( center );
}
if( midAngle > arc->GetEndAngle() )
{
VECTOR2I tmp;
tmp = s.GetStart();
s.SetStart( s.GetEnd() );
s.SetEnd( tmp );
s.SetCenter( center );
aShapes.push_back( s );
return;
}
s.SetWidth( lineWidth );
s.SetLayer( Eco1_User );
shapes.push_back( s );
return shapes;
}
PCB_SHAPE s;
PCB_SHAPE s( nullptr, SHAPE_T::SEGMENT );
s.SetStart( m_path.a1 );
s.SetEnd( m_path.a2 );
s.SetWidth( lineWidth );
shapes.push_back( s );
return shapes;
aShapes.push_back( s );
}
void CREEP_SHAPE::ConnectChildren( std::shared_ptr<GRAPH_NODE>& a1, std::shared_ptr<GRAPH_NODE>&,
CREEPAGE_GRAPH& aG ) const
{
@ -708,9 +680,9 @@ void BE_SHAPE_POINT::ConnectChildren( std::shared_ptr<GRAPH_NODE>& a1, std::shar
{
}
void BE_SHAPE_CIRCLE::ShortenChildDueToGV( std::shared_ptr<GRAPH_NODE>& a1,
std::shared_ptr<GRAPH_NODE>& a2, CREEPAGE_GRAPH& aG,
double aNormalWeight ) const
void BE_SHAPE_CIRCLE::ShortenChildDueToGV( std::shared_ptr<GRAPH_NODE>& a1, std::shared_ptr<GRAPH_NODE>& a2,
CREEPAGE_GRAPH& aG, double aNormalWeight ) const
{
EDA_ANGLE angle1 = EDA_ANGLE( a1->m_pos - m_pos );
EDA_ANGLE angle2 = EDA_ANGLE( a2->m_pos - m_pos );
@ -724,7 +696,6 @@ void BE_SHAPE_CIRCLE::ShortenChildDueToGV( std::shared_ptr<GRAPH_NODE>& a1,
while( angle2 > ANGLE_360 )
angle2 -= ANGLE_360;
EDA_ANGLE maxAngle = angle1 > angle2 ? angle1 : angle2;
EDA_ANGLE skipAngle =
EDA_ANGLE( asin( float( aG.m_minGrooveWidth ) / ( 2 * m_radius ) ), RADIANS_T );
@ -735,7 +706,6 @@ void BE_SHAPE_CIRCLE::ShortenChildDueToGV( std::shared_ptr<GRAPH_NODE>& a1,
skipPoint.x += m_radius * cos( pointAngle.AsRadians() );
skipPoint.y += m_radius * sin( pointAngle.AsRadians() );
std::shared_ptr<GRAPH_NODE> gnt = aG.AddNode( GRAPH_NODE::POINT, a1->m_parent, skipPoint );
PATH_CONNECTION pc;
@ -755,8 +725,9 @@ void BE_SHAPE_CIRCLE::ShortenChildDueToGV( std::shared_ptr<GRAPH_NODE>& a1,
gc->m_forceStraightLine = true;
}
void BE_SHAPE_CIRCLE::ConnectChildren( std::shared_ptr<GRAPH_NODE>& a1,
std::shared_ptr<GRAPH_NODE>& a2, CREEPAGE_GRAPH& aG ) const
void BE_SHAPE_CIRCLE::ConnectChildren( std::shared_ptr<GRAPH_NODE>& a1, std::shared_ptr<GRAPH_NODE>& a2,
CREEPAGE_GRAPH& aG ) const
{
if( !a1 || !a2 )
return;
@ -769,7 +740,7 @@ void BE_SHAPE_CIRCLE::ConnectChildren( std::shared_ptr<GRAPH_NODE>& a1,
double weight = m_radius * 2 * asin( distD.EuclideanNorm() / ( 2.0 * m_radius ) );
if( ( weight > aG.GetTarget() ) )
if( weight > aG.GetTarget() )
return;
if( aG.m_minGrooveWidth <= 0 )
@ -818,38 +789,13 @@ void BE_SHAPE_ARC::ConnectChildren( std::shared_ptr<GRAPH_NODE>& a1, std::shared
ShortenChildDueToGV( a1, a2, aG, weight );
}
void CREEPAGE_GRAPH::SetTarget( double aTarget )
{
m_creepageTarget = aTarget;
m_creepageTargetSquared = aTarget * aTarget;
}
bool segmentIntersectsArc( const VECTOR2I& p1, const VECTOR2I& p2, const VECTOR2I& center,
double radius, EDA_ANGLE startAngle, EDA_ANGLE endAngle,
std::vector<VECTOR2I>* aIntersectPoints )
{
SEG segment( p1, p2 );
VECTOR2I startPoint( radius * cos( startAngle.AsRadians() ),
radius * sin( startAngle.AsRadians() ) );
startPoint += center;
SHAPE_ARC arc( center, startPoint, endAngle - startAngle );
std::vector<VECTOR2I> intersectionPoints;
INTERSECTABLE_GEOM geom1 = segment;
INTERSECTABLE_GEOM geom2 = arc;
INTERSECTION_VISITOR visitor( geom2, intersectionPoints );
std::visit( visitor, geom1 );
if( aIntersectPoints )
{
for( VECTOR2I& point : intersectionPoints )
aIntersectPoints->push_back( point );
}
return intersectionPoints.size() > 0;
}
std::vector<PATH_CONNECTION> CU_SHAPE_SEGMENT::Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const
@ -1059,20 +1005,14 @@ std::vector<PATH_CONNECTION> CU_SHAPE_SEGMENT::Paths( const BE_SHAPE_ARC& aS2, d
for( const PATH_CONNECTION& pc : this->Paths( bsp1, aMaxWeight, aMaxSquaredWeight ) )
{
if( !segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle,
beArcEndAngle, nullptr ) )
{
if( !segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle, beArcEndAngle ) )
result.push_back( pc );
}
}
for( const PATH_CONNECTION& pc : this->Paths( bsp2, aMaxWeight, aMaxSquaredWeight ) )
{
if( !segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle,
beArcEndAngle, nullptr ) )
{
if( !segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle, beArcEndAngle ) )
result.push_back( pc );
}
}
}
@ -1106,25 +1046,21 @@ std::vector<PATH_CONNECTION> CU_SHAPE_CIRCLE::Paths( const BE_SHAPE_ARC& aS2, do
for( const PATH_CONNECTION& pc : this->Paths( bsp1, aMaxWeight, aMaxSquaredWeight ) )
{
if( !segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle,
beArcEndAngle, nullptr ) )
{
if( !segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle, beArcEndAngle ) )
result.push_back( pc );
}
}
for( const PATH_CONNECTION& pc : this->Paths( bsp2, aMaxWeight, aMaxSquaredWeight ) )
{
if( !segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle,
beArcEndAngle, nullptr ) )
{
if( !segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle, beArcEndAngle ) )
result.push_back( pc );
}
}
}
return result;
}
std::vector<PATH_CONNECTION> CU_SHAPE_ARC::Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const
{
@ -1182,20 +1118,14 @@ std::vector<PATH_CONNECTION> CU_SHAPE_ARC::Paths( const BE_SHAPE_ARC& aS2, doubl
for( const PATH_CONNECTION& pc : this->Paths( bsp1, aMaxWeight, aMaxSquaredWeight ) )
{
if( !segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle,
beArcEndAngle, nullptr ) )
{
if( !segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle, beArcEndAngle ) )
result.push_back( pc );
}
}
for( const PATH_CONNECTION& pc : this->Paths( bsp2, aMaxWeight, aMaxSquaredWeight ) )
{
if( !segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle,
beArcEndAngle, nullptr ) )
{
if( !segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle, beArcEndAngle ) )
result.push_back( pc );
}
}
}
@ -1755,7 +1685,7 @@ bool SegmentIntersectsBoard( const VECTOR2I& aP1, const VECTOR2I& aP2,
case SHAPE_T::SEGMENT:
{
bool intersects = segments_intersect( aP1, aP2, d->GetStart(), d->GetEnd(),
&intersectionPoints );
intersectionPoints );
if( intersects && !TestGrooveWidth )
return false;
@ -1771,10 +1701,10 @@ bool SegmentIntersectsBoard( const VECTOR2I& aP1, const VECTOR2I& aP2,
VECTOR2I c4( d->GetEnd().x, d->GetStart().y );
bool intersects = false;
intersects |= segments_intersect( aP1, aP2, c1, c2, &intersectionPoints );
intersects |= segments_intersect( aP1, aP2, c2, c3, &intersectionPoints );
intersects |= segments_intersect( aP1, aP2, c3, c4, &intersectionPoints );
intersects |= segments_intersect( aP1, aP2, c4, c1, &intersectionPoints );
intersects |= segments_intersect( aP1, aP2, c1, c2, intersectionPoints );
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;
@ -1796,7 +1726,7 @@ bool SegmentIntersectsBoard( const VECTOR2I& aP1, const VECTOR2I& aP2,
for( const VECTOR2I& p : points )
{
intersects |= segments_intersect( aP1, aP2, prevPoint, p, &intersectionPoints );
intersects |= segments_intersect( aP1, aP2, prevPoint, p, intersectionPoints );
prevPoint = p;
}
@ -1954,7 +1884,6 @@ std::vector<PATH_CONNECTION> GetPaths( CREEP_SHAPE* aS1, CREEP_SHAPE* aS2, doubl
// Reversed
if( cuarc2 && bearc1 )
return bearc1->Paths( *cuarc2, maxWeight, maxWeightSquared );
if( cuarc2 && becircle1 )
@ -2049,7 +1978,7 @@ double CREEPAGE_GRAPH::Solve( std::shared_ptr<GRAPH_NODE>& aFrom, std::shared_pt
for( const std::shared_ptr<GRAPH_CONNECTION>& connection : current->m_node_conns )
{
GRAPH_NODE* neighbor = ( connection->n1 ).get() == current ? ( connection->n2 ).get()
: ( connection->n1 ).get();
: ( connection->n1 ).get();
if( !neighbor )
continue;
@ -2061,7 +1990,6 @@ double CREEPAGE_GRAPH::Solve( std::shared_ptr<GRAPH_NODE>& aFrom, std::shared_pt
continue;
}
double alt = distances[current] + connection->m_path.weight; // Calculate alternative path cost
if( alt < distances[neighbor] )
@ -2252,18 +2180,17 @@ void CREEPAGE_GRAPH::GeneratePaths( double aMaxWeight, PCB_LAYER_ID aLayer )
thread_pool& tp = GetKiCadThreadPool();
std::copy_if( m_nodes.begin(), m_nodes.end(), std::back_inserter( nodes ),
[&]( const std::shared_ptr<GRAPH_NODE>& gn )
{
return !!gn && gn->m_parent && gn->m_connectDirectly
&& ( gn->m_type != GRAPH_NODE::TYPE::VIRTUAL );
} );
[&]( const std::shared_ptr<GRAPH_NODE>& gn )
{
return gn && gn->m_parent && gn->m_connectDirectly && ( gn->m_type != GRAPH_NODE::TYPE::VIRTUAL );
} );
std::sort( nodes.begin(), nodes.end(),
[]( const std::shared_ptr<GRAPH_NODE>& gn1, const std::shared_ptr<GRAPH_NODE>& gn2 )
{
return ( gn1->m_parent < gn2->m_parent ) || ( gn1->m_parent == gn2->m_parent
&& gn1->m_net < gn2->m_net );
} );
[]( const std::shared_ptr<GRAPH_NODE>& gn1, const std::shared_ptr<GRAPH_NODE>& gn2 )
{
return gn1->m_parent < gn2->m_parent
|| ( gn1->m_parent == gn2->m_parent && gn1->m_net < gn2->m_net );
} );
// Build parent -> net -> nodes mapping for efficient filtering
std::unordered_map<const BOARD_ITEM*, std::unordered_map<int, std::vector<std::shared_ptr<GRAPH_NODE>>>> parent_net_groups;
@ -2280,10 +2207,7 @@ void CREEPAGE_GRAPH::GeneratePaths( double aMaxWeight, PCB_LAYER_ID aLayer )
}
// Generate work items: compare nodes between different parents only
struct WorkItem {
std::shared_ptr<GRAPH_NODE> node1, node2;
};
std::vector<WorkItem> work_items;
std::vector<std::pair<std::shared_ptr<GRAPH_NODE>, std::shared_ptr<GRAPH_NODE>>> work_items;
for( size_t i = 0; i < parent_keys.size(); ++i )
{
@ -2300,9 +2224,16 @@ void CREEPAGE_GRAPH::GeneratePaths( double aMaxWeight, PCB_LAYER_ID aLayer )
if( net1 == net2 )
{
bool all_conductive_1 = std::all_of( nodes1.begin(), nodes1.end(),
[]( const auto& n ) { return n->m_parent->IsConductive(); } );
[]( const auto& n )
{
return n->m_parent->IsConductive();
} );
bool all_conductive_2 = std::all_of( nodes2.begin(), nodes2.end(),
[]( const auto& n ) { return n->m_parent->IsConductive(); } );
[]( const auto& n )
{
return n->m_parent->IsConductive();
} );
if( all_conductive_1 && all_conductive_2 )
continue;
@ -2310,63 +2241,69 @@ void CREEPAGE_GRAPH::GeneratePaths( double aMaxWeight, PCB_LAYER_ID aLayer )
// Add all node pairs from these net groups
for( const auto& gn1 : nodes1 )
{
for( const auto& gn2 : nodes2 )
work_items.push_back( { gn1, gn2 } );
}
}
}
}
}
auto processWorkItems = [&]( size_t idx ) -> bool
{
auto [gn1, gn2] = work_items[idx];
for( PATH_CONNECTION pc : GetPaths( gn1->m_parent, gn2->m_parent, aMaxWeight ) )
{
std::vector<const BOARD_ITEM*> IgnoreForTest = {
gn1->m_parent->GetParent(), gn2->m_parent->GetParent()
};
auto processWorkItems =
[&]( size_t idx ) -> bool
{
auto& [gn1, gn2] = work_items[idx];
if( !pc.isValid( m_board, aLayer, m_boardEdge, IgnoreForTest, m_boardOutline,
{ false, true }, m_minGrooveWidth ) )
continue;
for( const PATH_CONNECTION& pc : GetPaths( gn1->m_parent, gn2->m_parent, aMaxWeight ) )
{
std::vector<const BOARD_ITEM*> IgnoreForTest =
{
gn1->m_parent->GetParent(), gn2->m_parent->GetParent()
};
std::shared_ptr<GRAPH_NODE> connect1 = gn1, connect2 = gn2;
std::lock_guard<std::mutex> lock( nodes_lock );
if( !pc.isValid( m_board, aLayer, m_boardEdge, IgnoreForTest, m_boardOutline,
{ false, true }, m_minGrooveWidth ) )
{
continue;
}
// Handle non-point node1
if( gn1->m_parent->GetType() != CREEP_SHAPE::TYPE::POINT )
{
auto gnt1 = AddNode( GRAPH_NODE::POINT, gn1->m_parent, pc.a1 );
gnt1->m_connectDirectly = false;
connect1 = gnt1;
std::shared_ptr<GRAPH_NODE> connect1 = gn1, connect2 = gn2;
std::lock_guard<std::mutex> lock( nodes_lock );
if( gn1->m_parent->IsConductive() )
{
if( auto gc = AddConnection( gn1, gnt1 ) )
gc->m_path.m_show = false;
}
}
// Handle non-point node1
if( gn1->m_parent->GetType() != CREEP_SHAPE::TYPE::POINT )
{
auto gnt1 = AddNode( GRAPH_NODE::POINT, gn1->m_parent, pc.a1 );
gnt1->m_connectDirectly = false;
connect1 = gnt1;
if( gn1->m_parent->IsConductive() )
{
if( std::shared_ptr<GRAPH_CONNECTION> gc = AddConnection( gn1, gnt1 ) )
gc->m_path.m_show = false;
}
}
// Handle non-point node2
if( gn2->m_parent->GetType() != CREEP_SHAPE::TYPE::POINT )
{
auto gnt2 = AddNode( GRAPH_NODE::POINT, gn2->m_parent, pc.a2 );
gnt2->m_connectDirectly = false;
connect2 = gnt2;
// Handle non-point node2
if( gn2->m_parent->GetType() != CREEP_SHAPE::TYPE::POINT )
{
auto gnt2 = AddNode( GRAPH_NODE::POINT, gn2->m_parent, pc.a2 );
gnt2->m_connectDirectly = false;
connect2 = gnt2;
if( gn2->m_parent->IsConductive() )
{
if( std::shared_ptr<GRAPH_CONNECTION> gc = AddConnection( gn2, gnt2 ) )
gc->m_path.m_show = false;
}
}
if( gn2->m_parent->IsConductive() )
{
if( auto gc = AddConnection( gn2, gnt2 ) )
gc->m_path.m_show = false;
AddConnection( connect1, connect2, pc );
}
}
AddConnection( connect1, connect2, pc );
}
return true;
};
return true;
};
// If the number of tasks is high enough, this indicates that the calling process
// has already parallelized the work, so we can process all items in one go.
@ -2408,6 +2345,7 @@ void CREEPAGE_GRAPH::Trim( double aWeightLimit )
RemoveConnection( gc );
}
void CREEPAGE_GRAPH::RemoveConnection( const std::shared_ptr<GRAPH_CONNECTION>& aGc, bool aDelete )
{
if( !aGc )
@ -2458,6 +2396,7 @@ std::shared_ptr<GRAPH_NODE> CREEPAGE_GRAPH::AddNode( GRAPH_NODE::TYPE aType, CRE
return gn;
}
std::shared_ptr<GRAPH_NODE> CREEPAGE_GRAPH::AddNodeVirtual()
{
//Virtual nodes are always unique, do not try to find them
@ -2485,6 +2424,7 @@ std::shared_ptr<GRAPH_CONNECTION> CREEPAGE_GRAPH::AddConnection( std::shared_ptr
return gc;
}
std::shared_ptr<GRAPH_CONNECTION> CREEPAGE_GRAPH::AddConnection( std::shared_ptr<GRAPH_NODE>& aN1,
std::shared_ptr<GRAPH_NODE>& aN2 )
{
@ -2499,6 +2439,7 @@ std::shared_ptr<GRAPH_CONNECTION> CREEPAGE_GRAPH::AddConnection( std::shared_ptr
return AddConnection( aN1, aN2, pc );
}
std::shared_ptr<GRAPH_NODE> CREEPAGE_GRAPH::FindNode( GRAPH_NODE::TYPE aType, CREEP_SHAPE* aParent,
const VECTOR2I& aPos )
{
@ -2521,71 +2462,46 @@ std::shared_ptr<GRAPH_NODE> CREEPAGE_GRAPH::AddNetElements( int aNetCode, PCB_LA
{
for( PAD* pad : footprint->Pads() )
{
if( pad->GetNetCode() != aNetCode || !pad->GetLayerSet().test( aLayer ) )
if( pad->GetNetCode() != aNetCode || !pad->IsOnLayer( aLayer ) )
continue;
std::shared_ptr<SHAPE> padShape = pad->GetEffectiveShape( aLayer );
if( padShape )
{
if( std::shared_ptr<SHAPE> padShape = pad->GetEffectiveShape( aLayer ) )
Addshape( *padShape, virtualNode, pad );
}
}
}
for( PCB_TRACK* track : m_board.Tracks() )
{
if( !track )
if( track->GetNetCode() != aNetCode || !track->IsOnLayer( aLayer ) )
continue;
if( track->GetNetCode() != aNetCode )
continue;
if( !track->IsOnLayer( aLayer ) )
continue;
if( track->GetEffectiveShape() == nullptr )
continue;
Addshape( *( track->GetEffectiveShape() ), virtualNode, track );
if( std::shared_ptr<SHAPE> shape = track->GetEffectiveShape() )
Addshape( *shape, virtualNode, track );
}
for( ZONE* zone : m_board.Zones() )
{
if( !zone )
continue;
if( zone->GetNetCode() != aNetCode )
continue;
if( zone->GetEffectiveShape( aLayer ) == nullptr )
if( zone->GetNetCode() != aNetCode || !zone->IsOnLayer( aLayer ) )
continue;
Addshape( *( zone->GetEffectiveShape( aLayer ) ), virtualNode, zone );
if( std::shared_ptr<SHAPE> shape = zone->GetEffectiveShape( aLayer ) )
Addshape( *shape, virtualNode, zone );
}
const DRAWINGS drawings = m_board.Drawings();
for( BOARD_ITEM* drawing : drawings )
{
if( !drawing )
continue;
if( !drawing->IsConnected() )
continue;
BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( drawing );
if( !bci )
continue;
if( drawing->IsConnected() )
{
BOARD_CONNECTED_ITEM* bci = static_cast<BOARD_CONNECTED_ITEM*>( drawing );
if( bci->GetNetCode() != aNetCode )
continue;
if( bci->GetNetCode() != aNetCode || !bci->IsOnLayer( aLayer ) )
continue;
if( bci->IsOnLayer( aLayer ) )
{
Addshape( *( bci->GetEffectiveShape() ), virtualNode, bci );
if( std::shared_ptr<SHAPE> shape = bci->GetEffectiveShape() )
Addshape( *shape, virtualNode, bci );
}
}

56
pcbnew/drc/drc_creepage_utils.h

@ -21,8 +21,7 @@
*/
#ifndef _DRC_CREEPAGE_UTILS_H
#define _DRC_CREEPAGE_UTILS_H
#pragma once
#include <unordered_set>
@ -180,7 +179,6 @@ public:
virtual ~CREEP_SHAPE() {}
virtual int GetRadius() const { return 0; };
virtual EDA_ANGLE GetStartAngle() const { return EDA_ANGLE( 0 ); };
virtual EDA_ANGLE GetEndAngle() const { return EDA_ANGLE( 0 ); };
@ -260,7 +258,6 @@ public:
//virtual std::vector<PATH_CONNECTION> GetPathsCuToBe( CREEP_SHAPE* aShape ) const{ std::vector<PATH_CONNECTION> a; return a;};
bool IsConductive() { return m_conductive; };
protected:
bool m_conductive;
BOARD_ITEM* m_parent;
@ -276,7 +273,11 @@ protected:
class CU_SHAPE : public CREEP_SHAPE
{
public:
CU_SHAPE() : CREEP_SHAPE() { m_conductive = true; };
CU_SHAPE() :
CREEP_SHAPE()
{
m_conductive = true;
};
};
/** @class BE_SHAPE
@ -286,7 +287,11 @@ public:
class BE_SHAPE : public CREEP_SHAPE
{
public:
BE_SHAPE() : CREEP_SHAPE() { m_conductive = false; };
BE_SHAPE() :
CREEP_SHAPE()
{
m_conductive = false;
};
};
/** @class CU_SHAPE_SEGMENT
@ -296,7 +301,8 @@ public:
class CU_SHAPE_SEGMENT : public CU_SHAPE
{
public:
CU_SHAPE_SEGMENT( VECTOR2I aStart, VECTOR2I aEnd, double aWidth = 0 ) : CU_SHAPE()
CU_SHAPE_SEGMENT( VECTOR2I aStart, VECTOR2I aEnd, double aWidth = 0 ) :
CU_SHAPE()
{
m_start = aStart;
m_end = aEnd;
@ -334,7 +340,8 @@ private:
class CU_SHAPE_CIRCLE : public CU_SHAPE
{
public:
CU_SHAPE_CIRCLE( VECTOR2I aPos, double aRadius = 0 ) : CU_SHAPE()
CU_SHAPE_CIRCLE( VECTOR2I aPos, double aRadius = 0 ) :
CU_SHAPE()
{
m_pos = aPos;
m_radius = aRadius;
@ -375,8 +382,10 @@ public:
CU_SHAPE_ARC( VECTOR2I aPos, double aRadius, EDA_ANGLE aStartAngle, EDA_ANGLE aEndAngle,
VECTOR2D aStartPoint, VECTOR2D aEndPoint ) :
CU_SHAPE_CIRCLE( aPos, aRadius ),
m_startAngle( aStartAngle ), m_endAngle( aEndAngle ),
m_startPoint( aStartPoint ), m_endPoint( aEndPoint )
m_startAngle( aStartAngle ),
m_endAngle( aEndAngle ),
m_startPoint( aStartPoint ),
m_endPoint( aEndPoint )
{
m_type = CREEP_SHAPE::TYPE::ARC;
m_width = 0;
@ -406,12 +415,10 @@ public:
std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_ARC& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const override;
EDA_ANGLE GetStartAngle() const override { return m_startAngle; }
EDA_ANGLE GetEndAngle() const override { return m_endAngle; }
int GetRadius() const override { return m_radius; }
VECTOR2I GetStartPoint() const override { return m_startPoint; }
VECTOR2I GetEndPoint() const override { return m_endPoint; }
@ -439,16 +446,15 @@ private:
VECTOR2I m_endPoint;
};
/** @class Graphnode
/** @class GRAPH_NODE
*
* @brief a node in a @class CreepageGraph
* @brief a node in a @class CREEPAGE_GRAPH
*/
class GRAPH_NODE
{
public:
enum TYPE
{
POINT = 0,
CIRCLE,
ARC,
@ -456,7 +462,7 @@ public:
VIRTUAL
};
GRAPH_NODE( GRAPH_NODE::TYPE aType, CREEP_SHAPE* aParent, VECTOR2I aPos = VECTOR2I() ) :
GRAPH_NODE( GRAPH_NODE::TYPE aType, CREEP_SHAPE* aParent, const VECTOR2I& aPos = VECTOR2I() ) :
m_parent( aParent ),
m_pos( aPos ),
m_type( aType )
@ -469,7 +475,7 @@ public:
~GRAPH_NODE() {};
public:
CREEP_SHAPE* m_parent;
std::set<std::shared_ptr<GRAPH_CONNECTION>> m_node_conns;
VECTOR2I m_pos;
@ -482,9 +488,9 @@ public:
GRAPH_NODE::TYPE m_type;
};
/** @class GraphConnection
/** @class GRAPH_CONNECTION
*
* @brief a connection in a @class CreepageGraph
* @brief a connection in a @class CREEPAGE_GRAPH
*/
class GRAPH_CONNECTION
{
@ -498,8 +504,9 @@ public:
m_forceStraightLine = false;
};
std::vector<PCB_SHAPE> GetShapes();
void GetShapes( std::vector<PCB_SHAPE>& aShapes );
public:
std::shared_ptr<GRAPH_NODE> n1;
std::shared_ptr<GRAPH_NODE> n2;
PATH_CONNECTION m_path;
@ -655,12 +662,10 @@ public:
return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
};
EDA_ANGLE GetStartAngle() const override { return m_startAngle; }
EDA_ANGLE GetEndAngle() const override { return m_endAngle; }
int GetRadius() const override { return m_radius; }
VECTOR2I GetStartPoint() const override { return m_startPoint; }
VECTOR2I GetEndPoint() const override { return m_endPoint; }
EDA_ANGLE AngleBetweenStartAndEnd( const VECTOR2I aPoint ) const
@ -685,7 +690,7 @@ protected:
};
/** @class CreepageGraph
/** @class CREEPAGE_GRAPH
*
* @brief A graph with nodes and connections for creepage calculation
*/
@ -729,7 +734,6 @@ public:
}
};
void TransformEdgeToCreepShapes();
void TransformCreepShapesToNodes(std::vector<CREEP_SHAPE*>& aShapes);
void RemoveDuplicatedShapes();
@ -767,7 +771,6 @@ public:
void SetTarget( double aTarget );
double GetTarget() { return m_creepageTarget; };
struct GraphNodeHash
{
std::size_t operator()(const std::shared_ptr<GRAPH_NODE>& node) const
@ -784,6 +787,7 @@ public:
}
};
public:
BOARD& m_board;
std::vector<BOARD_ITEM*> m_boardEdge;
SHAPE_POLY_SET* m_boardOutline;
@ -801,5 +805,3 @@ private:
double m_creepageTargetSquared;
};
#endif

4
pcbnew/drc/drc_engine.cpp

@ -1786,7 +1786,7 @@ bool DRC_ENGINE::IsErrorLimitExceeded( int error_code )
void DRC_ENGINE::ReportViolation( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos,
int aMarkerLayer, DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
int aMarkerLayer, const std::vector<PCB_SHAPE>& aShapes )
{
static std::mutex globalLock;
@ -1795,7 +1795,7 @@ void DRC_ENGINE::ReportViolation( const std::shared_ptr<DRC_ITEM>& aItem, const
if( m_violationHandler )
{
std::lock_guard<std::mutex> guard( globalLock );
m_violationHandler( aItem, aPos, aMarkerLayer, aCustomHandler );
m_violationHandler( aItem, aPos, aMarkerLayer, aShapes );
}
if( m_logReporter )

11
pcbnew/drc/drc_engine.h

@ -28,7 +28,7 @@
#include <unordered_map>
#include <units_provider.h>
#include <geometry/shape.h>
#include <pcb_shape.h>
#include <lset.h>
#include <drc/drc_rule.h>
@ -65,11 +65,10 @@ class DRC_ITEM;
class DRC_RULE;
class DRC_CONSTRAINT;
typedef std::function<void( PCB_MARKER* aMarker )> DRC_CUSTOM_MARKER_HANDLER;
typedef std::function<void( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos,
int aLayer, DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )>
DRC_VIOLATION_HANDLER;
typedef std::function<void( const std::shared_ptr<DRC_ITEM>& aItem,
const VECTOR2I& aPos, int aLayer,
const std::vector<PCB_SHAPE>& aShapes )> DRC_VIOLATION_HANDLER;
/**
* Design Rule Checker object that performs all the DRC tests.
@ -177,7 +176,7 @@ public:
bool RulesValid() { return m_rulesValid; }
void ReportViolation( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos,
int aMarkerLayer, DRC_CUSTOM_MARKER_HANDLER* aCustomHandler = nullptr );
int aMarkerLayer, const std::vector<PCB_SHAPE>& aShapes = {} );
bool KeepRefreshing( bool aWait = false );
void AdvanceProgress();

4
pcbnew/drc/drc_test_provider.cpp

@ -73,10 +73,10 @@ const wxString DRC_TEST_PROVIDER::GetName() const { return wxT( "<no name test>"
void DRC_TEST_PROVIDER::reportViolation( std::shared_ptr<DRC_ITEM>& item,
const VECTOR2I& aMarkerPos, int aMarkerLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
const std::vector<PCB_SHAPE>& aShapes )
{
item->SetViolatingTest( this );
m_drcEngine->ReportViolation( item, aMarkerPos, aMarkerLayer, aCustomHandler );
m_drcEngine->ReportViolation( item, aMarkerPos, aMarkerLayer, aShapes );
}

3
pcbnew/drc/drc_test_provider.h

@ -107,8 +107,7 @@ protected:
#define REPORT_AUX( s ) if( getLogReporter() ) getLogReporter()->Report( s, RPT_SEVERITY_INFO )
virtual void reportViolation( std::shared_ptr<DRC_ITEM>& item, const VECTOR2I& aMarkerPos,
int aMarkerLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler = nullptr );
int aMarkerLayer, const std::vector<PCB_SHAPE>& aShapes = {} );
virtual bool reportProgress( size_t aCount, size_t aSize, size_t aDelta = 1 );
virtual bool reportPhase( const wxString& aStageName );

88
pcbnew/drc/drc_test_provider_clearance_base.cpp

@ -24,76 +24,51 @@
*/
#include <drc/drc_test_provider_clearance_base.h>
#include <pgm_base.h>
#include <settings/settings_manager.h>
#include <wx/app.h>
DRC_CUSTOM_MARKER_HANDLER
DRC_TEST_PROVIDER_CLEARANCE_BASE::GetGraphicsHandler( const std::vector<PCB_SHAPE>& aShapes,
const VECTOR2I& aStart, const VECTOR2I& aEnd,
int aLength )
{
// todo: Move this to a board-level object instead of getting it from the DRC Engine
COLOR4D errorColor = COLOR4D( RED );
if( PgmOrNull() )
{
COLOR_SETTINGS* colorSettings = ::GetColorSettings( DEFAULT_THEME );
errorColor = colorSettings->GetColor( LAYER_DRC_ERROR );
}
std::vector<PCB_SHAPE> shortestPathShapes1, shortestPathShapes2;
std::vector<PCB_SHAPE> DRC_TEST_PROVIDER_CLEARANCE_BASE::GetShapes( const std::vector<PCB_SHAPE>& aShapes,
const VECTOR2I& aStart, const VECTOR2I& aEnd,
int aLength )
{
STROKE_PARAMS hairline( 1.0 ); // Segments of width 1.0 will get drawn as lines by PCB_PAINTER
std::vector<PCB_SHAPE> shortestPathShapes;
// Add the path and its outlined area
for( PCB_SHAPE sh : aShapes )
// Add the path
for( PCB_SHAPE shape : aShapes )
{
sh.SetStroke( false );
sh.SetFilled( false );
sh.SetLineColor( WHITE );
shortestPathShapes1.push_back( sh );
sh.SetFilled( true );
sh.SetFillColor( errorColor.WithAlpha( 0.5 ) );
sh.SetWidth( aLength / 10 );
shortestPathShapes2.push_back( sh );
shape.SetStroke( hairline );
shortestPathShapes.push_back( std::move( shape ) );
}
// Draw perpendicular end stops
if( shortestPathShapes1.size() > 0 )
// Draw perpendicular begin/end stops
if( shortestPathShapes.size() > 0 )
{
PCB_SHAPE s1, s2;
s1.SetFilled( false );
s2.SetFilled( false );
VECTOR2I V1 = shortestPathShapes1[0].GetStart() - shortestPathShapes1[0].GetEnd();
VECTOR2I V1 = shortestPathShapes[0].GetStart() - shortestPathShapes[0].GetEnd();
VECTOR2I V2 = shortestPathShapes.back().GetStart() - shortestPathShapes.back().GetEnd();
V1 = V1.Perpendicular().Resize( aLength / 30 );
s1.SetStart( aStart + V1 );
s1.SetEnd( aStart - V1 );
s1.SetWidth( 0 );
s1.SetLineColor( WHITE );
VECTOR2I V2 = shortestPathShapes1.back().GetStart() - shortestPathShapes1.back().GetEnd();
V2 = V2.Perpendicular().Resize( aLength / 30 );
s2.SetStart( aEnd + V2 );
s2.SetEnd( aEnd - V2 );
s2.SetWidth( 0 );
s2.SetLineColor( WHITE );
PCB_SHAPE s( nullptr, SHAPE_T::SEGMENT );
s.SetStroke( hairline );
shortestPathShapes1.push_back( s1 );
shortestPathShapes1.push_back( s2 );
s.SetStart( aStart + V1 );
s.SetEnd( aStart - V1 );
shortestPathShapes.push_back( s );
s.SetStart( aEnd + V2 );
s.SetEnd( aEnd - V2 );
shortestPathShapes.push_back( s );
}
return [shortestPathShapes1, shortestPathShapes2]( PCB_MARKER* aMarker )
{
if( !aMarker )
return;
// Add outlined areas
for( PCB_SHAPE shape : aShapes )
{
shape.SetWidth( aLength / 10 );
shortestPathShapes.push_back( std::move( shape ) );
}
aMarker->SetShapes1( std::move( shortestPathShapes1 ) );
aMarker->SetShapes2( std::move( shortestPathShapes2 ) );
};
return shortestPathShapes;
}
@ -115,8 +90,7 @@ void DRC_TEST_PROVIDER_CLEARANCE_BASE::ReportAndShowPathCuToCu( std::shared_ptr<
PCB_SHAPE ptAShape( nullptr, SHAPE_T::SEGMENT );
ptAShape.SetStart( ptA );
ptAShape.SetEnd( ptB );
DRC_CUSTOM_MARKER_HANDLER handler = GetGraphicsHandler( { ptAShape }, ptA, ptB, aDistance );
reportViolation( aDrce, aMarkerPos, aMarkerLayer, &handler );
reportViolation( aDrce, aMarkerPos, aMarkerLayer, GetShapes( { ptAShape }, ptA, ptB, aDistance ) );
}
else
{

5
pcbnew/drc/drc_test_provider_clearance_base.h

@ -54,7 +54,6 @@ protected:
int aMarkerLayer, const BOARD_ITEM* aItem1,
const BOARD_ITEM* aItem2, PCB_LAYER_ID layer, int aDistance );
DRC_CUSTOM_MARKER_HANDLER GetGraphicsHandler( const std::vector<PCB_SHAPE>& aShapes,
const VECTOR2I& aStart, const VECTOR2I& aEnd,
int aLength );
std::vector<PCB_SHAPE> GetShapes( const std::vector<PCB_SHAPE>& aShapes, const VECTOR2I& aStart,
const VECTOR2I& aEnd, int aLength );
};

72
pcbnew/drc/drc_test_provider_creepage.cpp

@ -89,21 +89,6 @@ bool DRC_TEST_PROVIDER_CREEPAGE::Run()
}
std::shared_ptr<GRAPH_NODE> FindInGraphNodes( std::shared_ptr<GRAPH_NODE> aNode,
std::vector<std::shared_ptr<GRAPH_NODE>>& aGraph )
{
if( !aNode )
return nullptr;
for( std::shared_ptr<GRAPH_NODE> gn : aGraph )
{
if( aNode->m_pos == gn->m_pos )
return gn;
}
return nullptr;
}
int DRC_TEST_PROVIDER_CREEPAGE::testCreepage( CREEPAGE_GRAPH& aGraph, int aNetCodeA, int aNetCodeB,
PCB_LAYER_ID aLayer )
{
@ -188,7 +173,8 @@ int DRC_TEST_PROVIDER_CREEPAGE::testCreepage( CREEPAGE_GRAPH& aGraph, int aNetCo
if( !shortestPath.empty() && ( shortestPath.size() >= 4 ) && ( distance - creepageValue < 0 ) )
{
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CREEPAGE );
wxString msg = formatMsg( _( "(%s creepage %s; actual %s)" ), constraint.GetName(),
wxString msg = formatMsg( _( "(%s creepage %s; actual %s)" ),
constraint.GetName(),
creepageValue, distance );
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
drce->SetViolatingRule( constraint.GetParentRule() );
@ -207,30 +193,20 @@ int DRC_TEST_PROVIDER_CREEPAGE::testCreepage( CREEPAGE_GRAPH& aGraph, int aNetCo
return 1;
}
std::vector<PCB_SHAPE> shortestPathShapes1, shortestPathShapes2;
VECTOR2I startPoint = gc1->m_path.a2;
VECTOR2I endPoint = gc2->m_path.a2;
std::vector<PCB_SHAPE> path;
for( const std::shared_ptr<GRAPH_CONNECTION>& gc : shortestPath )
{
if( !gc )
continue;
std::vector<PCB_SHAPE> shapes = gc->GetShapes();
for( const PCB_SHAPE& sh : shapes )
path.push_back( sh );
}
gc->GetShapes( path );
DRC_CUSTOM_MARKER_HANDLER handler = GetGraphicsHandler( path, startPoint, endPoint, distance );
reportViolation( drce, gc1->m_path.a2, aLayer, &handler );
reportViolation( drce, gc1->m_path.a2, aLayer, GetShapes( path, startPoint, endPoint, distance ) );
}
return 1;
}
double DRC_TEST_PROVIDER_CREEPAGE::GetMaxConstraint( const std::vector<int>& aNetCodes )
{
double maxConstraint = 0;
@ -240,28 +216,28 @@ double DRC_TEST_PROVIDER_CREEPAGE::GetMaxConstraint( const std::vector<int>& aNe
PCB_TRACK bci2( m_board );
alg::for_all_pairs( aNetCodes.begin(), aNetCodes.end(),
[&]( int aNet1, int aNet2 )
{
if( aNet1 == aNet2 )
return;
bci1.SetNetCode( aNet1 );
bci2.SetNetCode( aNet2 );
for( PCB_LAYER_ID layer : LSET::AllCuMask( m_board->GetCopperLayerCount() ) )
{
bci1.SetLayer( layer );
bci2.SetLayer( layer );
constraint = m_drcEngine->EvalRules( CREEPAGE_CONSTRAINT, &bci1,
&bci2, layer );
double value = constraint.Value().Min();
maxConstraint = value > maxConstraint ? value : maxConstraint;
}
} );
[&]( int aNet1, int aNet2 )
{
if( aNet1 == aNet2 )
return;
bci1.SetNetCode( aNet1 );
bci2.SetNetCode( aNet2 );
for( PCB_LAYER_ID layer : LSET::AllCuMask( m_board->GetCopperLayerCount() ) )
{
bci1.SetLayer( layer );
bci2.SetLayer( layer );
constraint = m_drcEngine->EvalRules( CREEPAGE_CONSTRAINT, &bci1, &bci2, layer );
double value = constraint.Value().Min();
maxConstraint = value > maxConstraint ? value : maxConstraint;
}
} );
return maxConstraint;
}
void DRC_TEST_PROVIDER_CREEPAGE::CollectNetCodes( std::vector<int>& aVector )
{
NETCODES_MAP nets = m_board->GetNetInfo().NetsByNetcode();
@ -270,6 +246,7 @@ void DRC_TEST_PROVIDER_CREEPAGE::CollectNetCodes( std::vector<int>& aVector )
aVector.push_back( it->first );
}
void DRC_TEST_PROVIDER_CREEPAGE::CollectBoardEdges( std::vector<BOARD_ITEM*>& aVector )
{
if( !m_board )
@ -314,6 +291,7 @@ void DRC_TEST_PROVIDER_CREEPAGE::CollectBoardEdges( std::vector<BOARD_ITEM*>& aV
}
}
int DRC_TEST_PROVIDER_CREEPAGE::testCreepage()
{
if( !m_board )

17
pcbnew/pcb_draw_panel_gal.cpp

@ -78,8 +78,7 @@ const int GAL_LAYER_ORDER[] =
LAYER_SELECT_OVERLAY,
LAYER_CONFLICTS_SHADOW,
LAYER_DRC_ERROR, LAYER_DRC_WARNING, LAYER_DRC_EXCLUSION, LAYER_MARKER_SHADOWS,
LAYER_DRC_SHAPE1, LAYER_DRC_SHAPE2,
LAYER_DRC_ERROR, LAYER_DRC_WARNING, LAYER_DRC_EXCLUSION, LAYER_MARKER_SHADOWS, LAYER_DRC_SHAPES,
LAYER_PAD_NETNAMES, LAYER_VIA_NETNAMES,
Dwgs_User, ZONE_LAYER_FOR( Dwgs_User ), POINT_LAYER_FOR( Dwgs_User ),
Cmts_User, ZONE_LAYER_FOR( Cmts_User ), POINT_LAYER_FOR( Cmts_User ),
@ -550,7 +549,7 @@ void PCB_DRAW_PANEL_GAL::SetHighContrastLayer( PCB_LAYER_ID aLayer )
LAYER_VIA_THROUGH, LAYER_VIA_BBLIND, LAYER_VIA_MICROVIA, LAYER_VIA_HOLES,
LAYER_VIA_HOLEWALLS,
LAYER_DRC_ERROR, LAYER_DRC_WARNING, LAYER_DRC_EXCLUSION, LAYER_MARKER_SHADOWS,
LAYER_DRC_SHAPE1, LAYER_DRC_SHAPE2,
LAYER_DRC_SHAPES,
LAYER_SELECT_OVERLAY, LAYER_GP_OVERLAY,
LAYER_RATSNEST, LAYER_CURSOR,
LAYER_ANCHOR,
@ -592,8 +591,7 @@ void PCB_DRAW_PANEL_GAL::SetTopLayer( PCB_LAYER_ID aLayer )
LAYER_PAD_NETNAMES, LAYER_VIA_NETNAMES,
LAYER_SELECT_OVERLAY, LAYER_GP_OVERLAY,
LAYER_RATSNEST,
LAYER_DRC_ERROR, LAYER_DRC_WARNING, LAYER_DRC_EXCLUSION, LAYER_MARKER_SHADOWS,
LAYER_DRC_SHAPE1, LAYER_DRC_SHAPE2,
LAYER_DRC_ERROR, LAYER_DRC_WARNING, LAYER_DRC_EXCLUSION, LAYER_MARKER_SHADOWS, LAYER_DRC_SHAPES,
LAYER_CONFLICTS_SHADOW
};
@ -723,8 +721,7 @@ void PCB_DRAW_PANEL_GAL::SyncLayersVisibility( const BOARD* aBoard )
m_view->SetLayerVisible( LAYER_SELECT_OVERLAY, true );
m_view->SetLayerVisible( LAYER_RATSNEST, true );
m_view->SetLayerVisible( LAYER_MARKER_SHADOWS, true );
m_view->SetLayerVisible( LAYER_DRC_SHAPE1, true );
m_view->SetLayerVisible( LAYER_DRC_SHAPE2, true );
m_view->SetLayerVisible( LAYER_DRC_SHAPES, true );
}
@ -930,10 +927,8 @@ void PCB_DRAW_PANEL_GAL::setDefaultLayerDeps()
//m_view->SetLayerDisplayOnly( LAYER_DRC_EXCLUSION );
m_view->SetLayerTarget( LAYER_MARKER_SHADOWS, KIGFX::TARGET_OVERLAY );
m_view->SetLayerDisplayOnly( LAYER_MARKER_SHADOWS );
m_view->SetLayerTarget( LAYER_DRC_SHAPE1, KIGFX::TARGET_OVERLAY );
m_view->SetLayerDisplayOnly( LAYER_DRC_SHAPE1 );
m_view->SetLayerTarget( LAYER_DRC_SHAPE2, KIGFX::TARGET_OVERLAY );
m_view->SetLayerDisplayOnly( LAYER_DRC_SHAPE2 );
m_view->SetLayerTarget( LAYER_DRC_SHAPES, KIGFX::TARGET_OVERLAY );
m_view->SetLayerDisplayOnly( LAYER_DRC_SHAPES );
m_view->SetLayerTarget( LAYER_DRAWINGSHEET, KIGFX::TARGET_NONCACHED );
m_view->SetLayerDisplayOnly( LAYER_DRAWINGSHEET ) ;

14
pcbnew/pcb_marker.cpp

@ -327,11 +327,9 @@ SEVERITY PCB_MARKER::GetSeverity() const
std::vector<int> PCB_MARKER::ViewGetLayers() const
{
if( GetMarkerType() == MARKER_RATSNEST )
{
return {};
}
std::vector<int> layers{ 0, LAYER_MARKER_SHADOWS, LAYER_DRC_SHAPE1, LAYER_DRC_SHAPE2 };
std::vector<int> layers{ 0, LAYER_MARKER_SHADOWS, LAYER_DRC_SHAPES };
switch( GetSeverity() )
{
@ -373,7 +371,7 @@ const BOX2I PCB_MARKER::GetBoundingBox() const
{
BOX2I box = GetBoundingBoxMarker();
for( auto& s : m_shapes1 )
for( const PCB_SHAPE& s : m_shapes )
box.Merge( s.GetBoundingBox() );
return box;
@ -398,11 +396,7 @@ static struct PCB_MARKER_DESC
propMgr.InheritsAfter( TYPE_HASH( PCB_MARKER ), TYPE_HASH( MARKER_BASE ) );
// Markers cannot be locked and have no user-accessible layer control
propMgr.OverrideAvailability( TYPE_HASH( PCB_MARKER ), TYPE_HASH( BOARD_ITEM ),
_HKI( "Layer" ),
[]( INSPECTABLE* aItem ) { return false; } );
propMgr.OverrideAvailability( TYPE_HASH( PCB_MARKER ), TYPE_HASH( BOARD_ITEM ),
_HKI( "Locked" ),
[]( INSPECTABLE* aItem ) { return false; } );
propMgr.Mask( TYPE_HASH( PCB_MARKER ), TYPE_HASH( BOARD_ITEM ), _HKI( "Layer" ) );
propMgr.Mask( TYPE_HASH( PCB_MARKER ), TYPE_HASH( BOARD_ITEM ), _HKI( "Locked" ) );
}
} _PCB_MARKER_DESC;

13
pcbnew/pcb_marker.h

@ -150,15 +150,12 @@ public:
return wxT( "PCB_MARKER" );
}
std::vector<PCB_SHAPE> GetShapes1() const { return m_shapes1; };
std::vector<PCB_SHAPE> GetShapes2() const { return m_shapes2; };
void SetShapes1( const std::vector<PCB_SHAPE>& aShapes ) { m_shapes1 = aShapes; };
void SetShapes2( const std::vector<PCB_SHAPE>& aShapes ) { m_shapes2 = aShapes; };
std::vector<PCB_SHAPE> GetShapes() const { return m_shapes; };
void SetShapes( const std::vector<PCB_SHAPE>& aShapes ) { m_shapes = aShapes; };
protected:
KIGFX::COLOR4D getColor() const override;
std::vector<PCB_SHAPE> m_shapes1; // Shown on LAYER_DRC_SHAPE1
std::vector<PCB_SHAPE> m_shapes2; // Shown on LAYER_DRC_SHAPE2
protected:
std::vector<PCB_SHAPE> m_shapes; // Shown on LAYER_DRC_SHAPES
};

64
pcbnew/pcb_painter.cpp

@ -3055,6 +3055,8 @@ void PCB_PAINTER::draw( const PCB_MARKER* aMarker, int aLayer )
if( aMarker->GetBoard() && !aMarker->GetBoard()->IsElementVisible( aMarker->GetColorLayer() ) )
return;
COLOR4D color = m_pcbSettings.GetColor( aMarker, aMarker->GetColorLayer() );
aMarker->SetZoom( 1.0 / sqrt( m_gal->GetZoomFactor() ) );
switch( aLayer )
@ -3075,11 +3077,11 @@ void PCB_PAINTER::draw( const PCB_MARKER* aMarker, int aLayer )
{
m_gal->SetStrokeColor( m_pcbSettings.GetColor( aMarker, LAYER_MARKER_SHADOWS ) );
m_gal->SetIsStroke( true );
m_gal->SetLineWidth( aMarker->MarkerScale() );
m_gal->SetLineWidth( (float) aMarker->MarkerScale() );
}
else
{
m_gal->SetFillColor( m_pcbSettings.GetColor( aMarker, aMarker->GetColorLayer() ) );
m_gal->SetFillColor( color );
m_gal->SetIsFill( true );
}
@ -3088,37 +3090,49 @@ void PCB_PAINTER::draw( const PCB_MARKER* aMarker, int aLayer )
break;
}
case LAYER_DRC_SHAPE1:
case LAYER_DRC_SHAPE2:
case LAYER_DRC_SHAPES:
if( !aMarker->IsBrightened() )
return;
m_gal->SetLineWidth( aMarker->MarkerScale() );
for( const PCB_SHAPE& shape : aLayer == LAYER_DRC_SHAPE1 ? aMarker->GetShapes1() : aMarker->GetShapes2() )
for( const PCB_SHAPE& shape : aMarker->GetShapes() )
{
m_gal->SetIsFill( shape.IsSolidFill() );
m_gal->SetIsStroke( aLayer == LAYER_DRC_SHAPE1 ? true : false );
m_gal->SetStrokeColor( shape.GetLineColor() );
m_gal->SetFillColor( shape.GetFillColor() );
switch( shape.GetShape() )
if( shape.GetStroke().GetWidth() == 1.0 )
{
case SHAPE_T::SEGMENT:
m_gal->DrawSegment( shape.GetStart(), shape.GetEnd(), shape.GetWidth() );
break;
m_gal->SetIsFill( false );
m_gal->SetIsStroke( true );
m_gal->SetStrokeColor( WHITE );
m_gal->SetLineWidth( (float) shape.GetWidth() );
case SHAPE_T::ARC:
{
EDA_ANGLE startAngle, endAngle;
shape.CalcArcAngles( startAngle, endAngle );
m_gal->DrawArcSegment( shape.GetCenter(), shape.GetRadius(), startAngle, shape.GetArcAngle(),
shape.GetWidth(), ARC_HIGH_DEF );
break;
if( shape.GetShape() == SHAPE_T::SEGMENT )
{
m_gal->DrawLine( shape.GetStart(), shape.GetEnd() );
}
else if( shape.GetShape() == SHAPE_T::ARC )
{
EDA_ANGLE startAngle, endAngle;
shape.CalcArcAngles( startAngle, endAngle );
m_gal->DrawArc( shape.GetCenter(), shape.GetRadius(), startAngle, shape.GetArcAngle() );
}
}
else
{
m_gal->SetIsFill( true );
m_gal->SetIsStroke( false );
m_gal->SetFillColor( color.WithAlpha( 0.5 ) );
default:
break;
if( shape.GetShape() == SHAPE_T::SEGMENT )
{
m_gal->DrawSegment( shape.GetStart(), shape.GetEnd(), shape.GetWidth() );
}
else if( shape.GetShape() == SHAPE_T::ARC )
{
EDA_ANGLE startAngle, endAngle;
shape.CalcArcAngles( startAngle, endAngle );
m_gal->DrawArcSegment( shape.GetCenter(), shape.GetRadius(), startAngle, shape.GetArcAngle(),
shape.GetWidth(), ARC_HIGH_DEF );
}
}
}

5
pcbnew/pcbnew_jobs_handler.cpp

@ -2245,10 +2245,11 @@ int PCBNEW_JOBS_HANDLER::JobExportDrc( JOB* aJob )
drcEngine->SetProgressReporter( m_progressReporter );
drcEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
[&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
const std::vector<PCB_SHAPE>& aShapes )
{
PCB_MARKER* marker = new PCB_MARKER( aItem, aPos, aLayer );
marker->SetShapes( aShapes );
commit.Add( marker );
} );

3
pcbnew/pcbnew_printout.cpp

@ -167,8 +167,7 @@ void PCBNEW_PRINTOUT::setupViewLayers( KIGFX::VIEW& aView, const LSET& aLayerSet
setVisibility( LAYER_DRC_WARNING );
setVisibility( LAYER_DRC_ERROR );
setVisibility( LAYER_DRC_SHAPE1 );
setVisibility( LAYER_DRC_SHAPE2 );
setVisibility( LAYER_DRC_SHAPES );
setVisibility( LAYER_DRC_EXCLUSION );
setVisibility( LAYER_ANCHOR );
setVisibility( LAYER_DRAWINGSHEET );

4
pcbnew/python/scripting/pcbnew_scripting_helpers.cpp

@ -592,8 +592,8 @@ bool WriteDRCReport( BOARD* aBoard, const wxString& aFileName, EDA_UNITS aUnits,
engine->SetProgressReporter( nullptr );
engine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2D aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
[&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2D& aPos, int aLayer,
const std::vector<PCB_SHAPE>& aShapes )
{
if( aItem->GetErrorCode() == DRCE_MISSING_FOOTPRINT
|| aItem->GetErrorCode() == DRCE_DUPLICATE_FOOTPRINT

7
pcbnew/tools/drc_tool.cpp

@ -173,13 +173,10 @@ void DRC_TOOL::RunTests( PROGRESS_REPORTER* aProgressReporter, bool aRefillZones
m_drcEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
const std::vector<PCB_SHAPE>& aShapes )
{
PCB_MARKER* marker = new PCB_MARKER( aItem, aPos, aLayer );
if( aCustomHandler )
( *aCustomHandler )( marker );
marker->SetShapes( aShapes );
commit.Add( marker );
} );

4
qa/tests/pcbnew/drc/test_custom_rule_severities.cpp

@ -63,8 +63,8 @@ BOOST_FIXTURE_TEST_CASE( DRCCustomRuleSeverityTest, DRC_REGRESSION_TEST_FIXTURE
bds.m_DRCSeverities[ DRCE_FOOTPRINT_TYPE_MISMATCH ] = SEVERITY::RPT_SEVERITY_IGNORE;
bds.m_DRCEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
[&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
const std::vector<PCB_SHAPE>& aShapes )
{
PCB_MARKER temp( aItem, aPos );

4
qa/tests/pcbnew/drc/test_drc_component_classes.cpp

@ -74,8 +74,8 @@ BOOST_FIXTURE_TEST_CASE( DRCComponentClasses, DRC_REGRESSION_TEST_FIXTURE )
bds.m_DRCSeverities[ DRCE_ASSERTION_FAILURE ] = SEVERITY::RPT_SEVERITY_ERROR;
bds.m_DRCEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
[&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
const std::vector<PCB_SHAPE>& aShapes )
{
if( bds.GetSeverity( aItem->GetErrorCode() ) == SEVERITY::RPT_SEVERITY_ERROR )
violations.push_back( *aItem );

4
qa/tests/pcbnew/drc/test_drc_copper_conn.cpp

@ -80,8 +80,8 @@ BOOST_FIXTURE_TEST_CASE( DRCCopperConn, DRC_REGRESSION_TEST_FIXTURE )
bds.m_DRCSeverities[ DRCE_CONNECTION_WIDTH ] = SEVERITY::RPT_SEVERITY_ERROR;
bds.m_DRCEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
[&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
const std::vector<PCB_SHAPE>& aShapes )
{
if( bds.GetSeverity( aItem->GetErrorCode() ) == SEVERITY::RPT_SEVERITY_ERROR )
violations.push_back( *aItem );

4
qa/tests/pcbnew/drc/test_drc_copper_graphics.cpp

@ -63,8 +63,8 @@ BOOST_FIXTURE_TEST_CASE( DRCCopperGraphicsTest, DRC_COPPER_GRAPHICS_TEST_FIXTURE
bds.m_DRCSeverities[ DRCE_NONMIRRORED_TEXT_ON_BACK_LAYER ] = SEVERITY::RPT_SEVERITY_IGNORE;
bds.m_DRCEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
[&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
const std::vector<PCB_SHAPE>& aShapes )
{
PCB_MARKER temp( aItem, aPos );

4
qa/tests/pcbnew/drc/test_drc_copper_sliver.cpp

@ -104,8 +104,8 @@ BOOST_DATA_TEST_CASE_F( DRC_REGRESSION_TEST_FIXTURE, DRCCopperSliver,
bds.m_DRCSeverities[DRCE_COPPER_SLIVER] = SEVERITY::RPT_SEVERITY_ERROR;
bds.m_DRCEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
[&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
const std::vector<PCB_SHAPE>& aShapes )
{
if( bds.GetSeverity( aItem->GetErrorCode() ) == SEVERITY::RPT_SEVERITY_ERROR )
violations.push_back( *aItem );

4
qa/tests/pcbnew/drc/test_drc_courtyard_invalid.cpp

@ -304,8 +304,8 @@ void DoCourtyardInvalidTest( const COURTYARD_INVALID_CASE& aCase,
drcEngine.InitEngine( wxFileName() );
drcEngine.SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
[&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
const std::vector<PCB_SHAPE>& aShapes )
{
if( aItem->GetErrorCode() == DRCE_OVERLAPPING_FOOTPRINTS
|| aItem->GetErrorCode() == DRCE_MALFORMED_COURTYARD

4
qa/tests/pcbnew/drc/test_drc_courtyard_overlap.cpp

@ -460,8 +460,8 @@ static void DoCourtyardOverlapTest( const COURTYARD_OVERLAP_TEST_CASE& aCase,
drcEngine.InitEngine( wxFileName() );
drcEngine.SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
[&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
const std::vector<PCB_SHAPE>& aShapes )
{
if( aItem->GetErrorCode() == DRCE_OVERLAPPING_FOOTPRINTS
|| aItem->GetErrorCode() == DRCE_MALFORMED_COURTYARD

4
qa/tests/pcbnew/drc/test_drc_incorrect_text_mirror.cpp

@ -62,8 +62,8 @@ BOOST_FIXTURE_TEST_CASE( DRCIncorrectTextMirror, DRC_INCORRECT_TEXT_MIRROR_TEST_
bds.m_DRCSeverities[DRCE_NONMIRRORED_TEXT_ON_BACK_LAYER] = SEVERITY::RPT_SEVERITY_ERROR;
bds.m_DRCEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
[&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
const std::vector<PCB_SHAPE>& aShapes )
{
if( bds.GetSeverity( aItem->GetErrorCode() ) == SEVERITY::RPT_SEVERITY_ERROR )
violations.push_back( *aItem );

4
qa/tests/pcbnew/drc/test_drc_lengths.cpp

@ -76,8 +76,8 @@ BOOST_FIXTURE_TEST_CASE( DRCLengths, DRC_REGRESSION_TEST_FIXTURE )
bds.m_DRCSeverities[DRCE_LENGTH_OUT_OF_RANGE] = SEVERITY::RPT_SEVERITY_ERROR;
bds.m_DRCEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
[&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
const std::vector<PCB_SHAPE>& aShapes )
{
if( bds.GetSeverity( aItem->GetErrorCode() ) == SEVERITY::RPT_SEVERITY_ERROR )
violations.push_back( *aItem );

4
qa/tests/pcbnew/drc/test_drc_multi_netclasses.cpp

@ -77,8 +77,8 @@ BOOST_FIXTURE_TEST_CASE( DRCMultiNetclasses, DRC_REGRESSION_TEST_FIXTURE )
bds.m_DRCSeverities[ DRCE_TRACK_WIDTH ] = SEVERITY::RPT_SEVERITY_ERROR;
bds.m_DRCEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
[&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
const std::vector<PCB_SHAPE>& aShapes )
{
if( bds.GetSeverity( aItem->GetErrorCode() ) == SEVERITY::RPT_SEVERITY_ERROR )
violations.push_back( *aItem );

4
qa/tests/pcbnew/drc/test_drc_orientation.cpp

@ -77,8 +77,8 @@ BOOST_FIXTURE_TEST_CASE( DRCOrientation, DRC_REGRESSION_TEST_FIXTURE )
bds.m_DRCSeverities[ DRCE_ASSERTION_FAILURE ] = SEVERITY::RPT_SEVERITY_ERROR;
bds.m_DRCEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
[&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
const std::vector<PCB_SHAPE>& aShapes )
{
if( bds.GetSeverity( aItem->GetErrorCode() ) == SEVERITY::RPT_SEVERITY_ERROR )
violations.push_back( *aItem );

8
qa/tests/pcbnew/drc/test_drc_regressions.cpp

@ -90,8 +90,8 @@ BOOST_FIXTURE_TEST_CASE( DRCFalsePositiveRegressions, DRC_REGRESSION_TEST_FIXTUR
bds.m_DRCSeverities[ DRCE_LIB_FOOTPRINT_MISMATCH ] = SEVERITY::RPT_SEVERITY_IGNORE;
bds.m_DRCEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
[&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
const std::vector<PCB_SHAPE>& aShapes )
{
if( bds.GetSeverity( aItem->GetErrorCode() ) == SEVERITY::RPT_SEVERITY_ERROR )
violations.push_back( *aItem );
@ -176,8 +176,8 @@ BOOST_FIXTURE_TEST_CASE( DRCFalseNegativeRegressions, DRC_REGRESSION_TEST_FIXTUR
bds.m_DRCSeverities[test] = severity;
bds.m_DRCEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
[&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
std::vector<PCB_SHAPE> aShapes )
{
markers.emplace_back( PCB_MARKER( aItem, aPos ) );

4
qa/tests/pcbnew/drc/test_drc_skew.cpp

@ -78,8 +78,8 @@ BOOST_FIXTURE_TEST_CASE( DRCSkew, DRC_REGRESSION_TEST_FIXTURE )
bds.m_DRCSeverities[ DRCE_SKEW_OUT_OF_RANGE ] = SEVERITY::RPT_SEVERITY_ERROR;
bds.m_DRCEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
[&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
const std::vector<PCB_SHAPE>& aShapes )
{
if( bds.GetSeverity( aItem->GetErrorCode() ) == SEVERITY::RPT_SEVERITY_ERROR )
violations.push_back( *aItem );

4
qa/tests/pcbnew/drc/test_drc_starved_thermal.cpp

@ -66,8 +66,8 @@ BOOST_FIXTURE_TEST_CASE( DRCStarvedThermal, DRC_REGRESSION_TEST_FIXTURE )
bds.m_DRCSeverities[DRCE_STARVED_THERMAL] = SEVERITY::RPT_SEVERITY_ERROR;
bds.m_DRCEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
[&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
const std::vector<PCB_SHAPE>& aShapes )
{
if( bds.GetSeverity( aItem->GetErrorCode() ) == SEVERITY::RPT_SEVERITY_ERROR )
violations.push_back( *aItem );

4
qa/tests/pcbnew/drc/test_drc_via_dangling.cpp

@ -47,8 +47,8 @@ BOOST_FIXTURE_TEST_CASE( DRCViaDanglingRuleTest, DRC_REGRESSION_TEST_FIXTURE )
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
bds.m_DRCEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
[&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
const std::vector<PCB_SHAPE>& aShapes )
{
PCB_MARKER temp( aItem, aPos );

4
qa/tests/pcbnew/drc/test_solder_mask_bridging.cpp

@ -58,8 +58,8 @@ BOOST_FIXTURE_TEST_CASE( DRCSolderMaskBridgingTest, DRC_SOLDER_MASK_BRIDGING_TES
bds.m_DRCSeverities[ DRCE_SILK_MASK_CLEARANCE ] = SEVERITY::RPT_SEVERITY_IGNORE;
bds.m_DRCEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
[&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
const std::vector<PCB_SHAPE>& aShapes )
{
PCB_MARKER temp( aItem, aPos );

4
qa/tests/pcbnew/test_tracks_cleaner.cpp

@ -207,8 +207,8 @@ BOOST_DATA_TEST_CASE_F( TRACK_CLEANER_TEST_FIXTURE, TrackCleanerRegressionTests,
bds.m_DRCSeverities[ DRCE_SOLDERMASK_BRIDGE ] = SEVERITY::RPT_SEVERITY_IGNORE;
bds.m_DRCEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
[&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
const std::vector<PCB_SHAPE>& aShapes )
{
if( aItem->GetErrorCode() == DRCE_UNCONNECTED_ITEMS )
violations.push_back( *aItem );

12
qa/tests/pcbnew/test_zone_filler.cpp

@ -103,8 +103,8 @@ BOOST_FIXTURE_TEST_CASE( BasicZoneFills, ZONE_FILL_TEST_FIXTURE )
bds.m_DRCEngine->InitEngine( wxFileName() ); // Just to be sure to be sure
bds.m_DRCEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
[&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
const std::vector<PCB_SHAPE>& aShapes )
{
if( aItem->GetErrorCode() == DRCE_CLEARANCE )
{
@ -198,8 +198,8 @@ BOOST_DATA_TEST_CASE_F( ZONE_FILL_TEST_FIXTURE, RegressionZoneFillTests,
std::vector<DRC_ITEM> violations;
bds.m_DRCEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
[&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
std::vector<PCB_SHAPE> aShapes )
{
if( aItem->GetErrorCode() == DRCE_CLEARANCE )
violations.push_back( *aItem );
@ -245,8 +245,8 @@ BOOST_DATA_TEST_CASE_F( ZONE_FILL_TEST_FIXTURE, RegressionSliverZoneFillTests,
std::vector<DRC_ITEM> violations;
bds.m_DRCEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer,
DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
[&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
std::vector<PCB_SHAPE> aShapes )
{
if( aItem->GetErrorCode() == DRCE_COPPER_SLIVER )
violations.push_back( *aItem );

4
qa/tools/drc_proto/drc_proto.cpp

@ -114,8 +114,8 @@ int runDRCProto( PROJECT_CONTEXT project, std::shared_ptr<KIGFX::VIEW_OVERLAY> a
drcEngine->SetProgressReporter( new CONSOLE_PROGRESS_REPORTER ( &consoleLog ) );
drcEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos,
int aLayer,DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
[&]( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos, int aLayer,
const std::vector<PCB_SHAPE>& aShapes )
{
// fixme
} );

Loading…
Cancel
Save