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() );
2504 auto cuArc = std::make_unique<CU_SHAPE_ARC>( edaArc.
getCenter(), edaArc.
GetRadius(), alpha, beta,
2507 newshape = std::move( cuArc );
2515 for(
const SHAPE* subshape : (
static_cast<const SHAPE_COMPOUND*
>( &aShape )->Shapes() ) )
2520 if( !( ( subshape->Type() ==
SH_RECT ) && ( nbShapes == 5 ) ) )
2521 Addshape( *subshape, aConnectTo, aParent );
2533 const SEG object = *it;
2535 Addshape( segment, aConnectTo, aParent );
2550 Addshape( segment, aConnectTo, aParent );
2573 if( point != prevPoint )
2605 std::shared_ptr<GRAPH_NODE> gnShape =
nullptr;
2607 newshape->SetParent( aParent );
2609 switch( aShape.
Type() )
2620 gnShape->m_net = aConnectTo->m_net;
2621 std::shared_ptr<GRAPH_CONNECTION> gc =
AddConnection( gnShape, aConnectTo );
2624 gc->m_path.m_show =
false;
2629 const std::set<int>* aRelevantNets )
2631 auto irrelevantPair = [&](
const std::shared_ptr<GRAPH_NODE>& gn1,
2632 const std::shared_ptr<GRAPH_NODE>& gn2 ) ->
bool
2634 return aRelevantNets && gn1->m_parent && gn2->m_parent && gn1->m_parent->IsConductive()
2635 && gn2->m_parent->IsConductive() && !aRelevantNets->count( gn1->m_net )
2636 && !aRelevantNets->count( gn2->m_net );
2639 std::vector<std::shared_ptr<GRAPH_NODE>> nodes;
2640 std::mutex nodes_lock;
2643 std::vector<CREEPAGE_TRACK_ENTRY*> trackEntries;
2644 TRACK_RTREE::Builder trackBuilder;
2652 std::shared_ptr<SHAPE> sh = track->GetEffectiveShape();
2657 entry->
segment =
SEG( track->GetStart(), track->GetEnd() );
2658 entry->
layer = aLayer;
2659 entry->
halfWidth = track->GetWidth() / 2;
2660 entry->
track = track;
2662 BOX2I bbox = track->GetBoundingBox();
2663 int minCoords[2] = { bbox.
GetX(), bbox.
GetY() };
2665 trackBuilder.Add( minCoords, maxCoords, entry );
2666 trackEntries.push_back( entry );
2674 std::copy_if(
m_nodes.begin(),
m_nodes.end(), std::back_inserter( nodes ),
2675 [&](
const std::shared_ptr<GRAPH_NODE>& gn )
2677 return gn && gn->m_parent && gn->m_connectDirectly && ( gn->m_type != GRAPH_NODE::TYPE::VIRTUAL );
2680 std::sort( nodes.begin(), nodes.end(),
2681 [](
const std::shared_ptr<GRAPH_NODE>& gn1,
const std::shared_ptr<GRAPH_NODE>& gn2 )
2683 return gn1->m_parent < gn2->m_parent
2684 || ( gn1->m_parent == gn2->m_parent && gn1->m_net < gn2->m_net );
2689 std::unordered_map<const BOARD_ITEM*, std::unordered_map<int, std::vector<std::shared_ptr<GRAPH_NODE>>>> parent_net_groups;
2690 std::unordered_map<const BOARD_ITEM*, BOX2I> parent_bboxes;
2691 std::vector<const BOARD_ITEM*> parent_keys;
2693 for(
const auto& gn : nodes )
2695 const BOARD_ITEM* parent = gn->m_parent->GetParent();
2697 if( parent_net_groups[parent].
empty() )
2699 parent_keys.push_back( parent );
2704 parent_net_groups[parent][gn->m_net].push_back( gn );
2708 std::vector<std::pair<std::shared_ptr<GRAPH_NODE>, std::shared_ptr<GRAPH_NODE>>> work_items;
2713 int64_t maxDist =
static_cast<int64_t
>( aMaxWeight );
2721 std::vector<ParentEntry> parentEntries;
2723 for(
const auto* parent : parent_keys )
2728 entry.parent = parent;
2729 entry.bbox = parent_bboxes[parent];
2730 parentEntries.push_back( entry );
2736 for( ParentEntry& entry : parentEntries )
2738 int minCoords[2] = { entry.bbox.GetLeft(), entry.bbox.GetTop() };
2739 int maxCoords[2] = { entry.bbox.GetRight(), entry.bbox.GetBottom() };
2740 parentBuilder.
Add( minCoords, maxCoords, &entry );
2743 auto parentIndex = parentBuilder.
Build();
2746 std::mutex work_items_lock;
2748 auto searchParent = [&](
size_t i ) ->
bool
2750 const ParentEntry& entry1 = parentEntries[i];
2752 BOX2I bbox1 = entry1.bbox;
2754 std::vector<std::pair<std::shared_ptr<GRAPH_NODE>, std::shared_ptr<GRAPH_NODE>>> localWorkItems;
2757 int searchMin[2] = { bbox1.
GetLeft() - (int) maxDist, bbox1.
GetTop() - (int) maxDist };
2758 int searchMax[2] = { bbox1.
GetRight() + (int) maxDist, bbox1.
GetBottom() + (int) maxDist };
2760 auto parentVisitor = [&]( ParentEntry* entry2 ) ->
bool
2765 if( parent1 >= parent2 )
2769 BOX2I bbox2 = entry2->bbox;
2771 int64_t bboxDistX = 0;
2778 int64_t bboxDistY = 0;
2785 int64_t bboxDistSq = bboxDistX * bboxDistX + bboxDistY * bboxDistY;
2787 if( bboxDistSq > maxDist * maxDist )
2791 auto it1 = parent_net_groups.find( parent1 );
2792 auto it2 = parent_net_groups.find( parent2 );
2794 if( it1 == parent_net_groups.end() || it2 == parent_net_groups.end() )
2797 for(
const auto& [net1, nodes1] : it1->second )
2799 for(
const auto& [net2, nodes2] : it2->second )
2802 if( net1 == net2 && !nodes1.empty() && !nodes2.empty() )
2804 if( nodes1[0]->m_parent->IsConductive()
2805 && nodes2[0]->m_parent->IsConductive() )
2809 for(
const auto& gn1 : nodes1 )
2811 for(
const auto& gn2 : nodes2 )
2813 VECTOR2I pos1 = gn1->m_parent->GetPos();
2814 VECTOR2I pos2 = gn2->m_parent->GetPos();
2815 int r1 = gn1->m_parent->GetRadius();
2816 int r2 = gn2->m_parent->GetRadius();
2818 int64_t centerDistSq = ( pos1 - pos2 ).SquaredEuclideanNorm();
2819 double threshold = aMaxWeight + r1 + r2;
2820 double thresholdSq = threshold * threshold;
2822 if( (
double) centerDistSq > thresholdSq )
2825 if( irrelevantPair( gn1, gn2 ) )
2828 localWorkItems.push_back( { gn1, gn2 } );
2837 parentIndex.Search( searchMin, searchMax, parentVisitor );
2840 if( !localWorkItems.empty() )
2842 std::lock_guard<std::mutex> lock( work_items_lock );
2843 work_items.insert( work_items.end(), localWorkItems.begin(), localWorkItems.end() );
2850 if( parentEntries.size() > 100 &&
tp.get_tasks_total() <
tp.get_thread_count() - 4 )
2852 auto ret =
tp.submit_loop( 0, parentEntries.size(), searchParent );
2854 for(
auto& r : ret )
2862 for(
size_t i = 0; i < parentEntries.size(); ++i )
2871 for(
const auto& [parent, net_groups] : parent_net_groups )
2873 std::vector<std::shared_ptr<GRAPH_NODE>> sameParentNodes;
2875 for(
const auto& [net, nodeList] : net_groups )
2876 sameParentNodes.insert( sameParentNodes.end(), nodeList.begin(), nodeList.end() );
2878 for(
size_t i = 0; i < sameParentNodes.size(); i++ )
2880 for(
size_t j = i + 1; j < sameParentNodes.size(); j++ )
2882 auto& gn1 = sameParentNodes[i];
2883 auto& gn2 = sameParentNodes[j];
2886 if( gn1->m_parent == gn2->m_parent )
2890 if( gn1->m_parent->IsConductive() && gn2->m_parent->IsConductive()
2891 && gn1->m_net == gn2->m_net )
2896 VECTOR2I pos1 = gn1->m_parent->GetPos();
2897 VECTOR2I pos2 = gn2->m_parent->GetPos();
2898 int r1 = gn1->m_parent->GetRadius();
2899 int r2 = gn2->m_parent->GetRadius();
2901 int64_t centerDistSq = ( pos1 - pos2 ).SquaredEuclideanNorm();
2902 double threshold = aMaxWeight + r1 + r2;
2903 double thresholdSq = threshold * threshold;
2905 if( (
double) centerDistSq > thresholdSq )
2908 if( irrelevantPair( gn1, gn2 ) )
2911 work_items.push_back( { gn1, gn2 } );
2916 auto processWorkItems =
2917 [&](
size_t idx ) ->
bool
2919 auto& [gn1, gn2] = work_items[idx];
2927 std::vector<const BOARD_ITEM*> IgnoreForTest;
2938 IgnoreForTest.push_back( shape1->
GetParent() );
2941 IgnoreForTest.push_back( shape2->
GetParent() );
2951 std::shared_ptr<GRAPH_NODE> connect1 = gn1, connect2 = gn2;
2952 std::lock_guard<std::mutex> lock( nodes_lock );
2955 if( gn1->m_parent->GetType() != CREEP_SHAPE::TYPE::POINT_TYPE )
2958 gnt1->m_connectDirectly =
false;
2961 if( gn1->m_parent->IsConductive() )
2963 if( std::shared_ptr<GRAPH_CONNECTION> gc =
AddConnection( gn1, gnt1 ) )
2964 gc->m_path.m_show =
false;
2969 if( gn2->m_parent->GetType() != CREEP_SHAPE::TYPE::POINT_TYPE )
2972 gnt2->m_connectDirectly =
false;
2975 if( gn2->m_parent->IsConductive() )
2977 if( std::shared_ptr<GRAPH_CONNECTION> gc =
AddConnection( gn2, gnt2 ) )
2978 gc->m_path.m_show =
false;
2990 if(
tp.get_tasks_total() >=
tp.get_thread_count() - 4 )
2992 for(
size_t ii = 0; ii < work_items.size(); ii++ )
2993 processWorkItems( ii );
2997 auto ret =
tp.submit_loop( 0, work_items.size(), processWorkItems );
2999 for(
size_t ii = 0; ii < ret.size(); ii++ )
3006 while( r.wait_for( std::chrono::milliseconds( 100 ) ) != std::future_status::ready ){}
3021 for(
const std::shared_ptr<GRAPH_NODE>& gn : { aGc->n1, aGc->n2 } )
3024 gn->m_node_conns.erase( aGc );
3034 for(
size_t i = aConnectionCount; i < vectorSize; i++ )
3038 m_nodes.resize( aNodeCount,
nullptr );
3043 for(
size_t i = 0; i < aNodeCount; ++i )
3054 std::shared_ptr<GRAPH_NODE> gn =
FindNode( aType, parent, pos );
3059 gn = std::make_shared<GRAPH_NODE>( aType, parent, pos );
3069 std::shared_ptr<GRAPH_NODE> gn = std::make_shared<GRAPH_NODE>( GRAPH_NODE::TYPE::VIRTUAL,
nullptr );
3077 std::shared_ptr<GRAPH_NODE>& aN2,
3083 wxASSERT_MSG( ( aN1 != aN2 ),
"Creepage: a connection connects a node to itself" );
3085 std::shared_ptr<GRAPH_CONNECTION> gc = std::make_shared<GRAPH_CONNECTION>( aN1, aN2, aPc );
3087 aN1->m_node_conns.insert( gc );
3088 aN2->m_node_conns.insert( gc );
3095 std::shared_ptr<GRAPH_NODE>& aN2 )
3112 auto it =
m_nodeset.find( std::make_shared<GRAPH_NODE>( aType, aParent, aPos ) );
3125 virtualNode->m_net = aNetCode;
3129 for(
PAD*
pad : footprint->Pads() )
3131 if(
pad->GetNetCode() != aNetCode || !
pad->IsOnLayer( aLayer ) )
3134 if( std::shared_ptr<SHAPE> padShape =
pad->GetEffectiveShape( aLayer ) )
3141 if( track->GetNetCode() != aNetCode || !track->IsOnLayer( aLayer ) )
3144 if( std::shared_ptr<SHAPE> shape = track->GetEffectiveShape() )
3145 Addshape( *shape, virtualNode, track );
3151 if( zone->GetIsRuleArea() )
3154 if( zone->GetNetCode() != aNetCode || !zone->IsOnLayer( aLayer ) )
3157 if( std::shared_ptr<SHAPE> shape = zone->GetEffectiveShape( aLayer ) )
3158 Addshape( *shape, virtualNode, zone );
3165 if( drawing->IsConnected() )
3173 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 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.
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
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.
void SetCenter(const VECTOR2I &aCenter) override
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
int GetWidth() const override
const VECTOR2I & GetP1() const
const VECTOR2I & GetP0() const
SHAPE_TYPE Type() const
Return the type of the shape.
const std::vector< SHAPE * > & Shapes() const
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