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, you may find one here:
17 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
18 * or you may search the http://www.gnu.org website for the version 2 license,
19 * or you may write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23
24#pragma once
25
26#include <memory>
27#include <unordered_set>
28
29#include <common.h>
30#include <core/kicad_algo.h>
31#include <macros.h>
33#include <footprint.h>
34#include <pad.h>
35#include <pcb_track.h>
36#include <pcb_shape.h>
37#include <zone.h>
38#include <advanced_config.h>
39#include <geometry/shape_rect.h>
40#include <geometry/seg.h>
42#include <drc/drc_item.h>
43#include <drc/drc_rule.h>
44#include <board.h>
45
46
49
50
51// Simple wrapper for track segment data in the RTree
59
61
62extern bool SegmentIntersectsBoard( const VECTOR2I& aP1, const VECTOR2I& aP2,
63 const std::vector<BOARD_ITEM*>& aBe,
64 const std::vector<const BOARD_ITEM*>& aDontTestAgainst,
65 int aMinGrooveWidth );
66
67
69{
72 double weight = -1;
73 bool m_show = true;
74
77
78
92 bool isValid( const BOARD& aBoard, PCB_LAYER_ID aLayer,
93 const std::vector<BOARD_ITEM*>& aBoardEdges,
94 const std::vector<const BOARD_ITEM*>& aIgnoreForTest, SHAPE_POLY_SET* aOutline,
95 const std::pair<bool, bool>& aTestLocalConcavity, int aMinGrooveWidth,
96 TRACK_RTREE* aTrackIndex = nullptr ) const
97 {
98 if( !aOutline )
99 return true; // We keep the segment if there is a problem
100
101 if( !SegmentIntersectsBoard( a1, a2, aBoardEdges, aIgnoreForTest, aMinGrooveWidth ) )
102 return false;
103
104 // The mid point should be inside the board.
105 // Tolerance of 100nm.
106
107 VECTOR2I midPoint = ( a1 + a2 ) / 2;
108 int tolerance = 100;
109
110 bool contained = aOutline->Contains( midPoint, -1, tolerance )
111 || aOutline->PointOnEdge( midPoint, tolerance );
112
113 if( !contained )
114 return false;
115
116 if( false && ( aTestLocalConcavity.first || aTestLocalConcavity.second ) )
117 {
118 // Test for local concavity. If it is localy convex, then it will not be a path of interest.
119
120 double extendLine = 1000; // extend line by 1000nm
121 // In some cases, the projected point could be on the board edge
122 // In such cases, we wan to keep the line.
123 // We inflate the polygon to get a small margin for computation/rounding error.
124 // We might keep some unnecessary lines, but it's better than loosing the important ones.
125 double extendPoly = 100; // extend polygon by 10 nm
126
127 VECTOR2D a( double( a1.x ), double( a1.y ) );
128 VECTOR2D b( double( a2.x ), double( a2.y ) );
129
130 VECTOR2D dir( b - a );
131 dir = dir * ( extendLine / dir.SquaredEuclideanNorm() );
132
133 SHAPE_POLY_SET outline2 = *aOutline;
134 outline2.Inflate( extendPoly, CORNER_STRATEGY::ROUND_ALL_CORNERS, 3 );
135
136 if( aTestLocalConcavity.first && !aOutline->Contains( a - dir, -1, 0 ) )
137 return false;
138
139 if( aTestLocalConcavity.second && !aOutline->Contains( b + dir, -1, 0 ) )
140 return false;
141 }
142
143 if( aLayer != Edge_Cuts )
144 {
145 SEG segPath( a1, a2 );
146
147 // A creepage path endpoint sitting strictly inside another track's copper body
148 // is not a real surface point: the visible copper is the enclosing track, and
149 // the path would appear to start/end "inside" the copper in the UI. Reject
150 // connections whose endpoint lies inside any track interior (regardless of
151 // net). The endpoint track itself is in aIgnoreForTest and is skipped.
152 //
153 // The tolerance lets endpoints that sit exactly on a neighbor track's boundary
154 // (for example, two same-net tracks meeting at a shared corner) pass.
155 constexpr int interiorTolerance = 100; // 100 nm
156
157 auto endpointInside = [&]( const SEG& segTrack, int halfWidth ) -> bool
158 {
159 return segTrack.Distance( VECTOR2I( a1 ) ) + interiorTolerance < halfWidth
160 || segTrack.Distance( VECTOR2I( a2 ) ) + interiorTolerance < halfWidth;
161 };
162
163 if( aTrackIndex )
164 {
165 int minX = std::min( (int) a1.x, (int) a2.x );
166 int minY = std::min( (int) a1.y, (int) a2.y );
167 int maxX = std::max( (int) a1.x, (int) a2.x );
168 int maxY = std::max( (int) a1.y, (int) a2.y );
169
170 int searchMin[2] = { minX, minY };
171 int searchMax[2] = { maxX, maxY };
172
173 bool failed = false;
174
175 auto trackVisitor = [&]( CREEPAGE_TRACK_ENTRY* entry ) -> bool
176 {
177 if( !entry || entry->layer != aLayer )
178 return true;
179
180 if( segPath.Intersects( entry->segment ) )
181 {
182 failed = true;
183 return false;
184 }
185
186 if( !alg::contains( aIgnoreForTest, entry->track )
187 && endpointInside( entry->segment, entry->halfWidth ) )
188 {
189 failed = true;
190 return false;
191 }
192
193 return true;
194 };
195
196 aTrackIndex->Search( searchMin, searchMax, trackVisitor );
197
198 if( failed )
199 return false;
200 }
201 else
202 {
203 for( PCB_TRACK* track : aBoard.Tracks() )
204 {
205 if( !track || track->Type() != KICAD_T::PCB_TRACE_T
206 || !track->IsOnLayer( aLayer ) )
207 {
208 continue;
209 }
210
211 std::shared_ptr<SHAPE> sh = track->GetEffectiveShape();
212
213 if( !sh || sh->Type() != SHAPE_TYPE::SH_SEGMENT )
214 continue;
215
216 SEG segTrack( track->GetStart(), track->GetEnd() );
217
218 if( segPath.Intersects( segTrack ) )
219 return false;
220
221 if( !alg::contains( aIgnoreForTest, static_cast<const BOARD_ITEM*>( track ) )
222 && endpointInside( segTrack, track->GetWidth() / 2 ) )
223 {
224 return false;
225 }
226 }
227 }
228 }
229 return true;
230 }
231};
232
233
234class GRAPH_CONNECTION;
235class GRAPH_NODE;
236class CREEPAGE_GRAPH;
237class CREEP_SHAPE;
238class BE_SHAPE;
239class BE_SHAPE_POINT;
240class BE_SHAPE_ARC;
241class BE_SHAPE_CIRCLE;
242class CU_SHAPE;
243class CU_SHAPE_SEGMENT;
244class CU_SHAPE_CIRCLE;
245class CU_SHAPE_ARC;
246
252{
253public:
254 enum class TYPE
255 {
260 };
261
263 {
264 m_conductive = false;
265 m_parent = nullptr;
266 m_pos = VECTOR2I( 0, 0 );
267 m_type = CREEP_SHAPE::TYPE::UNDEFINED;
268 };
269
270 virtual ~CREEP_SHAPE() {}
271
272 virtual int GetRadius() const { return 0; };
273 virtual EDA_ANGLE GetStartAngle() const { return EDA_ANGLE( 0 ); };
274 virtual EDA_ANGLE GetEndAngle() const { return EDA_ANGLE( 0 ); };
275 virtual VECTOR2I GetStartPoint() const { return VECTOR2I( 0, 0 ); };
276 virtual VECTOR2I GetEndPoint() const { return VECTOR2I( 0, 0 ); };
277 VECTOR2I GetPos() const { return m_pos; };
278 CREEP_SHAPE::TYPE GetType() const { return m_type; };
279 const BOARD_ITEM* GetParent() const { return m_parent; };
280 void SetParent( BOARD_ITEM* aParent ) { m_parent = aParent; };
281
282 virtual void ConnectChildren( std::shared_ptr<GRAPH_NODE>& a1, std::shared_ptr<GRAPH_NODE>& a2,
283 CREEPAGE_GRAPH& aG ) const;
284
285 std::vector<PATH_CONNECTION> ReversePaths( const std::vector<PATH_CONNECTION>& aV ) const
286 {
287 std::vector<PATH_CONNECTION> r;
288 r.reserve( aV.size() );
289
290 for( const auto& pc : aV )
291 {
292 r.emplace_back( pc );
293 std::swap( r.back().a1, r.back().a2 );
294 }
295
296 return r;
297 }
298
299 std::vector<PATH_CONNECTION> Paths( const CREEP_SHAPE& aS2, double aMaxWeight,
300 double aMaxSquaredWeight ) const
301 {
302 std::vector<PATH_CONNECTION> a;
303 return a;
304 };
305
306 virtual std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
307 double aMaxSquaredWeight ) const
308 {
309 std::vector<PATH_CONNECTION> a;
310 return a;
311 };
312
313 virtual std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
314 double aMaxSquaredWeight ) const
315 {
316 std::vector<PATH_CONNECTION> a;
317 return a;
318 };
319
320 virtual std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
321 double aMaxSquaredWeight ) const
322 {
323 std::vector<PATH_CONNECTION> a;
324 return a;
325 };
326
327 virtual std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
328 double aMaxSquaredWeight ) const
329 {
330 std::vector<PATH_CONNECTION> a;
331 return a;
332 };
333
334 virtual std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
335 double aMaxSquaredWeight ) const
336 {
337 std::vector<PATH_CONNECTION> a;
338 return a;
339 };
340
341 virtual std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_ARC& aS2, double aMaxWeight,
342 double aMaxSquaredWeight ) const
343 {
344 std::vector<PATH_CONNECTION> a;
345 return a;
346 };
347
348 //virtual std::vector<PATH_CONNECTION> GetPathsCuToBe( CREEP_SHAPE* aShape ) const{ std::vector<PATH_CONNECTION> a; return a;};
349 bool IsConductive() { return m_conductive; };
350
351protected:
356};
357
358
363class CU_SHAPE : public CREEP_SHAPE
364{
365public:
368 {
369 m_conductive = true;
370 };
371};
372
377class BE_SHAPE : public CREEP_SHAPE
378{
379public:
382 {
383 m_conductive = false;
384 };
385};
386
392{
393public:
394 CU_SHAPE_SEGMENT( VECTOR2I aStart, VECTOR2I aEnd, double aWidth = 0 ) :
395 CU_SHAPE()
396 {
397 m_start = aStart;
398 m_end = aEnd;
399 m_width = aWidth;
400 m_pos = ( aStart + aEnd ) / 2;
401 }
402
403 VECTOR2I GetStart() const { return m_start; };
404 VECTOR2I GetEnd() const { return m_end; };
405 double GetWidth() const { return m_width; };
406
407 int GetRadius() const override
408 {
409 return (int) ( ( m_start - m_end ).EuclideanNorm() / 2 ) + (int) ( m_width / 2 );
410 };
411
412 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
413 double aMaxSquaredWeight ) const override;
414 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
415 double aMaxSquaredWeight ) const override;
416 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
417 double aMaxSquaredWeight ) const override;
418 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
419 double aMaxSquaredWeight ) const override;
420 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
421 double aMaxSquaredWeight ) const override;
422 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_ARC& aS2, double aMaxWeight,
423 double aMaxSquaredWeight ) const override;
424
425
426private:
429 double m_width = 0;
430};
431
437{
438public:
439 CU_SHAPE_CIRCLE( VECTOR2I aPos, double aRadius = 0 ) :
440 CU_SHAPE()
441 {
442 m_pos = aPos;
443 m_radius = aRadius;
444 }
445
446 int GetRadius() const override { return m_radius; };
447
448 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
449 double aMaxSquaredWeight ) const override;
450 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
451 double aMaxSquaredWeight ) const override;
452 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
453 double aMaxSquaredWeight ) const override;
454 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
455 double aMaxSquaredWeight ) const override
456 {
457 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
458 };
459
460 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
461 double aMaxSquaredWeight ) const override;
462 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_ARC& aS2, double aMaxWeight,
463 double aMaxSquaredWeight ) const override;
464
465protected:
466 double m_radius = 1;
467};
468
474{
475public:
476 CU_SHAPE_ARC( VECTOR2I aPos, double aRadius, EDA_ANGLE aStartAngle, EDA_ANGLE aEndAngle,
477 VECTOR2D aStartPoint, VECTOR2D aEndPoint ) :
478 CU_SHAPE_CIRCLE( aPos, aRadius ),
479 m_startAngle( aStartAngle ),
480 m_endAngle( aEndAngle ),
481 m_startPoint( aStartPoint ),
482 m_endPoint( aEndPoint )
483 {
484 m_type = CREEP_SHAPE::TYPE::ARC;
485 m_width = 0;
486 }
487
488 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
489 double aMaxSquaredWeight ) const override;
490
491 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
492 double aMaxSquaredWeight ) const override;
493
494 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
495 double aMaxSquaredWeight ) const override;
496
497 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
498 double aMaxSquaredWeight ) const override
499 {
500 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
501 };
502
503 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
504 double aMaxSquaredWeight ) const override
505 {
506 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
507 };
508
509 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_ARC& aS2, double aMaxWeight,
510 double aMaxSquaredWeight ) const override;
511
512 EDA_ANGLE GetStartAngle() const override { return m_startAngle; }
513 EDA_ANGLE GetEndAngle() const override { return m_endAngle; }
514 int GetRadius() const override { return m_radius; }
515
516 VECTOR2I GetStartPoint() const override { return m_startPoint; }
517 VECTOR2I GetEndPoint() const override { return m_endPoint; }
518
520 {
521 EDA_ANGLE angle( aPoint - m_pos );
522
523 while( angle < GetStartAngle() )
524 angle += ANGLE_360;
525
526 while( angle > GetEndAngle() + ANGLE_360 )
527 angle -= ANGLE_360;
528
529 return angle;
530 }
531
532 double GetWidth() const { return m_width; };
533 void SetWidth( double aW ) { m_width = aW; };
534
535private:
541};
542
548{
549public:
558
559 GRAPH_NODE( GRAPH_NODE::TYPE aType, CREEP_SHAPE* aParent, const VECTOR2I& aPos = VECTOR2I() ) :
560 m_parent( aParent ),
561 m_pos( aPos ),
562 m_type( aType )
563 {
564 m_node_conns = {};
565 m_virtual = false;
566 m_connectDirectly = true;
567 m_net = -1;
568 };
569
571
572public:
574 std::set<std::shared_ptr<GRAPH_CONNECTION>> m_node_conns;
576
577 // Virtual nodes are connected with a 0 weight connection to equivalent net ( same net or netclass )
580 int m_net;
581
583};
584
590{
591public:
592 GRAPH_CONNECTION( std::shared_ptr<GRAPH_NODE>& aN1, std::shared_ptr<GRAPH_NODE>& aN2,
593 const PATH_CONNECTION& aPc ) :
594 n1( aN1 ),
595 n2( aN2 )
596 {
597 m_path = aPc;
598 m_forceStraightLine = false;
599 };
600
601 void GetShapes( std::vector<PCB_SHAPE>& aShapes );
602
603public:
604 std::shared_ptr<GRAPH_NODE> n1;
605 std::shared_ptr<GRAPH_NODE> n2;
608};
609
610
616{
617public:
619 BE_SHAPE()
620 {
621 m_pos = aPos;
622 m_type = CREEP_SHAPE::TYPE::POINT;
623 }
624
625 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
626 double aMaxSquaredWeight ) const override;
627
628 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
629 double aMaxSquaredWeight ) const override;
630
631 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
632 double aMaxSquaredWeight ) const override;
633
634 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
635 double aMaxSquaredWeight ) const override
636 {
637 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
638 };
639
640 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
641 double aMaxSquaredWeight ) const override
642 {
643 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
644 }
645
646 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_ARC& aS2, double aMaxWeight,
647 double aMaxSquaredWeight ) const override
648 {
649 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
650 };
651
652
653 void ConnectChildren( std::shared_ptr<GRAPH_NODE>& a1, std::shared_ptr<GRAPH_NODE>& a2,
654 CREEPAGE_GRAPH& aG ) const override;
655};
656
662{
663public:
664 BE_SHAPE_CIRCLE( VECTOR2I aPos = VECTOR2I( 0, 0 ), int aRadius = 0 ) :
665 BE_SHAPE()
666 {
667 m_pos = aPos;
668 m_radius = aRadius;
669 m_type = CREEP_SHAPE::TYPE::CIRCLE;
670 }
671
672 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
673 double aMaxSquaredWeight ) const override
674 {
675 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
676 };
677
678 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
679 double aMaxSquaredWeight ) const override;
680
681 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
682 double aMaxSquaredWeight ) const override;
683
684 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
685 double aMaxSquaredWeight ) const override
686 {
687 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
688 };
689
690 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
691 double aMaxSquaredWeight ) const override
692 {
693 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
694 };
695
696
697 int GetRadius() const override { return m_radius; }
698
699 void ConnectChildren( std::shared_ptr<GRAPH_NODE>& a1, std::shared_ptr<GRAPH_NODE>& a2,
700 CREEPAGE_GRAPH& aG ) const override;
701
702 void ShortenChildDueToGV( std::shared_ptr<GRAPH_NODE>& a1, std::shared_ptr<GRAPH_NODE>& a2,
703 CREEPAGE_GRAPH& aG, double aNormalWeight ) const;
704
705
706protected:
708};
709
715{
716public:
717 BE_SHAPE_ARC( VECTOR2I aPos, int aRadius, EDA_ANGLE aStartAngle, EDA_ANGLE aEndAngle,
718 VECTOR2D aStartPoint, VECTOR2D aEndPoint ) :
719 BE_SHAPE_CIRCLE( aPos, aRadius ),
720 m_startAngle( aStartAngle ), m_endAngle( aEndAngle ),
721 m_startPoint( aStartPoint ), m_endPoint( aEndPoint )
722 {
723 m_type = CREEP_SHAPE::TYPE::ARC;
724 }
725
726 void ConnectChildren( std::shared_ptr<GRAPH_NODE>& a1, std::shared_ptr<GRAPH_NODE>& a2,
727 CREEPAGE_GRAPH& aG ) const override;
728
729
730 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
731 double aMaxSquaredWeight ) const override
732 {
733 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
734 };
735 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
736 double aMaxSquaredWeight ) const override
737 {
738 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
739 };
740 std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
741 double aMaxSquaredWeight ) const override;
742
743 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
744 double aMaxSquaredWeight ) const override
745 {
746 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
747 };
748 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
749 double aMaxSquaredWeight ) const override
750 {
751 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
752 };
753 std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_ARC& aS2, double aMaxWeight,
754 double aMaxSquaredWeight ) const override
755 {
756 return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
757 };
758
759 EDA_ANGLE GetStartAngle() const override { return m_startAngle; }
760 EDA_ANGLE GetEndAngle() const override { return m_endAngle; }
761 int GetRadius() const override { return m_radius; }
762
763 VECTOR2I GetStartPoint() const override { return m_startPoint; }
764 VECTOR2I GetEndPoint() const override { return m_endPoint; }
766 {
767 EDA_ANGLE angle( aPoint - m_pos );
768
769 while( angle < m_startAngle )
770 angle += ANGLE_360;
771 while( angle > m_endAngle + ANGLE_360 )
772 angle -= ANGLE_360;
773
774 return angle;
775 }
776
777 std::pair<bool, bool> IsThereATangentPassingThroughPoint( const BE_SHAPE_POINT aPoint ) const;
778
779protected:
784};
785
786
792{
793public:
795 m_board( aBoard )
796 {
797 m_boardOutline = nullptr;
799 m_creepageTarget = -1;
801 };
802
804 {
805 for( CREEP_SHAPE* cs : m_shapeCollection )
806 {
807 if( cs )
808 {
809 delete cs;
810 cs = nullptr;
811 }
812 }
813
814 // Clear out the circular shared pointer references
815 for( std::shared_ptr<GRAPH_NODE>& n : m_nodes )
816 {
817 if( n )
818 {
819 n->m_node_conns.clear();
820 n = nullptr;
821 }
822 }
823
824 for( std::shared_ptr<GRAPH_CONNECTION>& c : m_connections )
825 {
826 if( c )
827 c = nullptr;
828 }
829 };
830
832 void TransformCreepShapesToNodes(std::vector<CREEP_SHAPE*>& aShapes);
834
835 // Add a node to the graph. If an equivalent node exists, returns the pointer of the existing node instead
836 std::shared_ptr<GRAPH_NODE> AddNode( GRAPH_NODE::TYPE aType, CREEP_SHAPE* aParent = nullptr,
837 const VECTOR2I& aPos = VECTOR2I() );
838
839 std::shared_ptr<GRAPH_NODE> AddNodeVirtual();
840
841 std::shared_ptr<GRAPH_CONNECTION> AddConnection( std::shared_ptr<GRAPH_NODE>& aN1,
842 std::shared_ptr<GRAPH_NODE>& aN2,
843 const PATH_CONNECTION& aPc );
844
845 std::shared_ptr<GRAPH_CONNECTION> AddConnection( std::shared_ptr<GRAPH_NODE>& aN1,
846 std::shared_ptr<GRAPH_NODE>& aN2 );
847
848 std::shared_ptr<GRAPH_NODE> FindNode( GRAPH_NODE::TYPE aType, CREEP_SHAPE* aParent,
849 const VECTOR2I& aPos );
850
851 void RemoveConnection( const std::shared_ptr<GRAPH_CONNECTION>&, bool aDelete = false );
852
853 void Trim( double aWeightLimit );
854
855 void Addshape( const SHAPE& aShape, std::shared_ptr<GRAPH_NODE>& aConnectTo,
856 BOARD_ITEM* aParent = nullptr );
857
858 double Solve( std::shared_ptr<GRAPH_NODE>& aFrom, std::shared_ptr<GRAPH_NODE>& aTo,
859 std::vector<std::shared_ptr<GRAPH_CONNECTION>>& aResult );
860
861 void GeneratePaths( double aMaxWeight, PCB_LAYER_ID aLayer );
862
863 std::shared_ptr<GRAPH_NODE> AddNetElements( int aNetCode, PCB_LAYER_ID aLayer, int aMaxCreepage );
864
865 void SetTarget( double aTarget );
866 double GetTarget() { return m_creepageTarget; };
867
869 {
870 std::size_t operator()(const std::shared_ptr<GRAPH_NODE>& node) const
871 {
872 return hash_val(node->m_type, node->m_parent, node->m_pos.x, node->m_pos.y);
873 }
874 };
875
877 {
878 bool operator()(const std::shared_ptr<GRAPH_NODE>& lhs, const std::shared_ptr<GRAPH_NODE>& rhs) const
879 {
880 return lhs->m_type == rhs->m_type && lhs->m_parent == rhs->m_parent && lhs->m_pos == rhs->m_pos;
881 }
882 };
883
884public:
886 std::vector<BOARD_ITEM*> m_boardEdge;
887 std::vector<std::unique_ptr<PCB_SHAPE>> m_ownedBoardEdges;
889 std::vector<std::shared_ptr<GRAPH_NODE>> m_nodes;
890 std::vector<std::shared_ptr<GRAPH_CONNECTION>> m_connections;
891 std::vector<CREEP_SHAPE*> m_shapeCollection;
892
893 // This is a duplicate of m_nodes, but it is used to quickly find a node rather than iterating through m_nodes
894 std::unordered_set<std::shared_ptr<GRAPH_NODE>, GraphNodeHash, GraphNodeEqual> m_nodeset;
895
897
898private:
901};
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:84
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:323
const TRACKS & Tracks() const
Definition board.h:362
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)
std::shared_ptr< GRAPH_NODE > AddNodeVirtual()
void TransformCreepShapesToNodes(std::vector< CREEP_SHAPE * > &aShapes)
void Trim(double aWeightLimit)
SHAPE_POLY_SET * m_boardOutline
std::vector< BOARD_ITEM * > m_boardEdge
std::unordered_set< std::shared_ptr< GRAPH_NODE >, GraphNodeHash, GraphNodeEqual > m_nodeset
void GeneratePaths(double aMaxWeight, PCB_LAYER_ID aLayer)
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:42
bool Intersects(const SEG &aSeg) const
Definition seg.cpp:440
int Distance(const SEG &aSeg) const
Compute minimum Euclidean distance to segment aSeg.
Definition seg.cpp:702
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:128
constexpr extended_type SquaredEuclideanNorm() const
Compute the squared euclidean norm of the vector, which is defined as (x ** 2 + y ** 2).
Definition vector2d.h:307
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)
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:417
static constexpr std::size_t hash_val(const Types &... args)
Definition hash.h:51
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ Edge_Cuts
Definition layer_ids.h:112
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:100
@ SH_SEGMENT
line segment
Definition shape.h:48
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:93
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687
VECTOR2< double > VECTOR2D
Definition vector2d.h:686