KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drc_creepage_utils.h
Go to the documentation of this file.
1/*
2 * Copyright The KiCad Developers.
3 * Copyright (C) 2024 Fabien Corona f.corona<at>laposte.net
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
19
20#pragma once
21
22#include <memory>
23#include <unordered_set>
24
25#include <common.h>
26#include <core/kicad_algo.h>
27#include <macros.h>
29#include <footprint.h>
30#include <pad.h>
31#include <pcb_track.h>
32#include <pcb_shape.h>
33#include <zone.h>
34#include <advanced_config.h>
35#include <geometry/shape_rect.h>
36#include <geometry/seg.h>
38#include <drc/drc_item.h>
39#include <drc/drc_rule.h>
40#include <board.h>
41
42
45
46
47// Simple wrapper for track segment data in the RTree
55
57
58extern bool SegmentIntersectsBoard( const VECTOR2I& aP1, const VECTOR2I& aP2,
59 const std::vector<BOARD_ITEM*>& aBe,
60 const std::vector<const BOARD_ITEM*>& aDontTestAgainst,
61 int aMinGrooveWidth );
62
63
72void BuildCreepageBoardEdges( BOARD& aBoard, std::vector<BOARD_ITEM*>& aVector,
73 std::vector<std::unique_ptr<PCB_SHAPE>>& aOwned,
74 const std::set<const BOARD_ITEM*>* aExclude = nullptr );
75
76
78{
81 double weight = -1;
82 bool m_show = true;
83
86
87
101 bool isValid( const BOARD& aBoard, PCB_LAYER_ID aLayer,
102 const std::vector<BOARD_ITEM*>& aBoardEdges,
103 const std::vector<const BOARD_ITEM*>& aIgnoreForTest, SHAPE_POLY_SET* aOutline,
104 const std::pair<bool, bool>& aTestLocalConcavity, int aMinGrooveWidth,
105 TRACK_RTREE* aTrackIndex = nullptr ) const
106 {
107 if( !aOutline )
108 return true; // We keep the segment if there is a problem
109
110 if( !SegmentIntersectsBoard( a1, a2, aBoardEdges, aIgnoreForTest, aMinGrooveWidth ) )
111 return false;
112
113 // The mid point should be inside the board.
114 // Tolerance of 100nm.
115
116 VECTOR2I midPoint = ( a1 + a2 ) / 2;
117 int tolerance = 100;
118
119 bool contained = aOutline->Contains( midPoint, -1, tolerance )
120 || aOutline->PointOnEdge( midPoint, tolerance );
121
122 if( !contained )
123 return false;
124
125 if( false && ( aTestLocalConcavity.first || aTestLocalConcavity.second ) )
126 {
127 // Test for local concavity. If it is localy convex, then it will not be a path of interest.
128
129 double extendLine = 1000; // extend line by 1000nm
130 // In some cases, the projected point could be on the board edge
131 // In such cases, we wan to keep the line.
132 // We inflate the polygon to get a small margin for computation/rounding error.
133 // We might keep some unnecessary lines, but it's better than loosing the important ones.
134 double extendPoly = 100; // extend polygon by 10 nm
135
136 VECTOR2D a( double( a1.x ), double( a1.y ) );
137 VECTOR2D b( double( a2.x ), double( a2.y ) );
138
139 VECTOR2D dir( b - a );
140 dir = dir * ( extendLine / dir.SquaredEuclideanNorm() );
141
142 SHAPE_POLY_SET outline2 = *aOutline;
143 outline2.Inflate( extendPoly, CORNER_STRATEGY::ROUND_ALL_CORNERS, 3 );
144
145 if( aTestLocalConcavity.first && !aOutline->Contains( a - dir, -1, 0 ) )
146 return false;
147
148 if( aTestLocalConcavity.second && !aOutline->Contains( b + dir, -1, 0 ) )
149 return false;
150 }
151
152 if( aLayer != Edge_Cuts )
153 {
154 SEG segPath( a1, a2 );
155
156 // A creepage path endpoint sitting strictly inside another track's copper body
157 // is not a real surface point: the visible copper is the enclosing track, and
158 // the path would appear to start/end "inside" the copper in the UI. Reject
159 // connections whose endpoint lies inside any track interior (regardless of
160 // net). The endpoint track itself is in aIgnoreForTest and is skipped.
161 //
162 // The tolerance lets endpoints that sit exactly on a neighbor track's boundary
163 // (for example, two same-net tracks meeting at a shared corner) pass.
164 constexpr int interiorTolerance = 100; // 100 nm
165
166 auto endpointInside = [&]( const SEG& segTrack, int halfWidth ) -> bool
167 {
168 return segTrack.Distance( VECTOR2I( a1 ) ) + interiorTolerance < halfWidth
169 || segTrack.Distance( VECTOR2I( a2 ) ) + interiorTolerance < halfWidth;
170 };
171
172 if( aTrackIndex )
173 {
174 int minX = std::min( (int) a1.x, (int) a2.x );
175 int minY = std::min( (int) a1.y, (int) a2.y );
176 int maxX = std::max( (int) a1.x, (int) a2.x );
177 int maxY = std::max( (int) a1.y, (int) a2.y );
178
179 int searchMin[2] = { minX, minY };
180 int searchMax[2] = { maxX, maxY };
181
182 bool failed = false;
183
184 auto trackVisitor = [&]( CREEPAGE_TRACK_ENTRY* entry ) -> bool
185 {
186 if( !entry || entry->layer != aLayer )
187 return true;
188
189 if( segPath.Intersects( entry->segment ) )
190 {
191 failed = true;
192 return false;
193 }
194
195 if( !alg::contains( aIgnoreForTest, entry->track )
196 && endpointInside( entry->segment, entry->halfWidth ) )
197 {
198 failed = true;
199 return false;
200 }
201
202 return true;
203 };
204
205 aTrackIndex->Search( searchMin, searchMax, trackVisitor );
206
207 if( failed )
208 return false;
209 }
210 else
211 {
212 for( PCB_TRACK* track : aBoard.Tracks() )
213 {
214 if( !track || track->Type() != KICAD_T::PCB_TRACE_T
215 || !track->IsOnLayer( aLayer ) )
216 {
217 continue;
218 }
219
220 std::shared_ptr<SHAPE> sh = track->GetEffectiveShape();
221
222 if( !sh || sh->Type() != SHAPE_TYPE::SH_SEGMENT )
223 continue;
224
225 SEG segTrack( track->GetStart(), track->GetEnd() );
226
227 if( segPath.Intersects( segTrack ) )
228 return false;
229
230 if( !alg::contains( aIgnoreForTest, static_cast<const BOARD_ITEM*>( track ) )
231 && endpointInside( segTrack, track->GetWidth() / 2 ) )
232 {
233 return false;
234 }
235 }
236 }
237 }
238 return true;
239 }
240};
241
242
243class GRAPH_CONNECTION;
244class GRAPH_NODE;
245class CREEPAGE_GRAPH;
246class CREEP_SHAPE;
247class BE_SHAPE;
248class BE_SHAPE_POINT;
249class BE_SHAPE_ARC;
250class BE_SHAPE_CIRCLE;
251class CU_SHAPE;
252class CU_SHAPE_SEGMENT;
253class CU_SHAPE_CIRCLE;
254class CU_SHAPE_ARC;
255
261{
262public:
263 enum class TYPE
264 {
269 };
270
272 {
273 m_conductive = false;
274 m_parent = nullptr;
275 m_pos = VECTOR2I( 0, 0 );
276 m_type = CREEP_SHAPE::TYPE::UNDEFINED;
277 };
278
279 virtual ~CREEP_SHAPE() {}
280
281 virtual int GetRadius() const { return 0; };
282 virtual EDA_ANGLE GetStartAngle() const { return EDA_ANGLE( 0 ); };
283 virtual EDA_ANGLE GetEndAngle() const { return EDA_ANGLE( 0 ); };
284 virtual VECTOR2I GetStartPoint() const { return VECTOR2I( 0, 0 ); };
285 virtual VECTOR2I GetEndPoint() const { return VECTOR2I( 0, 0 ); };
286 VECTOR2I GetPos() const { return m_pos; };
287 CREEP_SHAPE::TYPE GetType() const { return m_type; };
288 const BOARD_ITEM* GetParent() const { return m_parent; };
289 void SetParent( BOARD_ITEM* aParent ) { m_parent = aParent; };
290
291 virtual void ConnectChildren( std::shared_ptr<GRAPH_NODE>& a1, std::shared_ptr<GRAPH_NODE>& a2,
292 CREEPAGE_GRAPH& aG ) const;
293
294 std::vector<PATH_CONNECTION> ReversePaths( const std::vector<PATH_CONNECTION>& aV ) const
295 {
296 std::vector<PATH_CONNECTION> r;
297 r.reserve( aV.size() );
298
299 for( const auto& pc : aV )
300 {
301 r.emplace_back( pc );
302 std::swap( r.back().a1, r.back().a2 );
303 }
304
305 return r;
306 }
307
308 std::vector<PATH_CONNECTION> Paths( const CREEP_SHAPE& aS2, double aMaxWeight,
309 double aMaxSquaredWeight ) const
310 {
311 std::vector<PATH_CONNECTION> a;
312 return a;
313 };
314
315 virtual std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
316 double aMaxSquaredWeight ) const
317 {
318 std::vector<PATH_CONNECTION> a;
319 return a;
320 };
321
322 virtual std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
323 double aMaxSquaredWeight ) const
324 {
325 std::vector<PATH_CONNECTION> a;
326 return a;
327 };
328
329 virtual std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
330 double aMaxSquaredWeight ) const
331 {
332 std::vector<PATH_CONNECTION> a;
333 return a;
334 };
335
336 virtual std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
337 double aMaxSquaredWeight ) const
338 {
339 std::vector<PATH_CONNECTION> a;
340 return a;
341 };
342
343 virtual std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
344 double aMaxSquaredWeight ) const
345 {
346 std::vector<PATH_CONNECTION> a;
347 return a;
348 };
349
350 virtual std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_ARC& aS2, double aMaxWeight,
351 double aMaxSquaredWeight ) const
352 {
353 std::vector<PATH_CONNECTION> a;
354 return a;
355 };
356
357 //virtual std::vector<PATH_CONNECTION> GetPathsCuToBe( CREEP_SHAPE* aShape ) const{ std::vector<PATH_CONNECTION> a; return a;};
358 bool IsConductive() { return m_conductive; };
359
360protected:
365};
366
367
372class CU_SHAPE : public CREEP_SHAPE
373{
374public:
377 {
378 m_conductive = true;
379 };
380};
381
386class BE_SHAPE : public CREEP_SHAPE
387{
388public:
391 {
392 m_conductive = false;
393 };
394};
395
401{
402public:
403 CU_SHAPE_SEGMENT( VECTOR2I aStart, VECTOR2I aEnd, double aWidth = 0 ) :
404 CU_SHAPE()
405 {
406 m_start = aStart;
407 m_end = aEnd;
408 m_width = aWidth;
409 m_pos = ( aStart + aEnd ) / 2;
410 }
411
412 VECTOR2I GetStart() const { return m_start; };
413 VECTOR2I GetEnd() const { return m_end; };
414 double GetWidth() const { return m_width; };
415
416 int GetRadius() const override
417 {
418 return (int) ( ( m_start - m_end ).EuclideanNorm() / 2 ) + (int) ( m_width / 2 );
419 };
420
421 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
422 double aMaxSquaredWeight ) const override;
423 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
424 double aMaxSquaredWeight ) const override;
425 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
426 double aMaxSquaredWeight ) const override;
427 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
428 double aMaxSquaredWeight ) const override;
429 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
430 double aMaxSquaredWeight ) const override;
431 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_ARC& aS2, double aMaxWeight,
432 double aMaxSquaredWeight ) const override;
433
434
435private:
438 double m_width = 0;
439};
440
446{
447public:
448 CU_SHAPE_CIRCLE( VECTOR2I aPos, double aRadius = 0 ) :
449 CU_SHAPE()
450 {
451 m_pos = aPos;
452 m_radius = aRadius;
453 }
454
455 int GetRadius() const override { return m_radius; };
456
457 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
458 double aMaxSquaredWeight ) const override;
459 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
460 double aMaxSquaredWeight ) const override;
461 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
462 double aMaxSquaredWeight ) const override;
463 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
464 double aMaxSquaredWeight ) const override
465 {
466 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
467 };
468
469 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
470 double aMaxSquaredWeight ) const override;
471 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_ARC& aS2, double aMaxWeight,
472 double aMaxSquaredWeight ) const override;
473
474protected:
475 double m_radius = 1;
476};
477
483{
484public:
485 CU_SHAPE_ARC( VECTOR2I aPos, double aRadius, EDA_ANGLE aStartAngle, EDA_ANGLE aEndAngle,
486 VECTOR2D aStartPoint, VECTOR2D aEndPoint ) :
487 CU_SHAPE_CIRCLE( aPos, aRadius ),
488 m_startAngle( aStartAngle ),
489 m_endAngle( aEndAngle ),
490 m_startPoint( aStartPoint ),
491 m_endPoint( aEndPoint )
492 {
493 m_type = CREEP_SHAPE::TYPE::ARC;
494 m_width = 0;
495 }
496
497 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
498 double aMaxSquaredWeight ) const override;
499
500 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
501 double aMaxSquaredWeight ) const override;
502
503 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
504 double aMaxSquaredWeight ) const override;
505
506 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
507 double aMaxSquaredWeight ) const override
508 {
509 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
510 };
511
512 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
513 double aMaxSquaredWeight ) const override
514 {
515 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
516 };
517
518 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_ARC& aS2, double aMaxWeight,
519 double aMaxSquaredWeight ) const override;
520
521 EDA_ANGLE GetStartAngle() const override { return m_startAngle; }
522 EDA_ANGLE GetEndAngle() const override { return m_endAngle; }
523 int GetRadius() const override { return m_radius; }
524
525 VECTOR2I GetStartPoint() const override { return m_startPoint; }
526 VECTOR2I GetEndPoint() const override { return m_endPoint; }
527
529 {
530 EDA_ANGLE angle( aPoint - m_pos );
531
532 while( angle < GetStartAngle() )
533 angle += ANGLE_360;
534
535 while( angle > GetEndAngle() + ANGLE_360 )
536 angle -= ANGLE_360;
537
538 return angle;
539 }
540
541 double GetWidth() const { return m_width; };
542 void SetWidth( double aW ) { m_width = aW; };
543
544private:
550};
551
557{
558public:
567
568 GRAPH_NODE( GRAPH_NODE::TYPE aType, CREEP_SHAPE* aParent, const VECTOR2I& aPos = VECTOR2I() ) :
569 m_parent( aParent ),
570 m_pos( aPos ),
571 m_type( aType )
572 {
573 m_node_conns = {};
574 m_virtual = false;
575 m_connectDirectly = true;
576 m_net = -1;
577 };
578
580
581public:
583 std::set<std::shared_ptr<GRAPH_CONNECTION>> m_node_conns;
585
586 // Virtual nodes are connected with a 0 weight connection to equivalent net ( same net or netclass )
589 int m_net;
590
592};
593
599{
600public:
601 GRAPH_CONNECTION( std::shared_ptr<GRAPH_NODE>& aN1, std::shared_ptr<GRAPH_NODE>& aN2,
602 const PATH_CONNECTION& aPc ) :
603 n1( aN1 ),
604 n2( aN2 )
605 {
606 m_path = aPc;
607 m_forceStraightLine = false;
608 };
609
610 void GetShapes( std::vector<PCB_SHAPE>& aShapes );
611
612public:
613 std::shared_ptr<GRAPH_NODE> n1;
614 std::shared_ptr<GRAPH_NODE> n2;
617};
618
619
625{
626public:
628 BE_SHAPE()
629 {
630 m_pos = aPos;
631 m_type = CREEP_SHAPE::TYPE::POINT;
632 }
633
634 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
635 double aMaxSquaredWeight ) const override;
636
637 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
638 double aMaxSquaredWeight ) const override;
639
640 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
641 double aMaxSquaredWeight ) const override;
642
643 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
644 double aMaxSquaredWeight ) const override
645 {
646 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
647 };
648
649 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
650 double aMaxSquaredWeight ) const override
651 {
652 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
653 }
654
655 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_ARC& aS2, double aMaxWeight,
656 double aMaxSquaredWeight ) const override
657 {
658 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
659 };
660
661
662 void ConnectChildren( std::shared_ptr<GRAPH_NODE>& a1, std::shared_ptr<GRAPH_NODE>& a2,
663 CREEPAGE_GRAPH& aG ) const override;
664};
665
671{
672public:
673 BE_SHAPE_CIRCLE( VECTOR2I aPos = VECTOR2I( 0, 0 ), int aRadius = 0 ) :
674 BE_SHAPE()
675 {
676 m_pos = aPos;
677 m_radius = aRadius;
678 m_type = CREEP_SHAPE::TYPE::CIRCLE;
679 }
680
681 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
682 double aMaxSquaredWeight ) const override
683 {
684 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
685 };
686
687 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
688 double aMaxSquaredWeight ) const override;
689
690 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
691 double aMaxSquaredWeight ) const override;
692
693 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
694 double aMaxSquaredWeight ) const override
695 {
696 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
697 };
698
699 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
700 double aMaxSquaredWeight ) const override
701 {
702 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
703 };
704
705
706 int GetRadius() const override { return m_radius; }
707
708 void ConnectChildren( std::shared_ptr<GRAPH_NODE>& a1, std::shared_ptr<GRAPH_NODE>& a2,
709 CREEPAGE_GRAPH& aG ) const override;
710
711 void ShortenChildDueToGV( std::shared_ptr<GRAPH_NODE>& a1, std::shared_ptr<GRAPH_NODE>& a2,
712 CREEPAGE_GRAPH& aG, double aNormalWeight ) const;
713
714
715protected:
717};
718
724{
725public:
726 BE_SHAPE_ARC( VECTOR2I aPos, int aRadius, EDA_ANGLE aStartAngle, EDA_ANGLE aEndAngle,
727 VECTOR2D aStartPoint, VECTOR2D aEndPoint ) :
728 BE_SHAPE_CIRCLE( aPos, aRadius ),
729 m_startAngle( aStartAngle ), m_endAngle( aEndAngle ),
730 m_startPoint( aStartPoint ), m_endPoint( aEndPoint )
731 {
732 m_type = CREEP_SHAPE::TYPE::ARC;
733 }
734
735 void ConnectChildren( std::shared_ptr<GRAPH_NODE>& a1, std::shared_ptr<GRAPH_NODE>& a2,
736 CREEPAGE_GRAPH& aG ) const override;
737
738
739 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
740 double aMaxSquaredWeight ) const override
741 {
742 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
743 };
744 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
745 double aMaxSquaredWeight ) const override
746 {
747 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
748 };
749 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
750 double aMaxSquaredWeight ) const override;
751
752 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
753 double aMaxSquaredWeight ) const override
754 {
755 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
756 };
757 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
758 double aMaxSquaredWeight ) const override
759 {
760 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
761 };
762 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_ARC& aS2, double aMaxWeight,
763 double aMaxSquaredWeight ) const override
764 {
765 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
766 };
767
768 EDA_ANGLE GetStartAngle() const override { return m_startAngle; }
769 EDA_ANGLE GetEndAngle() const override { return m_endAngle; }
770 int GetRadius() const override { return m_radius; }
771
772 VECTOR2I GetStartPoint() const override { return m_startPoint; }
773 VECTOR2I GetEndPoint() const override { return m_endPoint; }
775 {
776 EDA_ANGLE angle( aPoint - m_pos );
777
778 while( angle < m_startAngle )
779 angle += ANGLE_360;
780 while( angle > m_endAngle + ANGLE_360 )
781 angle -= ANGLE_360;
782
783 return angle;
784 }
785
786 std::pair<bool, bool> IsThereATangentPassingThroughPoint( const BE_SHAPE_POINT aPoint ) const;
787
788protected:
793};
794
795
801{
802public:
804 m_board( aBoard )
805 {
806 m_boardOutline = nullptr;
808 m_creepageTarget = -1;
810 };
811
813 {
814 for( CREEP_SHAPE* cs : m_shapeCollection )
815 {
816 if( cs )
817 {
818 delete cs;
819 cs = nullptr;
820 }
821 }
822
823 // Clear out the circular shared pointer references
824 for( std::shared_ptr<GRAPH_NODE>& n : m_nodes )
825 {
826 if( n )
827 {
828 n->m_node_conns.clear();
829 n = nullptr;
830 }
831 }
832
833 for( std::shared_ptr<GRAPH_CONNECTION>& c : m_connections )
834 {
835 if( c )
836 c = nullptr;
837 }
838 };
839
841 void TransformCreepShapesToNodes(std::vector<CREEP_SHAPE*>& aShapes);
843
844 // Add a node to the graph. If an equivalent node exists, returns the pointer of the existing node instead
845 std::shared_ptr<GRAPH_NODE> AddNode( GRAPH_NODE::TYPE aType, CREEP_SHAPE* aParent = nullptr,
846 const VECTOR2I& aPos = VECTOR2I() );
847
848 std::shared_ptr<GRAPH_NODE> AddNodeVirtual();
849
850 std::shared_ptr<GRAPH_CONNECTION> AddConnection( std::shared_ptr<GRAPH_NODE>& aN1,
851 std::shared_ptr<GRAPH_NODE>& aN2,
852 const PATH_CONNECTION& aPc );
853
854 std::shared_ptr<GRAPH_CONNECTION> AddConnection( std::shared_ptr<GRAPH_NODE>& aN1,
855 std::shared_ptr<GRAPH_NODE>& aN2 );
856
857 std::shared_ptr<GRAPH_NODE> FindNode( GRAPH_NODE::TYPE aType, CREEP_SHAPE* aParent,
858 const VECTOR2I& aPos );
859
860 void RemoveConnection( const std::shared_ptr<GRAPH_CONNECTION>&, bool aDelete = false );
861
862 void Trim( double aWeightLimit );
863
864 void Addshape( const SHAPE& aShape, std::shared_ptr<GRAPH_NODE>& aConnectTo,
865 BOARD_ITEM* aParent = nullptr );
866
867 double Solve( std::shared_ptr<GRAPH_NODE>& aFrom, std::shared_ptr<GRAPH_NODE>& aTo,
868 std::vector<std::shared_ptr<GRAPH_CONNECTION>>& aResult );
869
879 void GeneratePaths( double aMaxWeight, PCB_LAYER_ID aLayer,
880 const std::set<int>* aRelevantNets = nullptr );
881
887 void TruncateToPrefix( size_t aNodeCount, size_t aConnectionCount );
888
889 std::shared_ptr<GRAPH_NODE> AddNetElements( int aNetCode, PCB_LAYER_ID aLayer, int aMaxCreepage );
890
891 void SetTarget( double aTarget );
892 double GetTarget() { return m_creepageTarget; };
893
895 {
896 std::size_t operator()(const std::shared_ptr<GRAPH_NODE>& node) const
897 {
898 return hash_val(node->m_type, node->m_parent, node->m_pos.x, node->m_pos.y);
899 }
900 };
901
903 {
904 bool operator()(const std::shared_ptr<GRAPH_NODE>& lhs, const std::shared_ptr<GRAPH_NODE>& rhs) const
905 {
906 return lhs->m_type == rhs->m_type && lhs->m_parent == rhs->m_parent && lhs->m_pos == rhs->m_pos;
907 }
908 };
909
910public:
912 std::vector<BOARD_ITEM*> m_boardEdge;
913 std::vector<std::unique_ptr<PCB_SHAPE>> m_ownedBoardEdges;
915 std::vector<std::shared_ptr<GRAPH_NODE>> m_nodes;
916 std::vector<std::shared_ptr<GRAPH_CONNECTION>> m_connections;
917 std::vector<CREEP_SHAPE*> m_shapeCollection;
918
919 // This is a duplicate of m_nodes, but it is used to quickly find a node rather than iterating through m_nodes
920 std::unordered_set<std::shared_ptr<GRAPH_NODE>, GraphNodeHash, GraphNodeEqual> m_nodeset;
921
923
924private:
927};
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)
std::vector< PATH_CONNECTION > Paths(const CU_SHAPE_ARC &aS2, double aMaxWeight, double aMaxSquaredWeight) const override
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
std::vector< PATH_CONNECTION > Paths(const CU_SHAPE_SEGMENT &aS2, double aMaxWeight, double aMaxSquaredWeight) const override
std::vector< PATH_CONNECTION > Paths(const BE_SHAPE_CIRCLE &aS2, double aMaxWeight, double aMaxSquaredWeight) const override
std::vector< PATH_CONNECTION > Paths(const CU_SHAPE_CIRCLE &aS2, double aMaxWeight, double aMaxSquaredWeight) 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 CU_SHAPE_CIRCLE &aS2, double aMaxWeight, double aMaxSquaredWeight) const override
std::vector< PATH_CONNECTION > Paths(const CU_SHAPE_SEGMENT &aS2, double aMaxWeight, double aMaxSquaredWeight) 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
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 CU_SHAPE_ARC &aS2, double aMaxWeight, double aMaxSquaredWeight) const override
std::vector< PATH_CONNECTION > Paths(const CU_SHAPE_SEGMENT &aS2, double aMaxWeight, double aMaxSquaredWeight) const override
std::vector< PATH_CONNECTION > Paths(const BE_SHAPE_POINT &aS2, double aMaxWeight, double aMaxSquaredWeight) const override
std::vector< PATH_CONNECTION > Paths(const CU_SHAPE_CIRCLE &aS2, double aMaxWeight, double aMaxSquaredWeight) const override
Creepage: a board edge shape.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:81
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:372
const TRACKS & Tracks() const
Definition board.h:418
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)
std::vector< CREEP_SHAPE * > m_shapeCollection
CREEPAGE_GRAPH(BOARD &aBoard)
void GeneratePaths(double aMaxWeight, PCB_LAYER_ID aLayer, const std::set< int > *aRelevantNets=nullptr)
Generate creepage paths between graph nodes.
std::shared_ptr< GRAPH_NODE > AddNodeVirtual()
void TransformCreepShapesToNodes(std::vector< CREEP_SHAPE * > &aShapes)
void Trim(double aWeightLimit)
SHAPE_POLY_SET * m_boardOutline
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
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::vector< std::unique_ptr< PCB_SHAPE > > m_ownedBoardEdges
void RemoveConnection(const std::shared_ptr< GRAPH_CONNECTION > &, bool aDelete=false)
std::shared_ptr< GRAPH_NODE > FindNode(GRAPH_NODE::TYPE aType, CREEP_SHAPE *aParent, const VECTOR2I &aPos)
A class used to represent the shapes for creepage calculation.
VECTOR2I GetPos() const
virtual VECTOR2I GetStartPoint() const
virtual std::vector< PATH_CONNECTION > Paths(const BE_SHAPE_POINT &aS2, double aMaxWeight, double aMaxSquaredWeight) const
virtual std::vector< PATH_CONNECTION > Paths(const BE_SHAPE_ARC &aS2, double aMaxWeight, double aMaxSquaredWeight) const
CREEP_SHAPE::TYPE GetType() const
std::vector< PATH_CONNECTION > Paths(const CREEP_SHAPE &aS2, double aMaxWeight, double aMaxSquaredWeight) const
virtual EDA_ANGLE GetEndAngle() const
void SetParent(BOARD_ITEM *aParent)
CREEP_SHAPE::TYPE m_type
virtual std::vector< PATH_CONNECTION > Paths(const CU_SHAPE_ARC &aS2, double aMaxWeight, double aMaxSquaredWeight) const
virtual std::vector< PATH_CONNECTION > Paths(const BE_SHAPE_CIRCLE &aS2, double aMaxWeight, double aMaxSquaredWeight) const
virtual ~CREEP_SHAPE()
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
BOARD_ITEM * m_parent
virtual std::vector< PATH_CONNECTION > Paths(const CU_SHAPE_CIRCLE &aS2, double aMaxWeight, double aMaxSquaredWeight) const
virtual EDA_ANGLE GetStartAngle() const
virtual VECTOR2I GetEndPoint() const
virtual std::vector< PATH_CONNECTION > Paths(const CU_SHAPE_SEGMENT &aS2, double aMaxWeight, double aMaxSquaredWeight) const
std::vector< PATH_CONNECTION > ReversePaths(const std::vector< PATH_CONNECTION > &aV) const
Creepage: a conductive arc.
VECTOR2I GetStartPoint() const override
void SetWidth(double aW)
EDA_ANGLE AngleBetweenStartAndEnd(const VECTOR2I aPoint) const
VECTOR2I GetEndPoint() const override
std::vector< PATH_CONNECTION > Paths(const CU_SHAPE_CIRCLE &aS2, double aMaxWeight, double aMaxSquaredWeight) const override
EDA_ANGLE GetStartAngle() const override
double GetWidth() const
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 CU_SHAPE_SEGMENT &aS2, double aMaxWeight, double aMaxSquaredWeight) 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
std::vector< PATH_CONNECTION > Paths(const CU_SHAPE_SEGMENT &aS2, double aMaxWeight, double aMaxSquaredWeight) 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
int GetRadius() const override
VECTOR2I GetStart() const
double GetWidth() const
VECTOR2I GetEnd() const
CU_SHAPE_SEGMENT(VECTOR2I aStart, VECTOR2I aEnd, double aWidth=0)
Creepage: a conductive shape.
a connection in a
std::shared_ptr< GRAPH_NODE > n2
PATH_CONNECTION m_path
void GetShapes(std::vector< PCB_SHAPE > &aShapes)
std::shared_ptr< GRAPH_NODE > n1
GRAPH_CONNECTION(std::shared_ptr< GRAPH_NODE > &aN1, std::shared_ptr< GRAPH_NODE > &aN2, const PATH_CONNECTION &aPc)
CREEP_SHAPE * m_parent
std::set< std::shared_ptr< GRAPH_CONNECTION > > m_node_conns
GRAPH_NODE(GRAPH_NODE::TYPE aType, CREEP_SHAPE *aParent, const VECTOR2I &aPos=VECTOR2I())
GRAPH_NODE::TYPE m_type
Static (immutable) packed R-tree built via Hilbert-curve bulk loading.
Definition seg.h:38
bool Intersects(const SEG &aSeg) const
Definition seg.cpp:436
int Distance(const SEG &aSeg) const
Compute minimum Euclidean distance to segment aSeg.
Definition seg.cpp:698
Represent a set of closed polygons.
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
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.
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.
An abstract shape on 2D plane.
Definition shape.h:124
constexpr extended_type SquaredEuclideanNorm() const
Compute the squared euclidean norm of the vector, which is defined as (x ** 2 + y ** 2).
Definition vector2d.h:303
The common library.
@ ROUND_ALL_CORNERS
All angles are rounded.
KIRTREE::PACKED_RTREE< CREEPAGE_TRACK_ENTRY *, int, 2 > TRACK_RTREE
bool SegmentIntersectsBoard(const VECTOR2I &aP1, const VECTOR2I &aP2, const std::vector< BOARD_ITEM * > &aBe, const std::vector< const BOARD_ITEM * > &aDontTestAgainst, int aMinGrooveWidth)
void BuildCreepageBoardEdges(BOARD &aBoard, std::vector< BOARD_ITEM * > &aVector, std::vector< std::unique_ptr< PCB_SHAPE > > &aOwned, const std::set< const BOARD_ITEM * > *aExclude=nullptr)
Collect the board-edge items used by the creepage graph.
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:417
static constexpr std::size_t hash_val(const Types &... args)
Definition hash.h:47
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ Edge_Cuts
Definition layer_ids.h:108
This file contains miscellaneous commonly used macros and functions.
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:96
@ SH_SEGMENT
line segment
Definition shape.h:44
bool operator()(const std::shared_ptr< GRAPH_NODE > &lhs, const std::shared_ptr< GRAPH_NODE > &rhs) const
std::size_t operator()(const std::shared_ptr< GRAPH_NODE > &node) const
int halfWidth
const PCB_TRACK * track
SEG segment
PCB_LAYER_ID layer
bool isValid(const BOARD &aBoard, PCB_LAYER_ID aLayer, const std::vector< BOARD_ITEM * > &aBoardEdges, const std::vector< const BOARD_ITEM * > &aIgnoreForTest, SHAPE_POLY_SET *aOutline, const std::pair< bool, bool > &aTestLocalConcavity, int aMinGrooveWidth, TRACK_RTREE *aTrackIndex=nullptr) const
Test if a path is valid.
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:89
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682