28 std::vector<std::unique_ptr<PCB_SHAPE>>& aOwned,
29 const std::set<const BOARD_ITEM*>* aExclude )
36 if( !aExclude || !aItem )
39 if( aExclude->count( aItem ) )
44 return parent && aExclude->count( parent );
52 if( !aDrawing || !aDrawing->IsOnLayer(
Edge_Cuts ) )
55 if( excluded( aDrawing ) )
67 aVector.push_back( shape );
74 for(
size_t i = 1; i < pts.size(); ++i )
76 if( pts[i - 1] == pts[i] )
80 seg->SetStart( pts[i - 1] );
81 seg->SetEnd( pts[i] );
82 aVector.push_back( seg.get() );
83 aOwned.push_back( std::move( seg ) );
88 addEdgeDrawing( drawing );
95 for(
BOARD_ITEM* drawing : fp->GraphicalItems() )
96 addEdgeDrawing( drawing );
109 std::shared_ptr<SHAPE_SEGMENT> hole = p->GetEffectiveHoleShape();
116 int radius = hole->GetWidth() / 2;
122 s->SetPosition( ptA );
123 aVector.push_back( s.get() );
124 aOwned.push_back( std::move( s ) );
133 seg1->SetStart( ptA + perp );
134 seg1->SetEnd( ptB + perp );
135 aVector.push_back( seg1.get() );
136 aOwned.push_back( std::move( seg1 ) );
139 seg2->SetStart( ptA - perp );
140 seg2->SetEnd( ptB - perp );
141 aVector.push_back( seg2.get() );
142 aOwned.push_back( std::move( seg2 ) );
145 auto arcA = std::make_unique<PCB_SHAPE>(
nullptr,
SHAPE_T::ARC );
146 arcA->SetArcGeometry( ptA + perp, midA, ptA - perp );
147 aVector.push_back( arcA.get() );
148 aOwned.push_back( std::move( arcA ) );
151 auto arcB = std::make_unique<PCB_SHAPE>(
nullptr,
SHAPE_T::ARC );
152 arcB->SetArcGeometry( ptB - perp, midB, ptB + perp );
153 aVector.push_back( arcB.get() );
154 aOwned.push_back( std::move( arcB ) );
162 std::vector<VECTOR2I>* aIntersectionPoints =
nullptr )
164 SEG segment( p1, p2 );
171 std::vector<VECTOR2I> rawPoints;
173 std::visit( visitor, geom1 );
177 std::vector<VECTOR2I> filtered;
185 return ( a - b ).SquaredEuclideanNorm() <= toleranceSq;
188 for(
const VECTOR2I& ip : rawPoints )
190 if( !coincident( ip, p1 ) && !coincident( ip, p2 ) )
191 filtered.push_back( ip );
194 if( aIntersectionPoints )
196 for(
const VECTOR2I& ip : filtered )
197 aIntersectionPoints->push_back( ip );
200 return !filtered.empty();
207 std::vector<VECTOR2I>& aIntersectionPoints )
209 if( p1 == p2 || p1 == q2 || q1 == p2 || q1 == q2 )
212 SEG segment1( p1, q1 );
213 SEG segment2( p2, q2 );
218 size_t startCount = aIntersectionPoints.size();
221 std::visit( visitor, geom1 );
223 return aIntersectionPoints.size() > startCount;
238 if( a->
GetType() == CREEP_SHAPE::TYPE::UNDEFINED )
244 if( a->
GetType() == CREEP_SHAPE::TYPE::CIRCLE )
262 if( a->
GetType() == CREEP_SHAPE::TYPE::POINT_TYPE )
265 if( a->
GetType() == CREEP_SHAPE::TYPE::CIRCLE )
273 double aMaxSquaredWeight )
const
275 std::vector<PATH_CONNECTION>
result;
277 double weight = ( this->
GetPos() - aS2.
GetPos() ).SquaredEuclideanNorm();
279 if( weight > aMaxSquaredWeight )
285 pc.
weight = sqrt( weight );
293 double aMaxSquaredWeight )
const
295 std::vector<PATH_CONNECTION>
result;
303 double pointToCenterDistanceSquared = ( pointPos - circleCenter ).SquaredEuclideanNorm();
304 double weightSquared = pointToCenterDistanceSquared - (float)
radius * (
float)
radius;
306 if( weightSquared > aMaxSquaredWeight )
310 direction1 = direction1.
Resize( 1 );
314 double radiusSquared = double(
radius ) * double(
radius );
316 double distance = sqrt( pointToCenterDistanceSquared );
317 double value1 = radiusSquared /
distance;
318 double value2 = sqrt( radiusSquared - value1 * value1 );
324 pc.
weight = sqrt( weightSquared );
326 resultPoint = direction1 * value1 + direction2 * value2 + circleCenter;
327 pc.
a2.
x = int( resultPoint.
x );
328 pc.
a2.
y = int( resultPoint.
y );
331 resultPoint = direction1 * value1 - direction2 * value2 + circleCenter;
332 pc.
a2.
x = int( resultPoint.
x );
333 pc.
a2.
y = int( resultPoint.
y );
342 std::pair<bool, bool>
result;
359 double pointAngle = testAngle.
AsRadians();
362 bool connectToEndPoint;
364 connectToEndPoint = ( cos( startAngle ) * newPoint.
x + sin( startAngle ) * newPoint.
y >= R );
367 connectToEndPoint &= ( cos( endAngle ) * newPoint.
x + sin( endAngle ) * newPoint.
y <= R );
369 connectToEndPoint |= ( cos( endAngle ) * newPoint.
x + sin( endAngle ) * newPoint.
y <= R )
370 && ( pointAngle >= endAngle || pointAngle <= startAngle );
372 result.first = !connectToEndPoint;
374 connectToEndPoint = ( cos( endAngle ) * newPoint.
x + sin( endAngle ) * newPoint.
y >= R );
377 connectToEndPoint &= ( cos( startAngle ) * newPoint.
x + sin( startAngle ) * newPoint.
y <= R );
379 connectToEndPoint |= ( cos( startAngle ) * newPoint.
x + sin( startAngle ) * newPoint.
y <= R )
380 && ( pointAngle >= endAngle || pointAngle <= startAngle );
382 result.second = !connectToEndPoint;
388 double aMaxSquaredWeight )
const
390 std::vector<PATH_CONNECTION>
result;
396 std::pair<bool, bool> behavesLikeCircle;
399 if( behavesLikeCircle.first && behavesLikeCircle.second )
402 return this->
Paths( csc, aMaxWeight, aMaxSquaredWeight );
405 if( behavesLikeCircle.first )
408 std::vector<PATH_CONNECTION> paths = this->
Paths( csc, aMaxWeight, aMaxSquaredWeight );
410 if( paths.size() > 1 )
411 result.push_back( paths[1] );
421 if( behavesLikeCircle.second )
424 std::vector<PATH_CONNECTION> paths = this->
Paths( csc, aMaxWeight, aMaxSquaredWeight );
426 if( paths.size() > 1 )
427 result.push_back( paths[0] );
441 double aMaxSquaredWeight )
const
443 std::vector<PATH_CONNECTION>
result;
451 double centerDistance = ( circleCenter - arcCenter ).EuclideanNorm();
453 if( centerDistance + arcRadius < circleRadius )
491 double aMaxSquaredWeight )
const
493 std::vector<PATH_CONNECTION>
result;
499 double centerDistance = ( circleCenter - arcCenter ).EuclideanNorm();
501 if( centerDistance + arcRadius < circleRadius )
513 aMaxWeight, aMaxSquaredWeight ) )
522 .
Paths( aS2, aMaxWeight, aMaxSquaredWeight ) )
535 double aMaxSquaredWeight )
const
537 std::vector<PATH_CONNECTION>
result;
542 VECTOR2D distSquared(
double( ( p2 - p1 ).x ),
double( ( p2 - p1 ).y ) );
548 double Rdiff = abs( R1 - R2 );
549 double Rsum = R1 + R2;
552 double weightSquared1 = weightSquared - Rdiff * Rdiff;
554 double weightSquared2 = weightSquared - Rsum * Rsum;
556 if( weightSquared1 <= aMaxSquaredWeight )
559 direction1 = direction1.
Resize( 1 );
562 double D = sqrt( weightSquared );
563 double ratio1 = ( R1 - R2 ) /
D;
564 double ratio2 = sqrt( 1 - ratio1 * ratio1 );
568 pc.
weight = sqrt( weightSquared1 );
570 pc.
a1 = p1 + direction1 * R1 * ratio1 + direction2 * R1 * ratio2;
571 pc.
a2 = p2 + direction1 * R2 * ratio1 + direction2 * R2 * ratio2;
575 pc.
a1 = p1 + direction1 * R1 * ratio1 - direction2 * R1 * ratio2;
576 pc.
a2 = p2 + direction1 * R2 * ratio1 - direction2 * R2 * ratio2;
580 if( weightSquared2 <= aMaxSquaredWeight )
583 direction1 = direction1.
Resize( 1 );
586 double D = sqrt( weightSquared );
587 double ratio1 = ( R1 + R2 ) /
D;
588 double ratio2 = sqrt( 1 - ratio1 * ratio1 );
592 pc.
weight = sqrt( weightSquared2 );
594 pc.
a1 = p1 + direction1 * R1 * ratio1 + direction2 * R1 * ratio2;
595 pc.
a2 = p2 - direction1 * R2 * ratio1 - direction2 * R2 * ratio2;
599 pc.
a1 = p1 + direction1 * R1 * ratio1 - direction2 * R1 * ratio2;
600 pc.
a2 = p2 - direction1 * R2 * ratio1 + direction2 * R2 * ratio2;
611 for(
const std::unique_ptr<CREEP_SHAPE>& shape : aShapes )
620 case CREEP_SHAPE::TYPE::POINT_TYPE:
AddNode( GRAPH_NODE::TYPE::POINT, p1, p1->
GetPos() );
break;
621 case CREEP_SHAPE::TYPE::CIRCLE:
AddNode( GRAPH_NODE::TYPE::CIRCLE, p1, p1->
GetPos() );
break;
622 case CREEP_SHAPE::TYPE::ARC:
AddNode( GRAPH_NODE::TYPE::ARC, p1, p1->
GetPos() );
break;
631 [](
const auto& a,
const auto& b ) { return compareShapes( a.get(), b.get() ); } );
656 std::vector<BOX2I> cutouts;
672 for(
size_t j = i + 1; j < cutouts.size(); ++j )
674 if( cutouts[i].Intersects( cutouts[j] ) && !cutouts[i].Contains( cutouts[j] )
675 && !cutouts[j].Contains( cutouts[i] ) )
694 auto a = std::make_unique<BE_SHAPE_POINT>( d->
GetStart() );
697 a = std::make_unique<BE_SHAPE_POINT>( d->
GetEnd() );
725 while( endAngle < startAngle )
728 auto arc = std::make_unique<BE_SHAPE_ARC>(
center, r, startAngle, endAngle,
739 addArc( { x1 + r, y1 + r }, { x1 + r, y2 }, { x1 + r, y1 } );
740 addArc( { x2 - r, y1 + r }, { x2 - r, y1 }, { x2 - r, y2 } );
742 else if( w == 2 * r )
745 addArc( { x1 + r, y1 + r }, { x1, y1 + r }, { x2, y1 + r } );
746 addArc( { x1 + r, y2 - r }, { x2, y2 - r }, { x1, y2 - r } );
751 addArc( { x1 + r, y1 + r }, { x1, y1 + r }, { x1 + r, y1 } );
752 addArc( { x2 - r, y1 + r }, { x2 - r, y1 }, { x2, y1 + r } );
753 addArc( { x2 - r, y2 - r }, { x2, y2 - r }, { x2 - r, y2 } );
754 addArc( { x1 + r, y2 - r }, { x1 + r, y2 }, { x1, y2 - r } );
759 auto a = std::make_unique<BE_SHAPE_POINT>( d->
GetStart() );
762 a = std::make_unique<BE_SHAPE_POINT>( d->
GetEnd() );
779 auto a = std::make_unique<BE_SHAPE_POINT>( p );
797 double tolerance = 10;
828 if(
n1->m_type == GRAPH_NODE::TYPE::VIRTUAL ||
n2->m_type == GRAPH_NODE::TYPE::VIRTUAL )
832 &&
n1->m_parent ==
n2->m_parent
833 &&
n1->m_parent->GetType() == CREEP_SHAPE::TYPE::CIRCLE )
840 if( R1.
Cross( R2 ) > 0 )
852 aShapes.push_back( s );
857 &&
n1->m_parent ==
n2->m_parent
858 &&
n1->m_parent->GetType() == CREEP_SHAPE::TYPE::ARC )
867 if( R1.
Cross( R2 ) > 0 )
882 EDA_ANGLE midAngle = arc->AngleBetweenStartAndEnd( mid );
884 if( midAngle > arc->GetEndAngle() )
893 aShapes.push_back( s );
901 aShapes.push_back( s );
932 EDA_ANGLE maxAngle = angle1 > angle2 ? angle1 : angle2;
935 skipAngle += skipAngle;
936 EDA_ANGLE pointAngle = maxAngle - skipAngle;
946 pc.
a1 = maxAngle == angle2 ? a1->m_pos : a2->m_pos;
952 pc.
a2 = maxAngle == angle2 ? a2->m_pos : a1->m_pos;
955 std::shared_ptr<GRAPH_CONNECTION> gc = aG.
AddConnection( gnt, maxAngle == angle2 ? a2 : a1, pc );
958 gc->m_forceStraightLine =
true;
978 double delta = a2r - a1r;
985 for(
int i = 0; i <= 8; ++i )
987 double a = a1r +
delta * i / 8.0;
995 VECTOR2D distI( a1->m_pos - a2->m_pos );
996 VECTOR2D distD(
double( distI.
x ),
double( distI.
y ) );
1008 pc.
weight = std::max( weight, 0.0 );
1037 for(
int i = 0; i <= 8; ++i )
1039 double a = a1r + ( a2r - a1r ) * i / 8.0;
1047 double weight = abs(
m_radius * ( angle2 - angle1 ).AsRadians() );
1076 double aMaxSquaredWeight )
const
1078 std::vector<PATH_CONNECTION>
result;
1081 double halfWidth = this->
GetWidth() / 2;
1085 double length = ( start -
end ).EuclideanNorm();
1086 double projectedPos = cos( trackAngle.
AsRadians() ) * ( pointPos.
x - start.
x )
1087 + sin( trackAngle.
AsRadians() ) * ( pointPos.
y - start.
y );
1091 if( projectedPos <= 0 )
1093 newPoint = start + ( pointPos - start ).Resize( halfWidth );
1095 else if( projectedPos >= length )
1097 newPoint =
end + ( pointPos -
end ).Resize( halfWidth );
1101 double posOnSegment = ( start - pointPos ).SquaredEuclideanNorm()
1102 - (
end - pointPos ).SquaredEuclideanNorm();
1103 posOnSegment = posOnSegment / ( 2 * length ) + length / 2;
1105 newPoint = start + (
end - start ).Resize( posOnSegment );
1106 newPoint += ( pointPos - newPoint ).Resize( halfWidth );
1109 double weightSquared = ( pointPos - newPoint ).SquaredEuclideanNorm();
1111 if( weightSquared > aMaxSquaredWeight )
1117 pc.
weight = sqrt( weightSquared );
1125 double aMaxSquaredWeight )
const
1127 std::vector<PATH_CONNECTION>
result;
1130 double halfWidth = this->
GetWidth() / 2;
1134 double length = ( start -
end ).EuclideanNorm();
1137 double weightSquared = std::numeric_limits<double>::infinity();
1138 VECTOR2I PointOnTrack, PointOnCircle;
1142 double projectedPos1 = cos( trackAngle.
AsRadians() ) * ( circleCenter.
x - start.
x )
1143 + sin( trackAngle.
AsRadians() ) * ( circleCenter.
y - start.
y );
1144 double projectedPos2 = projectedPos1 + circleRadius;
1145 projectedPos1 = projectedPos1 - circleRadius;
1147 double trackSide = (
end - start ).Cross( circleCenter - start ) > 0 ? 1 : -1;
1149 if( ( projectedPos1 < 0 && projectedPos2 < 0 ) )
1157 else if( ( projectedPos1 > length && projectedPos2 > length ) )
1165 else if( ( projectedPos1 >= 0 ) && ( projectedPos1 <= length ) && ( projectedPos2 >= 0 )
1166 && ( projectedPos2 <= length ) )
1169 PointOnTrack = start;
1170 PointOnTrack += (
end - start ).Resize( projectedPos1 );
1171 PointOnTrack += (
end - start ).Perpendicular().
Resize( halfWidth ) * trackSide;
1172 PointOnCircle = circleCenter - (
end - start ).Resize( circleRadius );
1173 weightSquared = ( PointOnCircle - PointOnTrack ).SquaredEuclideanNorm();
1175 if( weightSquared < aMaxSquaredWeight )
1178 pc.
a1 = PointOnTrack;
1179 pc.
a2 = PointOnCircle;
1180 pc.
weight = sqrt( weightSquared );
1184 PointOnTrack = start;
1185 PointOnTrack += (
end - start ).Resize( projectedPos2 );
1186 PointOnTrack += (
end - start ).Perpendicular().
Resize( halfWidth ) * trackSide;
1187 PointOnCircle = circleCenter + (
end - start ).Resize( circleRadius );
1190 pc.
a1 = PointOnTrack;
1191 pc.
a2 = PointOnCircle;
1196 else if( ( ( projectedPos1 >= 0 ) && ( projectedPos1 <= length ) )
1197 && ( ( projectedPos2 > length ) || projectedPos2 < 0 ) )
1200 std::vector<PATH_CONNECTION> pcs = csc.
Paths( aS2, aMaxWeight, aMaxSquaredWeight );
1202 if( pcs.size() < 2 )
1205 result.push_back( pcs.at( trackSide == 1 ? 1 : 0 ) );
1208 PointOnTrack = start;
1209 PointOnTrack += (
end - start ).Resize( projectedPos1 );
1210 PointOnTrack += (
end - start ).Perpendicular().
Resize( halfWidth ) * trackSide;
1211 PointOnCircle = circleCenter - (
end - start ).Resize( circleRadius );
1212 weightSquared = ( PointOnCircle - PointOnTrack ).SquaredEuclideanNorm();
1214 if( weightSquared < aMaxSquaredWeight )
1217 pc.
a1 = PointOnTrack;
1218 pc.
a2 = PointOnCircle;
1219 pc.
weight = sqrt( weightSquared );
1224 else if( ( ( projectedPos2 >= 0 ) && ( projectedPos2 <= length ) )
1225 && ( ( projectedPos1 > length ) || projectedPos1 < 0 ) )
1228 std::vector<PATH_CONNECTION> pcs = csc.
Paths( aS2, aMaxWeight, aMaxSquaredWeight );
1230 if( pcs.size() < 2 )
1233 result.push_back( pcs.at( trackSide == 1 ? 0 : 1 ) );
1235 PointOnTrack = start;
1236 PointOnTrack += (
end - start ).Resize( projectedPos2 );
1237 PointOnTrack += (
end - start ).Perpendicular().
Resize( halfWidth ) * trackSide;
1238 PointOnCircle = circleCenter + (
end - start ).Resize( circleRadius );
1239 weightSquared = ( PointOnCircle - PointOnTrack ).SquaredEuclideanNorm();
1241 if( weightSquared < aMaxSquaredWeight )
1244 pc.
a1 = PointOnTrack;
1245 pc.
a2 = PointOnCircle;
1246 pc.
weight = sqrt( weightSquared );
1251 else if( projectedPos1 < 0 && projectedPos2 > length )
1256 std::vector<PATH_CONNECTION> startPcs = cscStart.
Paths( aS2, aMaxWeight, aMaxSquaredWeight );
1258 if( startPcs.size() >= 2 )
1259 result.push_back( startPcs.at( trackSide == 1 ? 0 : 1 ) );
1262 std::vector<PATH_CONNECTION> endPcs = cscEnd.
Paths( aS2, aMaxWeight, aMaxSquaredWeight );
1264 if( endPcs.size() >= 2 )
1265 result.push_back( endPcs.at( trackSide == 1 ? 1 : 0 ) );
1273 double aMaxSquaredWeight )
const
1275 std::vector<PATH_CONNECTION>
result;
1299 if( !
segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle, beArcEndAngle ) )
1305 if( !
segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle, beArcEndAngle ) )
1315 double aMaxSquaredWeight )
const
1317 std::vector<PATH_CONNECTION>
result;
1340 if( !
segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle, beArcEndAngle ) )
1346 if( !
segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle, beArcEndAngle ) )
1356 double aMaxSquaredWeight )
const
1358 std::vector<PATH_CONNECTION>
result;
1387 double aMaxSquaredWeight )
const
1389 std::vector<PATH_CONNECTION>
result;
1412 if( !
segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle, beArcEndAngle ) )
1418 if( !
segmentIntersectsArc( pc.a1, pc.a2, beArcPos, beArcRadius, beArcStartAngle, beArcEndAngle ) )
1428 double aMaxSquaredWeight )
const
1430 std::vector<PATH_CONNECTION>
result;
1435 double weight = (
center - point ).EuclideanNorm() - R;
1437 if( weight > aMaxWeight )
1441 pc.
weight = std::max( weight, 0.0 );
1451 double aMaxSquaredWeight )
const
1453 std::vector<PATH_CONNECTION>
result;
1460 if( ( C1 - C2 ).SquaredEuclideanNorm() < ( R1 - R2 ) * ( R1 - R2 ) )
1466 double weight = ( C1 - C2 ).EuclideanNorm() - R1 - R2;
1468 if( weight > aMaxWeight || weight < 0 )
1472 pc.
weight = std::max( weight, 0.0 );
1473 pc.
a1 = ( C2 - C1 ).Resize( R1 ) + C1;
1474 pc.
a2 = ( C1 - C2 ).Resize( R2 ) + C2;
1481 double aMaxSquaredWeight )
const
1483 std::vector<PATH_CONNECTION>
result;
1487 double halfWidth = this->
GetWidth() / 2;
1489 EDA_ANGLE trackAngle( s_end - s_start );
1492 double length = ( s_start - s_end ).EuclideanNorm();
1493 double projectedPos = cos( trackAngle.
AsRadians() ) * ( pointPos.
x - s_start.
x )
1494 + sin( trackAngle.
AsRadians() ) * ( pointPos.
y - s_start.
y );
1496 if( ( projectedPos <= 0 ) || ( s_start == s_end ) )
1499 return csc.
Paths( aS2, aMaxWeight, aMaxSquaredWeight );
1502 if( projectedPos >= length )
1505 return csc.
Paths( aS2, aMaxWeight, aMaxSquaredWeight );
1509 double trackSide = ( s_end - s_start ).Cross( pointPos - s_start ) > 0 ? 1 : -1;
1512 pc.
a1 = s_start + ( s_end - s_start ).Resize( projectedPos )
1513 + ( s_end - s_start ).Perpendicular().
Resize( halfWidth ) * trackSide;
1514 pc.
a2 = ( pc.
a1 - pointPos ).Resize(
radius ) + pointPos;
1515 pc.
weight = ( pc.
a2 - pc.
a1 ).SquaredEuclideanNorm();
1517 if( pc.
weight <= aMaxSquaredWeight )
1528 double aMaxSquaredWeight )
const
1530 std::vector<PATH_CONNECTION>
result;
1535 double circleRadius = this->
GetRadius();
1543 if( ( circlePos - arcPos ).EuclideanNorm() > arcRadius + circleRadius )
1545 const std::vector<PATH_CONNECTION>& pcs = this->
Paths( csc, aMaxWeight, aMaxSquaredWeight );
1547 if( pcs.size() == 1 )
1553 result.push_back( pcs[0] );
1565 std::vector<PATH_CONNECTION> pcs1 = this->
Paths( csc1, aMaxWeight, aMaxSquaredWeight );
1566 std::vector<PATH_CONNECTION> pcs2 = this->
Paths( csc2, aMaxWeight, aMaxSquaredWeight );
1570 if( !bestPath || ( ( bestPath->
weight > pc.weight ) && ( pc.weight > 0 ) ) )
1576 if( !bestPath || ( ( bestPath->
weight > pc.weight ) && ( pc.weight > 0 ) ) )
1584 if( ( circlePos - arcPos ).SquaredEuclideanNorm() < arcRadius * arcRadius )
1586 if( circlePos != arcPos )
1592 pc3.
weight = std::max( arcRadius - ( circlePos - arcPos ).EuclideanNorm() - circleRadius, 0.0 );
1593 pc3.
a1 = circlePos + ( circlePos - arcPos ).Resize( circleRadius );
1594 pc3.
a2 = arcPos + ( circlePos - arcPos ).Resize( arcRadius - aS2.
GetWidth() / 2 );
1602 if( bestPath && bestPath->
weight > 0 )
1604 result.push_back( *bestPath );
1612 double aMaxSquaredWeight )
const
1614 std::vector<PATH_CONNECTION>
result;
1618 double halfWidth1 = this->
GetWidth() / 2;
1622 double halfWidth2 = aS2.
GetWidth() / 2;
1627 std::vector<PATH_CONNECTION> pcs;
1628 pcs = this->
Paths( csc, aMaxWeight, aMaxSquaredWeight );
1630 if( pcs.size() < 1 )
1636 if( pcs.size() > 0 )
1638 circlePoint = pcs[0].a1;
1642 if( testAngle < aS2.
GetEndAngle() && pcs.size() > 0 )
1644 result.push_back( pcs[0] );
1654 if( !bestPath || ( bestPath->
weight > pc.weight ) )
1660 if( !bestPath || ( bestPath->
weight > pc.weight ) )
1669 if( !bestPath || ( bestPath->
weight > pc.weight ) )
1676 if( !bestPath || ( bestPath->
weight > pc.weight ) )
1681 result.push_back( *bestPath );
1700 t = std::max( 0.0, std::min( 1.0, t ) );
1702 return A + ( AB * t );
1708 double aMaxSquaredWeight )
const
1710 std::vector<PATH_CONNECTION>
result;
1714 double halfWidth1 = this->
GetWidth() / 2;
1719 double halfWidth2 = aS2.
GetWidth() / 2;
1727 double dist1 = ( P1 -
C ).SquaredEuclideanNorm();
1728 double dist2 = ( P2 -
D ).SquaredEuclideanNorm();
1729 double dist3 = ( P3 -
A ).SquaredEuclideanNorm();
1730 double dist4 = ( P4 -
B ).SquaredEuclideanNorm();
1733 double min_dist = dist1;
1737 if( dist2 < min_dist )
1744 if( dist3 < min_dist )
1751 if( dist4 < min_dist )
1760 pc.
a1 = closest1 + ( closest2 - closest1 ).Resize( halfWidth1 );
1761 pc.
a2 = closest2 + ( closest1 - closest2 ).Resize( halfWidth2 );
1762 pc.
weight = std::max( sqrt( min_dist ) - halfWidth1 - halfWidth2, 0.0 );
1764 if( pc.
weight <= aMaxWeight )
1772 double aMaxSquaredWeight )
const
1774 std::vector<PATH_CONNECTION>
result;
1780 double dist = ( center1 - center2 ).EuclideanNorm();
1784 double reach = aMaxWeight + R1;
1786 if( dist == 0 || dist * dist > reach * reach + R2 * R2 )
1795 double weight = std::max( R2 - dist - R1, 0.0 );
1797 if( weight > aMaxWeight )
1800 double radialAngle = circleAngle +
M_PI;
1801 double cx = cos( radialAngle );
1802 double cy = sin( radialAngle );
1818 double weight = sqrt( dist * dist - R2 * R2 ) - R1;
1819 double theta = asin( R2 / dist );
1820 double psi = acos( R2 / dist );
1822 if( weight > aMaxWeight )
1826 pc.
weight = std::max( weight, 0.0 );
1831 pStart =
VECTOR2I( R1 * cos( theta + circleAngle ), R1 * sin( theta + circleAngle ) );
1833 pEnd =
VECTOR2I( -R2 * cos( psi - circleAngle ), R2 * sin( psi - circleAngle ) );
1840 pStart =
VECTOR2I( R1 * cos( -theta + circleAngle ), R1 * sin( -theta + circleAngle ) );
1842 pEnd =
VECTOR2I( -R2 * cos( -psi - circleAngle ), R2 * sin( -psi - circleAngle ) );
1854 double aMaxSquaredWeight )
const
1856 std::vector<PATH_CONNECTION>
result;
1872 if( ( point - arcCenter ).SquaredEuclideanNorm() >
radius *
radius )
1875 return circle.Paths( aS2, aMaxWeight, aMaxSquaredWeight );
1880 pc.
weight = std::max( (
radius - width / 2 ) - ( point - arcCenter ).EuclideanNorm(), 0.0 );
1881 pc.
a1 = ( point - arcCenter ).Resize(
radius - width / 2 ) + arcCenter;
1894 if( ( point - this->
GetStartPoint() ).SquaredEuclideanNorm()
1895 > ( point - this->
GetEndPoint() ).SquaredEuclideanNorm() )
1905 return circle.Paths( aS2, aMaxWeight, aMaxSquaredWeight );
1911 double aMaxSquaredWeight )
const
1913 std::vector<PATH_CONNECTION>
result;
1922 bestPath.
weight = std::numeric_limits<double>::infinity();
1931 for(
const std::vector<PATH_CONNECTION>& pcs : { csc1.
Paths( csc2, aMaxWeight, aMaxSquaredWeight ),
1932 this->
Paths( csc2, aMaxWeight, aMaxSquaredWeight ),
1933 csc1.
Paths( aS2, aMaxWeight, aMaxSquaredWeight ) } )
1945 for(
const std::vector<PATH_CONNECTION>& pcs : { this->
Paths( csc5, aMaxWeight, aMaxSquaredWeight ),
1946 this->
Paths( csc6, aMaxWeight, aMaxSquaredWeight ),
1947 csc3.
Paths( aS2, aMaxWeight, aMaxSquaredWeight ),
1948 csc4.
Paths( aS2, aMaxWeight, aMaxSquaredWeight ) } )
1952 if( bestPath.
weight > pc.weight )
1957 if( bestPath.
weight != std::numeric_limits<double>::infinity() )
1958 result.push_back( bestPath );
1965 std::vector<VECTOR2I>* aIntersectPoints )
1967 SEG segment( p1, p2 );
1970 std::vector<VECTOR2I> intersectionPoints;
1975 std::visit( visitor, geom1 );
1983 return ( a - b ).SquaredEuclideanNorm() <= toleranceSq;
1986 std::vector<VECTOR2I> filtered;
1988 for(
const VECTOR2I& ip : intersectionPoints )
1990 if( !coincident( ip, p1 ) && !coincident( ip, p2 ) )
1991 filtered.push_back( ip );
1994 if( aIntersectPoints )
1997 aIntersectPoints->push_back( point );
2000 return filtered.size() > 0;
2004 const std::vector<BOARD_ITEM*>& aBe,
2005 const std::vector<const BOARD_ITEM*>& aDontTestAgainst,
2006 int aMinGrooveWidth )
2008 std::vector<VECTOR2I> intersectionPoints;
2009 bool TestGrooveWidth = aMinGrooveWidth > 0;
2013 if( count( aDontTestAgainst.begin(), aDontTestAgainst.end(), be ) > 0 )
2026 if( intersects && !TestGrooveWidth )
2048 bool intersects =
false;
2053 intersectionPoints );
2055 intersectionPoints );
2061 intersectionPoints );
2063 intersectionPoints );
2066 if( intersects && !TestGrooveWidth )
2072 struct CornerArcRange
2079 std::vector<CornerArcRange> arcs;
2086 arcs.push_back( { { x1 + r, y1 + r },
2089 arcs.push_back( { { x2 - r, y1 + r },
2093 else if( w == 2 * r )
2096 arcs.push_back( { { x1 + r, y1 + r },
2099 arcs.push_back( { { x1 + r, y2 - r },
2117 for(
const CornerArcRange& ca : arcs )
2120 ca.startAngle, ca.endAngle,
2121 &intersectionPoints );
2123 if( arcIntersects && !TestGrooveWidth )
2134 bool intersects =
false;
2140 if( intersects && !TestGrooveWidth )
2151 if( points.size() < 2 )
2154 VECTOR2I prevPoint = points.back();
2156 bool intersects =
false;
2164 if( intersects && !TestGrooveWidth )
2177 if( intersects && !TestGrooveWidth )
2193 if( intersects && !TestGrooveWidth )
2204 if( intersectionPoints.size() <= 0 )
2207 if( intersectionPoints.size() % 2 != 0 )
2210 int minx = intersectionPoints[0].x;
2211 int maxx = intersectionPoints[0].x;
2212 int miny = intersectionPoints[0].y;
2213 int maxy = intersectionPoints[0].y;
2215 for(
const VECTOR2I& v : intersectionPoints )
2217 minx = v.x < minx ? v.x : minx;
2218 maxx = v.x > maxx ? v.x : maxx;
2219 miny = v.x < miny ? v.x : miny;
2220 maxy = v.x > maxy ? v.x : maxy;
2223 if( abs( maxx - minx ) > abs( maxy - miny ) )
2225 std::sort( intersectionPoints.begin(), intersectionPoints.end(),
2233 std::sort( intersectionPoints.begin(), intersectionPoints.end(),
2240 int GVSquared = aMinGrooveWidth * aMinGrooveWidth;
2242 for(
size_t i = 0; i < intersectionPoints.size(); i += 2 )
2244 if( intersectionPoints[i].SquaredDistance( intersectionPoints[i + 1] ) > GVSquared )
2254 double maxWeight = aMaxWeight;
2255 double maxWeightSquared = maxWeight * maxWeight;
2256 std::vector<PATH_CONNECTION>
result;
2275 if( cuarc1 && cuarc2 )
2276 return cuarc1->
Paths( *cuarc2, maxWeight, maxWeightSquared );
2277 if( cuarc1 && cucircle2 )
2278 return cuarc1->
Paths( *cucircle2, maxWeight, maxWeightSquared );
2279 if( cuarc1 && cusegment2 )
2280 return cuarc1->
Paths( *cusegment2, maxWeight, maxWeightSquared );
2281 if( cucircle1 && cuarc2 )
2282 return cucircle1->
Paths( *cuarc2, maxWeight, maxWeightSquared );
2283 if( cucircle1 && cucircle2 )
2284 return cucircle1->
Paths( *cucircle2, maxWeight, maxWeightSquared );
2285 if( cucircle1 && cusegment2 )
2286 return cucircle1->
Paths( *cusegment2, maxWeight, maxWeightSquared );
2287 if( cusegment1 && cuarc2 )
2288 return cusegment1->
Paths( *cuarc2, maxWeight, maxWeightSquared );
2289 if( cusegment1 && cucircle2 )
2290 return cusegment1->
Paths( *cucircle2, maxWeight, maxWeightSquared );
2291 if( cusegment1 && cusegment2 )
2292 return cusegment1->
Paths( *cusegment2, maxWeight, maxWeightSquared );
2297 if( cuarc1 && bearc2 )
2298 return cuarc1->
Paths( *bearc2, maxWeight, maxWeightSquared );
2299 if( cuarc1 && becircle2 )
2300 return cuarc1->
Paths( *becircle2, maxWeight, maxWeightSquared );
2301 if( cuarc1 && bepoint2 )
2302 return cuarc1->
Paths( *bepoint2, maxWeight, maxWeightSquared );
2303 if( cucircle1 && bearc2 )
2304 return cucircle1->
Paths( *bearc2, maxWeight, maxWeightSquared );
2305 if( cucircle1 && becircle2 )
2306 return cucircle1->
Paths( *becircle2, maxWeight, maxWeightSquared );
2307 if( cucircle1 && bepoint2 )
2308 return cucircle1->
Paths( *bepoint2, maxWeight, maxWeightSquared );
2309 if( cusegment1 && bearc2 )
2310 return cusegment1->
Paths( *bearc2, maxWeight, maxWeightSquared );
2311 if( cusegment1 && becircle2 )
2312 return cusegment1->
Paths( *becircle2, maxWeight, maxWeightSquared );
2313 if( cusegment1 && bepoint2 )
2314 return cusegment1->
Paths( *bepoint2, maxWeight, maxWeightSquared );
2318 if( cuarc2 && bearc1 )
2319 return bearc1->
Paths( *cuarc2, maxWeight, maxWeightSquared );
2320 if( cuarc2 && becircle1 )
2321 return becircle1->
Paths( *cuarc2, maxWeight, maxWeightSquared );
2322 if( cuarc2 && bepoint1 )
2323 return bepoint1->
Paths( *cuarc2, maxWeight, maxWeightSquared );
2324 if( cucircle2 && bearc1 )
2325 return bearc1->
Paths( *cucircle2, maxWeight, maxWeightSquared );
2326 if( cucircle2 && becircle1 )
2327 return becircle1->
Paths( *cucircle2, maxWeight, maxWeightSquared );
2328 if( cucircle2 && bepoint1 )
2329 return bepoint1->
Paths( *cucircle2, maxWeight, maxWeightSquared );
2330 if( cusegment2 && bearc1 )
2331 return bearc1->
Paths( *cusegment2, maxWeight, maxWeightSquared );
2332 if( cusegment2 && becircle1 )
2333 return becircle1->
Paths( *cusegment2, maxWeight, maxWeightSquared );
2334 if( cusegment2 && bepoint1 )
2335 return bepoint1->
Paths( *cusegment2, maxWeight, maxWeightSquared );
2340 if( bearc1 && bearc2 )
2341 return bearc1->
Paths( *bearc2, maxWeight, maxWeightSquared );
2342 if( bearc1 && becircle2 )
2343 return bearc1->
Paths( *becircle2, maxWeight, maxWeightSquared );
2344 if( bearc1 && bepoint2 )
2345 return bearc1->
Paths( *bepoint2, maxWeight, maxWeightSquared );
2346 if( becircle1 && bearc2 )
2347 return becircle1->
Paths( *bearc2, maxWeight, maxWeightSquared );
2348 if( becircle1 && becircle2 )
2349 return becircle1->
Paths( *becircle2, maxWeight, maxWeightSquared );
2350 if( becircle1 && bepoint2 )
2351 return becircle1->
Paths( *bepoint2, maxWeight, maxWeightSquared );
2352 if( bepoint1 && bearc2 )
2353 return bepoint1->
Paths( *bearc2, maxWeight, maxWeightSquared );
2354 if( bepoint1 && becircle2 )
2355 return bepoint1->
Paths( *becircle2, maxWeight, maxWeightSquared );
2356 if( bepoint1 && bepoint2 )
2357 return bepoint1->
Paths( *bepoint2, maxWeight, maxWeightSquared );
2363 std::vector<std::shared_ptr<GRAPH_CONNECTION>>& aResult )
2365 if( !aFrom || !aTo )
2372 std::unordered_map<GRAPH_NODE*, double> distances;
2373 std::unordered_map<GRAPH_NODE*, GRAPH_NODE*> previous;
2378 using QUEUE_ITEM = std::pair<double, GRAPH_NODE*>;
2380 auto cmp = [](
const QUEUE_ITEM& aLeft,
const QUEUE_ITEM& aRight )
2382 if( aLeft.first == aRight.first )
2383 return aLeft.second > aRight.second;
2384 return aLeft.first > aRight.first;
2386 std::priority_queue<QUEUE_ITEM, std::vector<QUEUE_ITEM>,
decltype( cmp )> pq( cmp );
2389 for(
const std::shared_ptr<GRAPH_NODE>& node :
m_nodes )
2391 if( node !=
nullptr )
2392 distances[node.get()] = std::numeric_limits<double>::infinity();
2395 distances[aFrom.get()] = 0.0;
2396 distances[aTo.get()] = std::numeric_limits<double>::infinity();
2397 pq.push( { 0.0, aFrom.get() } );
2400 while( !pq.empty() )
2402 auto [dist, current] = pq.top();
2407 if( dist > distances[current] )
2410 if( current == aTo.get() )
2416 for(
const std::shared_ptr<GRAPH_CONNECTION>& connection : current->m_node_conns )
2418 GRAPH_NODE* neighbor = ( connection->n1 ).get() == current ? ( connection->n2 ).get()
2419 : ( connection->n1 ).get();
2425 if( connection->m_path.weight < 0.0 )
2427 wxLogTrace(
"CREEPAGE",
"Negative weight connection found. Ignoring connection." );
2431 double alt = distances[current] + connection->m_path.weight;
2433 if( alt < distances[neighbor] )
2435 distances[neighbor] = alt;
2436 previous[neighbor] = current;
2437 pq.push( { alt, neighbor } );
2442 double pathWeight = distances[aTo.get()];
2445 if( pathWeight == std::numeric_limits<double>::infinity() )
2446 return std::numeric_limits<double>::infinity();
2451 while( step != aFrom.get() )
2455 for(
const std::shared_ptr<GRAPH_CONNECTION>& node_conn : step->
m_node_conns )
2457 if( ( ( node_conn->n1 ).get() == prevNode && ( node_conn->n2 ).get() == step )
2458 || ( ( node_conn->n1 ).get() == step && ( node_conn->n2 ).get() == prevNode ) )
2460 aResult.push_back( node_conn );
2473 std::unique_ptr<CREEP_SHAPE> newshape;
2478 switch( aShape.
Type() )
2483 newshape = std::make_unique<CU_SHAPE_SEGMENT>( segment.
GetSeg().
A, segment.
GetSeg().
B,
2491 newshape = std::make_unique<CU_SHAPE_CIRCLE>(
circle.GetCenter(),
circle.GetRadius() );
2506 start = arc.
GetP0();
2512 start = arc.
GetP1();
2518 auto cuarc = std::make_unique<CU_SHAPE_ARC>( edaArc.
getCenter(), edaArc.
GetRadius(), alpha, beta,
2521 newshape = std::move( cuarc );
2527 int nbShapes =
static_cast<const SHAPE_COMPOUND*
>( &aShape )->Shapes().size();
2528 for(
const SHAPE* subshape : (
static_cast<const SHAPE_COMPOUND*
>( &aShape )->Shapes() ) )
2533 if( !( ( subshape->Type() ==
SH_RECT ) && ( nbShapes == 5 ) ) )
2534 Addshape( *subshape, aConnectTo, aParent );
2546 const SEG object = *it;
2548 Addshape( segment, aConnectTo, aParent );
2563 Addshape( segment, aConnectTo, aParent );
2586 if( point != prevPoint )
2618 std::shared_ptr<GRAPH_NODE> gnShape =
nullptr;
2620 newshape->SetParent( aParent );
2622 switch( aShape.
Type() )
2633 gnShape->m_net = aConnectTo->m_net;
2634 std::shared_ptr<GRAPH_CONNECTION> gc =
AddConnection( gnShape, aConnectTo );
2637 gc->m_path.m_show =
false;
2642 const std::set<int>* aRelevantNets )
2644 auto irrelevantPair = [&](
const std::shared_ptr<GRAPH_NODE>& gn1,
2645 const std::shared_ptr<GRAPH_NODE>& gn2 ) ->
bool
2647 return aRelevantNets && gn1->m_parent && gn2->m_parent && gn1->m_parent->IsConductive()
2648 && gn2->m_parent->IsConductive() && !aRelevantNets->count( gn1->m_net )
2649 && !aRelevantNets->count( gn2->m_net );
2652 std::vector<std::shared_ptr<GRAPH_NODE>> nodes;
2653 std::mutex nodes_lock;
2656 std::vector<CREEPAGE_TRACK_ENTRY*> trackEntries;
2657 TRACK_RTREE::Builder trackBuilder;
2665 std::shared_ptr<SHAPE> sh = track->GetEffectiveShape();
2670 entry->
segment =
SEG( track->GetStart(), track->GetEnd() );
2671 entry->
layer = aLayer;
2672 entry->
halfWidth = track->GetWidth() / 2;
2673 entry->
track = track;
2675 BOX2I bbox = track->GetBoundingBox();
2676 int minCoords[2] = { bbox.
GetX(), bbox.
GetY() };
2678 trackBuilder.Add( minCoords, maxCoords, entry );
2679 trackEntries.push_back( entry );
2687 std::copy_if(
m_nodes.begin(),
m_nodes.end(), std::back_inserter( nodes ),
2688 [&](
const std::shared_ptr<GRAPH_NODE>& gn )
2690 return gn && gn->m_parent && gn->m_connectDirectly && ( gn->m_type != GRAPH_NODE::TYPE::VIRTUAL );
2693 std::sort( nodes.begin(), nodes.end(),
2694 [](
const std::shared_ptr<GRAPH_NODE>& gn1,
const std::shared_ptr<GRAPH_NODE>& gn2 )
2696 return gn1->m_parent < gn2->m_parent
2697 || ( gn1->m_parent == gn2->m_parent && gn1->m_net < gn2->m_net );
2702 std::unordered_map<const BOARD_ITEM*, std::unordered_map<int, std::vector<std::shared_ptr<GRAPH_NODE>>>> parent_net_groups;
2703 std::unordered_map<const BOARD_ITEM*, BOX2I> parent_bboxes;
2704 std::vector<const BOARD_ITEM*> parent_keys;
2706 for(
const auto& gn : nodes )
2708 const BOARD_ITEM* parent = gn->m_parent->GetParent();
2710 if( parent_net_groups[parent].
empty() )
2712 parent_keys.push_back( parent );
2717 parent_net_groups[parent][gn->m_net].push_back( gn );
2721 std::vector<std::pair<std::shared_ptr<GRAPH_NODE>, std::shared_ptr<GRAPH_NODE>>> work_items;
2726 int64_t maxDist =
static_cast<int64_t
>( aMaxWeight );
2734 std::vector<ParentEntry> parentEntries;
2736 for(
const auto* parent : parent_keys )
2741 entry.parent = parent;
2742 entry.bbox = parent_bboxes[parent];
2743 parentEntries.push_back( entry );
2749 for( ParentEntry& entry : parentEntries )
2751 int minCoords[2] = { entry.bbox.GetLeft(), entry.bbox.GetTop() };
2752 int maxCoords[2] = { entry.bbox.GetRight(), entry.bbox.GetBottom() };
2753 parentBuilder.
Add( minCoords, maxCoords, &entry );
2756 auto parentIndex = parentBuilder.
Build();
2759 std::mutex work_items_lock;
2761 auto searchParent = [&](
size_t i ) ->
bool
2763 const ParentEntry& entry1 = parentEntries[i];
2765 BOX2I bbox1 = entry1.bbox;
2767 std::vector<std::pair<std::shared_ptr<GRAPH_NODE>, std::shared_ptr<GRAPH_NODE>>> localWorkItems;
2770 int searchMin[2] = { bbox1.
GetLeft() - (int) maxDist, bbox1.
GetTop() - (int) maxDist };
2771 int searchMax[2] = { bbox1.
GetRight() + (int) maxDist, bbox1.
GetBottom() + (int) maxDist };
2773 auto parentVisitor = [&]( ParentEntry* entry2 ) ->
bool
2778 if( parent1 >= parent2 )
2782 BOX2I bbox2 = entry2->bbox;
2784 int64_t bboxDistX = 0;
2791 int64_t bboxDistY = 0;
2798 int64_t bboxDistSq = bboxDistX * bboxDistX + bboxDistY * bboxDistY;
2800 if( bboxDistSq > maxDist * maxDist )
2804 auto it1 = parent_net_groups.find( parent1 );
2805 auto it2 = parent_net_groups.find( parent2 );
2807 if( it1 == parent_net_groups.end() || it2 == parent_net_groups.end() )
2810 for(
const auto& [net1, nodes1] : it1->second )
2812 for(
const auto& [net2, nodes2] : it2->second )
2815 if( net1 == net2 && !nodes1.empty() && !nodes2.empty() )
2817 if( nodes1[0]->m_parent->IsConductive()
2818 && nodes2[0]->m_parent->IsConductive() )
2822 for(
const auto& gn1 : nodes1 )
2824 for(
const auto& gn2 : nodes2 )
2826 VECTOR2I pos1 = gn1->m_parent->GetPos();
2827 VECTOR2I pos2 = gn2->m_parent->GetPos();
2828 int r1 = gn1->m_parent->GetRadius();
2829 int r2 = gn2->m_parent->GetRadius();
2831 int64_t centerDistSq = ( pos1 - pos2 ).SquaredEuclideanNorm();
2832 double threshold = aMaxWeight + r1 + r2;
2833 double thresholdSq = threshold * threshold;
2835 if( (
double) centerDistSq > thresholdSq )
2838 if( irrelevantPair( gn1, gn2 ) )
2841 localWorkItems.push_back( { gn1, gn2 } );
2850 parentIndex.Search( searchMin, searchMax, parentVisitor );
2853 if( !localWorkItems.empty() )
2855 std::lock_guard<std::mutex> lock( work_items_lock );
2856 work_items.insert( work_items.end(), localWorkItems.begin(), localWorkItems.end() );
2863 if( parentEntries.size() > 100 &&
tp.get_tasks_total() <
tp.get_thread_count() - 4 )
2865 auto ret =
tp.submit_loop( 0, parentEntries.size(), searchParent );
2867 for(
auto& r : ret )
2875 for(
size_t i = 0; i < parentEntries.size(); ++i )
2884 for(
const auto& [parent, net_groups] : parent_net_groups )
2886 std::vector<std::shared_ptr<GRAPH_NODE>> sameParentNodes;
2888 for(
const auto& [net, nodeList] : net_groups )
2889 sameParentNodes.insert( sameParentNodes.end(), nodeList.begin(), nodeList.end() );
2891 for(
size_t i = 0; i < sameParentNodes.size(); i++ )
2893 for(
size_t j = i + 1; j < sameParentNodes.size(); j++ )
2895 auto& gn1 = sameParentNodes[i];
2896 auto& gn2 = sameParentNodes[j];
2899 if( gn1->m_parent == gn2->m_parent )
2903 if( gn1->m_parent->IsConductive() && gn2->m_parent->IsConductive()
2904 && gn1->m_net == gn2->m_net )
2909 VECTOR2I pos1 = gn1->m_parent->GetPos();
2910 VECTOR2I pos2 = gn2->m_parent->GetPos();
2911 int r1 = gn1->m_parent->GetRadius();
2912 int r2 = gn2->m_parent->GetRadius();
2914 int64_t centerDistSq = ( pos1 - pos2 ).SquaredEuclideanNorm();
2915 double threshold = aMaxWeight + r1 + r2;
2916 double thresholdSq = threshold * threshold;
2918 if( (
double) centerDistSq > thresholdSq )
2921 if( irrelevantPair( gn1, gn2 ) )
2924 work_items.push_back( { gn1, gn2 } );
2929 auto processWorkItems =
2930 [&](
size_t idx ) ->
bool
2932 auto& [gn1, gn2] = work_items[idx];
2940 std::vector<const BOARD_ITEM*> IgnoreForTest;
2951 IgnoreForTest.push_back( shape1->
GetParent() );
2954 IgnoreForTest.push_back( shape2->
GetParent() );
2964 std::shared_ptr<GRAPH_NODE> connect1 = gn1, connect2 = gn2;
2965 std::lock_guard<std::mutex> lock( nodes_lock );
2968 if( gn1->m_parent->GetType() != CREEP_SHAPE::TYPE::POINT_TYPE )
2971 gnt1->m_connectDirectly =
false;
2974 if( gn1->m_parent->IsConductive() )
2976 if( std::shared_ptr<GRAPH_CONNECTION> gc =
AddConnection( gn1, gnt1 ) )
2977 gc->m_path.m_show =
false;
2982 if( gn2->m_parent->GetType() != CREEP_SHAPE::TYPE::POINT_TYPE )
2985 gnt2->m_connectDirectly =
false;
2988 if( gn2->m_parent->IsConductive() )
2990 if( std::shared_ptr<GRAPH_CONNECTION> gc =
AddConnection( gn2, gnt2 ) )
2991 gc->m_path.m_show =
false;
3003 if(
tp.get_tasks_total() >=
tp.get_thread_count() - 4 )
3005 for(
size_t ii = 0; ii < work_items.size(); ii++ )
3006 processWorkItems( ii );
3010 auto ret =
tp.submit_loop( 0, work_items.size(), processWorkItems );
3012 for(
size_t ii = 0; ii < ret.size(); ii++ )
3019 while( r.wait_for( std::chrono::milliseconds( 100 ) ) != std::future_status::ready ){}
3034 for(
const std::shared_ptr<GRAPH_NODE>& gn : { aGc->n1, aGc->n2 } )
3037 gn->m_node_conns.erase( aGc );
3047 for(
size_t i = aConnectionCount; i < vectorSize; i++ )
3051 m_nodes.resize( aNodeCount,
nullptr );
3056 for(
size_t i = 0; i < aNodeCount; ++i )
3067 std::shared_ptr<GRAPH_NODE> gn =
FindNode( aType, parent, pos );
3072 gn = std::make_shared<GRAPH_NODE>( aType, parent, pos );
3082 std::shared_ptr<GRAPH_NODE> gn = std::make_shared<GRAPH_NODE>( GRAPH_NODE::TYPE::VIRTUAL,
nullptr );
3090 std::shared_ptr<GRAPH_NODE>& aN2,
3096 wxASSERT_MSG( ( aN1 != aN2 ),
"Creepage: a connection connects a node to itself" );
3098 std::shared_ptr<GRAPH_CONNECTION> gc = std::make_shared<GRAPH_CONNECTION>( aN1, aN2, aPc );
3100 aN1->m_node_conns.insert( gc );
3101 aN2->m_node_conns.insert( gc );
3108 std::shared_ptr<GRAPH_NODE>& aN2 )
3125 auto it =
m_nodeset.find( std::make_shared<GRAPH_NODE>( aType, aParent, aPos ) );
3138 virtualNode->m_net = aNetCode;
3142 for(
PAD*
pad : footprint->Pads() )
3144 if(
pad->GetNetCode() != aNetCode || !
pad->IsOnLayer( aLayer ) )
3147 if( std::shared_ptr<SHAPE> padShape =
pad->GetEffectiveShape( aLayer ) )
3154 if( track->GetNetCode() != aNetCode || !track->IsOnLayer( aLayer ) )
3157 if( std::shared_ptr<SHAPE> shape = track->GetEffectiveShape() )
3158 Addshape( *shape, virtualNode, track );
3164 if( zone->GetIsRuleArea() )
3167 if( zone->GetNetCode() != aNetCode || !zone->IsOnLayer( aLayer ) )
3170 if( std::shared_ptr<SHAPE> shape = zone->GetEffectiveShape( aLayer ) )
3171 Addshape( *shape, virtualNode, zone );
3178 if( drawing->IsConnected() )
3186 Addshape( *shape, virtualNode, bci );
Creepage: a board edge arc.
std::pair< bool, bool > IsThereATangentPassingThroughPoint(const BE_SHAPE_POINT aPoint) const
EDA_ANGLE GetStartAngle() const override
int GetRadius() const override
BE_SHAPE_ARC(VECTOR2I aPos, int aRadius, EDA_ANGLE aStartAngle, EDA_ANGLE aEndAngle, VECTOR2D aStartPoint, VECTOR2D aEndPoint)
VECTOR2I GetStartPoint() const override
std::vector< PATH_CONNECTION > Paths(const BE_SHAPE_POINT &aS2, double aMaxWeight, double aMaxSquaredWeight) const override
void ConnectChildren(std::shared_ptr< GRAPH_NODE > &a1, std::shared_ptr< GRAPH_NODE > &a2, CREEPAGE_GRAPH &aG) const override
EDA_ANGLE GetEndAngle() const override
VECTOR2I GetEndPoint() const override
EDA_ANGLE AngleBetweenStartAndEnd(const VECTOR2I aPoint) const
Creepage: a board edge circle.
int GetRadius() const override
BE_SHAPE_CIRCLE(VECTOR2I aPos=VECTOR2I(0, 0), int aRadius=0)
void ShortenChildDueToGV(std::shared_ptr< GRAPH_NODE > &a1, std::shared_ptr< GRAPH_NODE > &a2, CREEPAGE_GRAPH &aG, double aNormalWeight) const
std::vector< PATH_CONNECTION > Paths(const BE_SHAPE_POINT &aS2, double aMaxWeight, double aMaxSquaredWeight) const override
void ConnectChildren(std::shared_ptr< GRAPH_NODE > &a1, std::shared_ptr< GRAPH_NODE > &a2, CREEPAGE_GRAPH &aG) const override
Creepage: a board edge point.
BE_SHAPE_POINT(VECTOR2I aPos)
void ConnectChildren(std::shared_ptr< GRAPH_NODE > &a1, std::shared_ptr< GRAPH_NODE > &a2, CREEPAGE_GRAPH &aG) const override
std::vector< PATH_CONNECTION > Paths(const BE_SHAPE_POINT &aS2, double aMaxWeight, double aMaxSquaredWeight) const override
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Information pertinent to a Pcbnew printed circuit board.
const std::vector< PAD * > GetPads() const
Return a reference to a list of all the pads.
const FOOTPRINTS & Footprints() const
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
const DRAWINGS & Drawings() const
constexpr coord_type GetY() const
constexpr coord_type GetX() const
constexpr coord_type GetLeft() const
constexpr coord_type GetRight() const
constexpr coord_type GetTop() const
constexpr coord_type GetBottom() const
Represent basic circle geometry with utility geometry functions.
A graph with nodes and connections for creepage calculation.
std::shared_ptr< GRAPH_NODE > AddNode(GRAPH_NODE::TYPE aType, CREEP_SHAPE *aParent=nullptr, const VECTOR2I &aPos=VECTOR2I())
std::shared_ptr< GRAPH_CONNECTION > AddConnection(std::shared_ptr< GRAPH_NODE > &aN1, std::shared_ptr< GRAPH_NODE > &aN2, const PATH_CONNECTION &aPc)
void SetTarget(double aTarget)
double Solve(std::shared_ptr< GRAPH_NODE > &aFrom, std::shared_ptr< GRAPH_NODE > &aTo, std::vector< std::shared_ptr< GRAPH_CONNECTION > > &aResult)
void Addshape(const SHAPE &aShape, std::shared_ptr< GRAPH_NODE > &aConnectTo, BOARD_ITEM *aParent=nullptr)
void GeneratePaths(double aMaxWeight, PCB_LAYER_ID aLayer, const std::set< int > *aRelevantNets=nullptr)
Generate creepage paths between graph nodes.
void TransformEdgeToCreepShapes()
std::shared_ptr< GRAPH_NODE > AddNodeVirtual()
bool m_hasOverlappingCutouts
SHAPE_POLY_SET * m_boardOutline
void TransformCreepShapesToNodes(const std::vector< std::unique_ptr< CREEP_SHAPE > > &aShapes)
void RemoveDuplicatedShapes()
void TruncateToPrefix(size_t aNodeCount, size_t aConnectionCount)
Remove every node and connection added after the given prefix sizes, then rebuild the node lookup set...
std::vector< BOARD_ITEM * > m_boardEdge
double m_creepageTargetSquared
std::vector< std::unique_ptr< CREEP_SHAPE > > m_shapeCollection
std::unordered_set< std::shared_ptr< GRAPH_NODE >, GraphNodeHash, GraphNodeEqual > m_nodeset
std::vector< std::shared_ptr< GRAPH_NODE > > m_nodes
std::vector< std::shared_ptr< GRAPH_CONNECTION > > m_connections
std::shared_ptr< GRAPH_NODE > AddNetElements(int aNetCode, PCB_LAYER_ID aLayer, int aMaxCreepage)
std::shared_ptr< GRAPH_NODE > FindNode(GRAPH_NODE::TYPE aType, CREEP_SHAPE *aParent, const VECTOR2I &aPos)
void detachConnection(const std::shared_ptr< GRAPH_CONNECTION > &aGc)
A class used to represent the shapes for creepage calculation.
CREEP_SHAPE::TYPE GetType() const
virtual int GetRadius() const
const BOARD_ITEM * GetParent() const
virtual void ConnectChildren(std::shared_ptr< GRAPH_NODE > &a1, std::shared_ptr< GRAPH_NODE > &a2, CREEPAGE_GRAPH &aG) const
Creepage: a conductive arc.
VECTOR2I GetStartPoint() const override
EDA_ANGLE AngleBetweenStartAndEnd(const VECTOR2I aPoint) const
VECTOR2I GetEndPoint() const override
EDA_ANGLE GetStartAngle() const override
CU_SHAPE_ARC(VECTOR2I aPos, double aRadius, EDA_ANGLE aStartAngle, EDA_ANGLE aEndAngle, VECTOR2D aStartPoint, VECTOR2D aEndPoint)
int GetRadius() const override
EDA_ANGLE GetEndAngle() const override
std::vector< PATH_CONNECTION > Paths(const BE_SHAPE_POINT &aS2, double aMaxWeight, double aMaxSquaredWeight) const override
Creepage: a conductive circle.
int GetRadius() const override
CU_SHAPE_CIRCLE(VECTOR2I aPos, double aRadius=0)
std::vector< PATH_CONNECTION > Paths(const BE_SHAPE_POINT &aS2, double aMaxWeight, double aMaxSquaredWeight) const override
Creepage: a conductive segment.
std::vector< PATH_CONNECTION > Paths(const BE_SHAPE_POINT &aS2, double aMaxWeight, double aMaxSquaredWeight) const override
VECTOR2I GetStart() const
CU_SHAPE_SEGMENT(VECTOR2I aStart, VECTOR2I aEnd, double aWidth=0)
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
void SetCenter(const VECTOR2I &aCenter)
VECTOR2I getCenter() const
std::vector< VECTOR2I > GetPolyPoints() const
Duplicate the polygon outlines into a flat list of VECTOR2I points.
void CalcArcAngles(EDA_ANGLE &aStartAngle, EDA_ANGLE &aEndAngle) const
Calc arc start and end angles such that aStartAngle < aEndAngle.
void RebuildBezierToSegmentsPointsList(int aMaxError)
Rebuild the m_bezierPoints vertex list that approximate the Bezier curve by a list of segments.
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
const std::vector< VECTOR2I > & GetBezierPoints() const
virtual void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Set the three controlling points for an arc.
int GetCornerRadius() const
VECTOR2I GetArcMid() const
std::shared_ptr< GRAPH_NODE > n2
void GetShapes(std::vector< PCB_SHAPE > &aShapes)
std::shared_ptr< GRAPH_NODE > n1
std::set< std::shared_ptr< GRAPH_CONNECTION > > m_node_conns
Builder for constructing a PACKED_RTREE from a set of items.
void Add(const ELEMTYPE aMin[NUMDIMS], const ELEMTYPE aMax[NUMDIMS], const DATATYPE &aData)
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
void SetEnd(const VECTOR2I &aEnd) override
void SetStart(const VECTOR2I &aStart) override
const VECTOR2I & GetArcMid() const
int GetWidth() const override
const VECTOR2I & GetP1() const
const VECTOR2I & GetP0() const
SHAPE_TYPE Type() const
Return the type of the shape.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
int PointCount() const
Return the number of points (vertices) in this line chain.
const VECTOR2I & CLastPoint() const
Return the last point in the line chain.
const std::vector< VECTOR2I > & CPoints() const
Represent a set of closed polygons.
bool PointOnEdge(const VECTOR2I &aP, int aAccuracy=0) const
Check if point aP lies on an edge or vertex of some of the outlines or holes.
CONST_SEGMENT_ITERATOR CIterateSegmentsWithHoles() const
Return an iterator object, for the aOutline-th outline in the set (with holes).
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Return true if a given subpolygon contains the point aP.
const VECTOR2I & GetPosition() const
const VECTOR2I GetSize() const
const SEG & GetSeg() const
int GetWidth() const override
Represent a simple polygon consisting of a zero-thickness closed chain of connected line segments.
const SHAPE_LINE_CHAIN & Vertices() const
Return the list of vertices defining this simple polygon.
An abstract shape on 2D plane.
constexpr extended_type Cross(const VECTOR2< T > &aVector) const
Compute cross product of self with aVector.
constexpr extended_type SquaredEuclideanNorm() const
Compute the squared euclidean norm of the vector, which is defined as (x ** 2 + y ** 2).
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
VECTOR2_TRAITS< int32_t >::extended_type extended_type
constexpr VECTOR2< T > Perpendicular() const
Compute the perpendicular vector.
constexpr extended_type Dot(const VECTOR2< T > &aVector) const
Compute dot product of self with aVector.
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Handle a list of polygons defining a copper zone.
static bool empty(const wxTextEntryBase *aCtrl)
VECTOR2I closestPointOnSegment(const VECTOR2I &A, const VECTOR2I &B, const VECTOR2I &P)
bool SegmentIntersectsBoard(const VECTOR2I &aP1, const VECTOR2I &aP2, const std::vector< BOARD_ITEM * > &aBe, const std::vector< const BOARD_ITEM * > &aDontTestAgainst, int aMinGrooveWidth)
std::vector< PATH_CONNECTION > GetPaths(CREEP_SHAPE *aS1, CREEP_SHAPE *aS2, double aMaxWeight)
bool segmentIntersectsArc(const VECTOR2I &p1, const VECTOR2I &p2, const VECTOR2I ¢er, double radius, EDA_ANGLE startAngle, EDA_ANGLE endAngle, std::vector< VECTOR2I > *aIntersectionPoints=nullptr)
bool compareShapes(const CREEP_SHAPE *a, const CREEP_SHAPE *b)
bool segments_intersect(const VECTOR2I &p1, const VECTOR2I &q1, const VECTOR2I &p2, const VECTOR2I &q2, std::vector< VECTOR2I > &aIntersectionPoints)
void BuildCreepageBoardEdges(BOARD &aBoard, std::vector< BOARD_ITEM * > &aVector, std::vector< std::unique_ptr< PCB_SHAPE > > &aOwned, const std::set< const BOARD_ITEM * > *aExclude)
Collect the board-edge items used by the creepage graph.
bool areEquivalent(const CREEP_SHAPE *a, const CREEP_SHAPE *b)
bool segmentIntersectsCircle(const VECTOR2I &p1, const VECTOR2I &p2, const VECTOR2I ¢er, double radius, std::vector< VECTOR2I > *aIntersectPoints)
KIRTREE::PACKED_RTREE< CREEPAGE_TRACK_ENTRY *, int, 2 > TRACK_RTREE
static constexpr EDA_ANGLE ANGLE_0
static constexpr EDA_ANGLE ANGLE_360
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
std::variant< LINE, HALF_LINE, SEG, CIRCLE, SHAPE_ARC, SHAPE_ELLIPSE, BOX2I > INTERSECTABLE_GEOM
A variant type that can hold any of the supported geometry types for intersection calculations.
PCB_LAYER_ID
A quick note on layer IDs:
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
std::deque< BOARD_ITEM * > DRAWINGS
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
@ SH_POLY_SET
set of polygons (with holes, etc.)
@ SH_RECT
axis-aligned rectangle
@ SH_SIMPLE
simple polygon
@ SH_LINE_CHAIN
line chain (polyline)
@ SH_COMPOUND
compound shape, consisting of multiple simple shapes
A visitor that visits INTERSECTABLE_GEOM variant objects with another (which is held as state: m_othe...
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
wxString result
Test unit parsing edge cases and error handling.
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::priority_thread_pool thread_pool
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D