KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pns_kicad_iface.cpp
Go to the documentation of this file.
1/*
2 * KiRouter - a push-and-(sometimes-)shove PCB router
3 *
4 * Copyright (C) 2013-2016 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * Author: Tomasz Wlostowski <[email protected]>
7 *
8 * This program is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22#include <board.h>
26#include <netinfo.h>
27#include <footprint.h>
28#include <layer_range.h>
30#include <pad.h>
31#include <pcb_track.h>
32#include <zone.h>
33#include <pcb_shape.h>
34#include <pcb_generator.h>
35#include <pcb_text.h>
36#include <pcb_barcode.h>
37#include <pcb_table.h>
38#include <pcb_tablecell.h>
39#include <pcb_dimension.h>
40#include <board_commit.h>
41#include <eda_group.h>
42#include <layer_ids.h>
43#include <optional>
44#include <kidialog.h>
45#include <tools/pcb_tool_base.h>
47#include <tool/tool_manager.h>
49
51#include <pcb_painter.h>
52
53#include <geometry/shape.h>
55#include <geometry/shape_arc.h>
59
60#include <drc/drc_rule.h>
61#include <drc/drc_engine.h>
62
64
65#include <wx/log.h>
66
67#include <memory>
68#include <unordered_map>
69#include <unordered_set>
70
71#include <advanced_config.h>
72#include <pcbnew_settings.h>
73#include <macros.h>
74
75#include "pns_kicad_iface.h"
76#include "pns_arc.h"
77#include "pns_sizes_settings.h"
78#include "pns_item.h"
79#include "pns_layerset.h"
80#include "pns_line.h"
81#include "pns_solid.h"
82#include "pns_segment.h"
83#include "pns_node.h"
84#include "pns_router.h"
85#include "pns_debug_decorator.h"
86#include "pns_diff_pair.h"
87#include "pns_topology.h"
88#include "router_preview_item.h"
89
91
92// Keep this odd so that it can never match a "real" pointer
93#define ENTERED_GROUP_MAGIC_NUMBER ( (BOARD*)777 )
94
96{
97 const PNS::ITEM* A;
98 const PNS::ITEM* B;
99 bool Flag;
100
101 CLEARANCE_CACHE_KEY( const PNS::ITEM* aA, const PNS::ITEM* aB, bool aFlag ) :
102 A( aA < aB ? aA : aB ),
103 B( aA < aB ? aB : aA ),
104 Flag( aFlag )
105 {
106 }
107
108 bool operator==( const CLEARANCE_CACHE_KEY& other ) const
109 {
110 return A == other.A && B == other.B && Flag == other.Flag;
111 }
112};
113
114namespace std
115{
116 template <>
118 {
119 std::size_t operator()( const CLEARANCE_CACHE_KEY& k ) const
120 {
121 size_t retval = 0xBADC0FFEE0DDF00D;
122 hash_combine( retval, hash<const void*>()( k.A ), hash<const void*>()( k.B ),
123 hash<int>()( k.Flag ) );
124 return retval;
125 }
126 };
127}
128
129
130// Identifies a pair of items for the temporary clearance cache by their properties (net, layers,
131// kind) instead of their memory address. Items with the same properties get the same clearance
132// from the rules, so they share one cache entry.
134{
135 struct SIDE
136 {
137 const void* boardItem;
138 const void* net;
141 int kind;
143
144 bool operator==( const SIDE& o ) const
145 {
146 return boardItem == o.boardItem && net == o.net && layerStart == o.layerStart && layerEnd == o.layerEnd
147 && kind == o.kind && freePad == o.freePad;
148 }
149
150 bool operator<( const SIDE& o ) const
151 {
152 if( boardItem != o.boardItem )
153 return boardItem < o.boardItem;
154 if( net != o.net )
155 return net < o.net;
156 if( layerStart != o.layerStart )
157 return layerStart < o.layerStart;
158 if( layerEnd != o.layerEnd )
159 return layerEnd < o.layerEnd;
160 if( kind != o.kind )
161 return kind < o.kind;
162 return freePad < o.freePad;
163 }
164 };
165
168 bool Flag;
169
170 static SIDE makeSide( const PNS::ITEM* aItem )
171 {
172 return SIDE{ (const void*) aItem->BoardItem(),
173 (const void*) aItem->Net(),
174 aItem->Layers().Start(),
175 aItem->Layers().End(),
176 (int) aItem->Kind(),
177 aItem->IsFreePad() };
178 }
179
180 TEMP_CLEARANCE_CACHE_KEY( const PNS::ITEM* aA, const PNS::ITEM* aB, bool aFlag ) :
181 Flag( aFlag )
182 {
183 SIDE sa = makeSide( aA );
184 SIDE sb = makeSide( aB );
185
186 // Canonical order so the key is symmetric in (A, B)
187 if( sb < sa )
188 {
189 A = sb;
190 B = sa;
191 }
192 else
193 {
194 A = sa;
195 B = sb;
196 }
197 }
198
199 bool operator==( const TEMP_CLEARANCE_CACHE_KEY& o ) const { return A == o.A && B == o.B && Flag == o.Flag; }
200};
201
202namespace std
203{
204template <>
206{
207 std::size_t operator()( const TEMP_CLEARANCE_CACHE_KEY& k ) const
208 {
209 size_t retval = 0xBADC0FFEE0DDF00D;
210
211 for( const TEMP_CLEARANCE_CACHE_KEY::SIDE* s : { &k.A, &k.B } )
212 {
213 hash_combine( retval, hash<const void*>()( s->boardItem ), hash<const void*>()( s->net ),
214 hash<int>()( s->layerStart ), hash<int>()( s->layerEnd ), hash<int>()( s->kind ),
215 hash<bool>()( s->freePad ) );
216 }
217
218 hash_combine( retval, hash<bool>()( k.Flag ) );
219 return retval;
220 }
221};
222} // namespace std
223
224
226{
230 int layer;
231
232 bool operator==( const HULL_CACHE_KEY& other ) const
233 {
234 return item == other.item
235 && clearance == other.clearance
237 && layer == other.layer;
238 }
239};
240
241namespace std
242{
243 template <>
244 struct hash<HULL_CACHE_KEY>
245 {
246 std::size_t operator()( const HULL_CACHE_KEY& k ) const
247 {
248 size_t retval = 0xBADC0FFEE0DDF00D;
249 hash_combine( retval, hash<const void*>()( k.item ), hash<int>()( k.clearance ),
250 hash<int>()( k.walkaroundThickness ), hash<int>()( k.layer ) );
251 return retval;
252 }
253 };
254}
255
256
258{
259public:
260 PNS_PCBNEW_RULE_RESOLVER( BOARD* aBoard, PNS::ROUTER_IFACE* aRouterIface );
262
263 int Clearance( const PNS::ITEM* aA, const PNS::ITEM* aB,
264 bool aUseClearanceEpsilon = true ) override;
265
266 bool HasUserDefinedPhysicalConstraint() override;
267
269 int DpNetPolarity( PNS::NET_HANDLE aNet ) override;
270 bool DpNetPair( const PNS::ITEM* aItem, PNS::NET_HANDLE& aNetP,
271 PNS::NET_HANDLE& aNetN ) override;
272
273 int NetCode( PNS::NET_HANDLE aNet ) override;
274 wxString NetName( PNS::NET_HANDLE aNet ) override;
275
276 bool IsInNetTie( const PNS::ITEM* aA ) override;
277 bool IsNetTieExclusion( const PNS::ITEM* aItem, const VECTOR2I& aCollisionPos,
278 const PNS::ITEM* aCollidingItem ) override;
279
280 bool IsDrilledHole( const PNS::ITEM* aItem ) override;
281 bool IsNonPlatedSlot( const PNS::ITEM* aItem ) override;
282
287 bool IsKeepout( const PNS::ITEM* aObstacle, const PNS::ITEM* aItem, bool* aEnforce ) override;
288
289 bool QueryConstraint( PNS::CONSTRAINT_TYPE aType, const PNS::ITEM* aItemA,
290 const PNS::ITEM* aItemB, int aLayer,
291 PNS::CONSTRAINT* aConstraint ) override;
292
293 int ClearanceEpsilon() const override { return m_clearanceEpsilon; }
294
295 void ClearCacheForItems( std::vector<const PNS::ITEM*>& aItems ) override;
296 void ClearCaches() override;
297 void ClearTemporaryCaches() override;
298
299 const SHAPE_LINE_CHAIN& HullCache( const PNS::ITEM* aItem, int aClearance,
300 int aWalkaroundThickness, int aLayer ) override;
301
302private:
303 BOARD_ITEM* getBoardItem( const PNS::ITEM* aItem, PCB_LAYER_ID aBoardLayer, int aIdx = 0 );
304
305private:
312
313 // Cached for the routing session; HasUserDefinedPhysicalConstraint runs in the
314 // collideSimple inner loop and walks the DRC engine map otherwise.
315 std::optional<bool> m_hasUserPhysicalConstraint;
316
317 std::unordered_map<CLEARANCE_CACHE_KEY, int> m_clearanceCache;
318 std::unordered_map<TEMP_CLEARANCE_CACHE_KEY, int> m_tempClearanceCache;
319 std::unordered_map<HULL_CACHE_KEY, SHAPE_LINE_CHAIN> m_hullCache;
320};
321
322
324 PNS::ROUTER_IFACE* aRouterIface ) :
325 m_routerIface( aRouterIface ),
326 m_board( aBoard ),
327 m_dummyTracks{ { aBoard }, { aBoard } },
328 m_dummyArcs{ { aBoard }, { aBoard } },
329 m_dummyVias{ { aBoard }, { aBoard } }
330{
331 for( PCB_TRACK& track : m_dummyTracks )
332 track.SetFlags( ROUTER_TRANSIENT );
333
334 for( PCB_ARC& arc : m_dummyArcs )
335 arc.SetFlags( ROUTER_TRANSIENT );
336
337 for ( PCB_VIA& via : m_dummyVias )
338 via.SetFlags( ROUTER_TRANSIENT );
339
340 if( aBoard )
341 m_clearanceEpsilon = aBoard->GetDesignSettings().GetDRCEpsilon();
342 else
343 m_clearanceEpsilon = 0;
344}
345
346
350
351
353{
354 BOARD_ITEM* item = aA->BoardItem();
355
356 return item && item->GetParentFootprint() && item->GetParentFootprint()->IsNetTie();
357}
358
359
361 const VECTOR2I& aCollisionPos,
362 const PNS::ITEM* aCollidingItem )
363{
364 if( !aItem || !aCollidingItem )
365 return false;
366
367 std::shared_ptr<DRC_ENGINE> drcEngine = m_board->GetDesignSettings().m_DRCEngine;
368 BOARD_ITEM* item = aItem->BoardItem();
369 BOARD_ITEM* collidingItem = aCollidingItem->BoardItem();
370
371 FOOTPRINT* collidingFp = collidingItem->GetParentFootprint();
372 FOOTPRINT* itemFp = item ? item->GetParentFootprint() : nullptr;
373
374 if( collidingFp && itemFp && ( collidingFp == itemFp ) && itemFp->IsNetTie() )
375 {
376 // Two items colliding from the same net tie footprint are not checked
377 return true;
378 }
379
380 if( drcEngine )
381 {
382 return drcEngine->IsNetTieExclusion( NetCode( aItem->Net() ),
383 m_routerIface->GetBoardLayerFromPNSLayer( aItem->Layer() ),
384 aCollisionPos, collidingItem );
385 }
386
387 return false;
388}
389
390
391bool PNS_PCBNEW_RULE_RESOLVER::IsKeepout( const PNS::ITEM* aObstacle, const PNS::ITEM* aItem,
392 bool* aEnforce )
393{
394 auto checkKeepout =
395 []( const ZONE* aKeepout, const BOARD_ITEM* aOther )
396 {
397 if( !aOther )
398 return false;
399
400 if( aKeepout->GetDoNotAllowTracks() && aOther->IsType( { PCB_ARC_T, PCB_TRACE_T } ) )
401 return true;
402
403 if( aKeepout->GetDoNotAllowVias() && aOther->Type() == PCB_VIA_T )
404 return true;
405
406 if( aKeepout->GetDoNotAllowPads() && aOther->Type() == PCB_PAD_T )
407 return true;
408
409 // Incomplete test, but better than nothing:
410 if( aKeepout->GetDoNotAllowFootprints() && aOther->Type() == PCB_PAD_T )
411 {
412 return !aKeepout->GetParentFootprint()
413 || aKeepout->GetParentFootprint() != aOther->GetParentFootprint();
414 }
415
416 return false;
417 };
418
419 if( aObstacle->Parent() && aObstacle->Parent()->Type() == PCB_ZONE_T )
420 {
421 const ZONE* zone = static_cast<ZONE*>( aObstacle->Parent() );
422
423 if( zone->GetIsRuleArea() && zone->HasKeepoutParametersSet() )
424 {
425 *aEnforce = checkKeepout( zone,
426 getBoardItem( aItem, m_routerIface->GetBoardLayerFromPNSLayer(
427 aObstacle->Layer() ) ) );
428 return true;
429 }
430 }
431
432 return false;
433}
434
435
436static bool isCopper( const PNS::ITEM* aItem )
437{
438 if ( !aItem )
439 return false;
440
441 const BOARD_ITEM *parent = aItem->Parent();
442
443 return !parent || parent->IsOnCopperLayer();
444}
445
446
447static bool isHole( const PNS::ITEM* aItem )
448{
449 if ( !aItem )
450 return false;
451
452 return aItem->OfKind( PNS::ITEM::HOLE_T );
453}
454
455
456static bool isEdge( const PNS::ITEM* aItem )
457{
458 if ( !aItem )
459 return false;
460
461 const PCB_SHAPE *parent = dynamic_cast<PCB_SHAPE*>( aItem->BoardItem() );
462
463 return parent && ( parent->IsOnLayer( Edge_Cuts ) || parent->IsOnLayer( Margin ) );
464}
465
466
468{
469 if( !isHole( aItem ) )
470 return false;
471
472 BOARD_ITEM* parent = aItem->Parent();
473
474 if( !parent && aItem->ParentPadVia() )
475 {
476 const PNS::ITEM* padVia = aItem->ParentPadVia();
477 parent = padVia->Parent();
478
479 // A via the router is still placing has no board item yet; its hole is drilled all the
480 // same, otherwise it only ever gets hole-to-copper clearance against other holes.
481 if( !parent && padVia->OfKind( PNS::ITEM::VIA_T ) )
482 {
483 VIATYPE type = static_cast<const PNS::VIA*>( padVia )->ViaType();
484 return type == VIATYPE::THROUGH || type == VIATYPE::BLIND || type == VIATYPE::BURIED;
485 }
486 }
487
488 return parent && parent->HasDrilledHole();
489}
490
491
493{
494 if( !isHole( aItem ) )
495 return false;
496
497 BOARD_ITEM* parent = aItem->Parent();
498
499 if( !parent && aItem->ParentPadVia() )
500 parent = aItem->ParentPadVia()->Parent();
501
502 if( parent )
503 {
504 if( parent->Type() == PCB_PAD_T )
505 {
506 PAD* pad = static_cast<PAD*>( parent );
507
508 return pad->GetAttribute() == PAD_ATTRIB::NPTH
509 && pad->GetDrillSizeX() != pad->GetDrillSizeY();
510 }
511
512 // Via holes are (currently) always round, and always plated
513 }
514
515 return false;
516}
517
518
520{
521 switch( aItem->Kind() )
522 {
523 case PNS::ITEM::ARC_T:
524 m_dummyArcs[aIdx].SetLayer( aBoardLayer );
525 m_dummyArcs[aIdx].SetNet( static_cast<NETINFO_ITEM*>( aItem->Net() ) );
526 m_dummyArcs[aIdx].SetStart( aItem->Anchor( 0 ) );
527 m_dummyArcs[aIdx].SetEnd( aItem->Anchor( 1 ) );
528 return &m_dummyArcs[aIdx];
529
530 case PNS::ITEM::VIA_T:
532 m_dummyVias[aIdx].SetLayer( aBoardLayer );
533 m_dummyVias[aIdx].SetNet( static_cast<NETINFO_ITEM*>( aItem->Net() ) );
534 m_dummyVias[aIdx].SetStart( aItem->Anchor( 0 ) );
535 return &m_dummyVias[aIdx];
536
539 m_dummyTracks[aIdx].SetLayer( aBoardLayer );
540 m_dummyTracks[aIdx].SetNet( static_cast<NETINFO_ITEM*>( aItem->Net() ) );
541 m_dummyTracks[aIdx].SetStart( aItem->Anchor( 0 ) );
542 m_dummyTracks[aIdx].SetEnd( aItem->Anchor( 1 ) );
543 return &m_dummyTracks[aIdx];
544
545 default:
546 return nullptr;
547 }
548}
549
550
552 const PNS::ITEM* aItemA, const PNS::ITEM* aItemB,
553 int aPNSLayer, PNS::CONSTRAINT* aConstraint )
554{
555 std::shared_ptr<DRC_ENGINE> drcEngine = m_board->GetDesignSettings().m_DRCEngine;
556
557 if( !drcEngine )
558 return false;
559
560 DRC_CONSTRAINT_T hostType;
561
562 switch ( aType )
563 {
577 default: return false; // should not happen
578 }
579
580 BOARD_ITEM* parentA = aItemA ? aItemA->BoardItem() : nullptr;
581 BOARD_ITEM* parentB = aItemB ? aItemB->BoardItem() : nullptr;
582 PCB_LAYER_ID board_layer = m_routerIface->GetBoardLayerFromPNSLayer( aPNSLayer );
583 DRC_CONSTRAINT hostConstraint;
584
585 // For clearance-type constraints, pick the smaller (more permissive) value.
586 // Returns true if we found a zero/negative clearance (can't get more permissive).
587 auto pickSmallerConstraint = []( DRC_CONSTRAINT& aBest, const DRC_CONSTRAINT& aCandidate ) -> bool
588 {
589 if( aCandidate.IsNull() )
590 return false;
591
592 if( aBest.IsNull() )
593 {
594 aBest = aCandidate;
595 }
596 else if( aCandidate.m_Value.HasMin() && aBest.m_Value.HasMin()
597 && aCandidate.m_Value.Min() < aBest.m_Value.Min() )
598 {
599 aBest = aCandidate;
600 }
601
602 return aBest.m_Value.HasMin() && aBest.m_Value.Min() <= 0;
603 };
604
605 // Check for multi-segment LINEs without BoardItems. These need segment-by-segment
606 // evaluation because custom DRC rules may have geometry-dependent conditions (like
607 // intersectsCourtyard) that require evaluating actual segment positions.
608 auto isMultiSegmentLine = []( const PNS::ITEM* aItem, BOARD_ITEM* aParent ) -> bool
609 {
610 if( !aItem || aParent || aItem->Kind() != PNS::ITEM::LINE_T )
611 return false;
612
613 const auto* line = static_cast<const PNS::LINE*>( aItem );
614 return line->CLine().SegmentCount() > 1;
615 };
616
617 bool lineANeedsSegmentEval = false;
618 bool lineBNeedsSegmentEval = false;
619
620 if( drcEngine->HasGeometryDependentRules() )
621 {
622 lineANeedsSegmentEval = isMultiSegmentLine( aItemA, parentA );
623 lineBNeedsSegmentEval = isMultiSegmentLine( aItemB, parentB );
624 }
625
626 // Evaluate segments of a multi-segment LINE against a single opposing item.
627 auto evaluateLineSegments = [&]( const PNS::ITEM* aLineItem, BOARD_ITEM* aOpposingItem,
628 bool aLineIsFirst, int aIdx ) -> DRC_CONSTRAINT
629 {
630 DRC_CONSTRAINT bestConstraint;
631 const auto* line = static_cast<const PNS::LINE*>( aLineItem );
632 const SHAPE_LINE_CHAIN& chain = line->CLine();
633
634 PCB_TRACK& dummyTrack = m_dummyTracks[aIdx];
635 dummyTrack.SetLayer( board_layer );
636 dummyTrack.SetNet( static_cast<NETINFO_ITEM*>( aLineItem->Net() ) );
637 dummyTrack.SetWidth( line->Width() );
638
639 for( int i = 0; i < chain.SegmentCount(); i++ )
640 {
641 dummyTrack.SetStart( chain.CPoint( i ) );
642 dummyTrack.SetEnd( chain.CPoint( i + 1 ) );
643
644 DRC_CONSTRAINT segConstraint = aLineIsFirst
645 ? drcEngine->EvalRules( hostType, &dummyTrack, aOpposingItem, board_layer )
646 : drcEngine->EvalRules( hostType, aOpposingItem, &dummyTrack, board_layer );
647
648 if( pickSmallerConstraint( bestConstraint, segConstraint ) )
649 break;
650 }
651
652 return bestConstraint;
653 };
654
655 // Check if two multi-segment lines have overlapping bboxes (worth doing segment evaluation)
656 auto linesBBoxOverlap = [&]() -> bool
657 {
658 if( !lineANeedsSegmentEval || !lineBNeedsSegmentEval )
659 return true;
660
661 const auto* lineA = static_cast<const PNS::LINE*>( aItemA );
662 const auto* lineB = static_cast<const PNS::LINE*>( aItemB );
663 const int proximityThreshold = std::max( lineA->Width(), lineB->Width() ) * 2;
664
665 BOX2I bboxA = lineA->CLine().BBox();
666 bboxA.Inflate( proximityThreshold );
667
668 return bboxA.Intersects( lineB->CLine().BBox() );
669 };
670
671 // Handle multi-segment lines with segment-by-segment evaluation.
672 if( ( lineANeedsSegmentEval || lineBNeedsSegmentEval ) && linesBBoxOverlap() )
673 {
674 // Get dummy items for non-multi-segment items that need them
675 if( aItemA && !parentA && !lineANeedsSegmentEval )
676 parentA = getBoardItem( aItemA, board_layer, 0 );
677
678 if( aItemB && !parentB && !lineBNeedsSegmentEval )
679 parentB = getBoardItem( aItemB, board_layer, 1 );
680
681 if( lineANeedsSegmentEval && lineBNeedsSegmentEval )
682 {
683 // Both items are multi-segment lines. Evaluate segment pairs, skipping pairs
684 // that are far apart since geometry-dependent rules won't trigger for them.
685 const auto* lineA = static_cast<const PNS::LINE*>( aItemA );
686 const auto* lineB = static_cast<const PNS::LINE*>( aItemB );
687 const SHAPE_LINE_CHAIN& chainA = lineA->CLine();
688 const SHAPE_LINE_CHAIN& chainB = lineB->CLine();
689
690 const int proximityThreshold = std::max( lineA->Width(), lineB->Width() ) * 2;
691
692 PCB_TRACK& dummyA = m_dummyTracks[0];
693 dummyA.SetLayer( board_layer );
694 dummyA.SetNet( static_cast<NETINFO_ITEM*>( aItemA->Net() ) );
695 dummyA.SetWidth( lineA->Width() );
696
697 PCB_TRACK& dummyB = m_dummyTracks[1];
698 dummyB.SetLayer( board_layer );
699 dummyB.SetNet( static_cast<NETINFO_ITEM*>( aItemB->Net() ) );
700 dummyB.SetWidth( lineB->Width() );
701
702 bool done = false;
703 BOX2I bboxA, bboxB;
704
705 for( int i = 0; i < chainA.SegmentCount() && !done; i++ )
706 {
707 const VECTOR2I& ptA1 = chainA.CPoint( i );
708 const VECTOR2I& ptA2 = chainA.CPoint( i + 1 );
709
710 bboxA.SetOrigin( ptA1 );
711 bboxA.SetEnd( ptA2 );
712 bboxA.Normalize();
713 bboxA.Inflate( proximityThreshold );
714
715 dummyA.SetStart( ptA1 );
716 dummyA.SetEnd( ptA2 );
717
718 for( int j = 0; j < chainB.SegmentCount(); j++ )
719 {
720 const VECTOR2I& ptB1 = chainB.CPoint( j );
721 const VECTOR2I& ptB2 = chainB.CPoint( j + 1 );
722
723 bboxB.SetOrigin( ptB1 );
724 bboxB.SetEnd( ptB2 );
725 bboxB.Normalize();
726
727 if( !bboxA.Intersects( bboxB ) )
728 continue;
729
730 dummyB.SetStart( ptB1 );
731 dummyB.SetEnd( ptB2 );
732
733 DRC_CONSTRAINT segConstraint =
734 drcEngine->EvalRules( hostType, &dummyA, &dummyB, board_layer );
735
736 if( pickSmallerConstraint( hostConstraint, segConstraint ) )
737 {
738 done = true;
739 break;
740 }
741 }
742 }
743 }
744 else if( lineANeedsSegmentEval )
745 {
746 hostConstraint = evaluateLineSegments( aItemA, parentB, true, 0 );
747 }
748 else
749 {
750 hostConstraint = evaluateLineSegments( aItemB, parentA, false, 1 );
751 }
752 }
753 else
754 {
755 // Standard path: no multi-segment lines (or lines too far apart), use anchor-based dummies
756 if( aItemA && !parentA )
757 parentA = getBoardItem( aItemA, board_layer, 0 );
758
759 if( aItemB && !parentB )
760 parentB = getBoardItem( aItemB, board_layer, 1 );
761
762 if( parentA )
763 hostConstraint = drcEngine->EvalRules( hostType, parentA, parentB, board_layer );
764 }
765
766 if( hostConstraint.IsNull() )
767 return false;
768
769 if( hostConstraint.GetSeverity() == RPT_SEVERITY_IGNORE
770 && ( !hostConstraint.GetParentRule()->IsImplicit()
772 {
773 aConstraint->m_Value.SetMin( -1 );
774 aConstraint->m_RuleName = hostConstraint.GetName();
775 aConstraint->m_Type = aType;
776 return true;
777 }
778
779 switch ( aType )
780 {
794 aConstraint->m_Value = hostConstraint.GetValue();
795 aConstraint->m_RuleName = hostConstraint.GetName();
796 aConstraint->m_Type = aType;
797 aConstraint->m_IsTimeDomain = hostConstraint.GetOption( DRC_CONSTRAINT::OPTIONS::TIME_DOMAIN );
798 return true;
799
800 default:
801 return false;
802 }
803}
804
805
806void PNS_PCBNEW_RULE_RESOLVER::ClearCacheForItems( std::vector<const PNS::ITEM*>& aItems )
807{
808 if( aItems.empty() )
809 return;
810
811 std::unordered_set<const PNS::ITEM*> dirtyItems( aItems.begin(), aItems.end() );
812
813 std::erase_if( m_clearanceCache,
814 [&dirtyItems]( const auto& entry )
815 {
816 return dirtyItems.contains( entry.first.A ) || dirtyItems.contains( entry.first.B );
817 } );
818
819 std::erase_if( m_hullCache,
820 [&dirtyItems]( const auto& entry )
821 {
822 return dirtyItems.contains( entry.first.item );
823 } );
824}
825
826
834
835
840
841
843 int aClearance,
844 int aWalkaroundThickness,
845 int aLayer )
846{
847 HULL_CACHE_KEY key = { aItem, aClearance, aWalkaroundThickness, aLayer };
848
849 auto it = m_hullCache.find( key );
850
851 if( it != m_hullCache.end() )
852 return it->second;
853
854 SHAPE_LINE_CHAIN hull = aItem->Hull( aClearance, aWalkaroundThickness, aLayer );
855 auto result = m_hullCache.emplace( key, std::move( hull ) );
856
857 return result.first->second;
858}
859
860
862{
863 if( !m_hasUserPhysicalConstraint.has_value() )
864 {
865 if( std::shared_ptr<DRC_ENGINE> drc = m_board->GetDesignSettings().m_DRCEngine )
866 m_hasUserPhysicalConstraint = drc->HasUserDefinedPhysicalConstraint();
867 else
869 }
870
872}
873
874
876 bool aUseClearanceEpsilon )
877{
878 const bool bothOwned = aA && aB && aA->Owner() && aB->Owner();
879
880 if( bothOwned )
881 {
882 // Search cache (used for actual board items)
883 auto it = m_clearanceCache.find( CLEARANCE_CACHE_KEY( aA, aB, aUseClearanceEpsilon ) );
884
885 if( it != m_clearanceCache.end() )
886 return it->second;
887 }
888 else if( aA && aB )
889 {
890 // Search cache (used for temporary items within an algorithm)
891 auto it = m_tempClearanceCache.find( TEMP_CLEARANCE_CACHE_KEY( aA, aB, aUseClearanceEpsilon ) );
892
893 if( it != m_tempClearanceCache.end() )
894 return it->second;
895 }
896
897 PNS::CONSTRAINT constraint;
898 int rv = 0;
899 PNS_LAYER_RANGE layers;
900
901 if( !aB )
902 layers = aA->Layers();
903 else if( isEdge( aA ) )
904 layers = aB->Layers();
905 else if( isEdge( aB ) )
906 layers = aA->Layers();
907 else
908 layers = aA->Layers().Intersection( aB->Layers() );
909
910 // Normalize layer range (no -1 magic numbers)
912
913 const bool sameNet = aA && aB && aA->Net() && aA->Net() == aB->Net();
914 const bool freePad = aA && aB && ( aA->IsFreePad() || aB->IsFreePad() );
915
916 for( int layer = layers.Start(); layer <= layers.End(); ++layer )
917 {
918 if( IsDrilledHole( aA ) && IsDrilledHole( aB ) )
919 {
920 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_HOLE_TO_HOLE, aA, aB, layer, &constraint ) )
921 {
922 if( constraint.m_Value.Min() > rv )
923 rv = constraint.m_Value.Min();
924 }
925 }
926 else if( isHole( aA ) || isHole( aB ) )
927 {
928 if( !sameNet )
929 {
930 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_HOLE_CLEARANCE, aA, aB, layer, &constraint ) )
931 {
932 if( constraint.m_Value.Min() > rv )
933 rv = constraint.m_Value.Min();
934 }
935 }
936 }
937
938 // No 'else'; plated holes get both HOLE_CLEARANCE and CLEARANCE
939 if( isCopper( aA ) && ( !aB || isCopper( aB ) ) && !sameNet && !freePad )
940 {
941 if( !sameNet && !freePad )
942 {
943 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_CLEARANCE, aA, aB, layer, &constraint ) )
944 {
945 if( constraint.m_Value.Min() > rv )
946 rv = constraint.m_Value.Min();
947 }
948 }
949 }
950
951 if( isEdge( aA ) || isEdge( aB ) )
952 {
953 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_EDGE_CLEARANCE, aA, aB, layer, &constraint ) )
954 {
955 if( constraint.m_Value.Min() > rv )
956 rv = constraint.m_Value.Min();
957 }
958 }
959
960 // Physical clearances are net-blind: a physical_clearance rule applies regardless
961 if( isHole( aA ) || isHole( aB ) )
962 {
963 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_PHYSICAL_HOLE_CLEARANCE, aA, aB, layer, &constraint ) )
964 {
965 if( constraint.m_Value.Min() > rv )
966 rv = constraint.m_Value.Min();
967 }
968 }
969
970 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_PHYSICAL_CLEARANCE, aA, aB, layer, &constraint ) )
971 {
972 if( constraint.m_Value.Min() > rv )
973 rv = constraint.m_Value.Min();
974 }
975 }
976
977 // Same-net pairs short-circuit clearance unless a physical_clearance rule gave a positive value
978 if( ( sameNet || freePad ) && rv == 0 )
979 rv = -1;
980
981 if( aUseClearanceEpsilon && rv > 0 )
982 rv = std::max( 0, rv - m_clearanceEpsilon );
983
984 // Remember this result so we don't recompute it. Real board items go in the long-lived
985 // cache. Temporary items the router creates while routing go in a separate cache we can
986 // clear on their own.
987 if( bothOwned )
988 m_clearanceCache[CLEARANCE_CACHE_KEY( aA, aB, aUseClearanceEpsilon )] = rv;
989 else if( aA && aB )
990 m_tempClearanceCache[TEMP_CLEARANCE_CACHE_KEY( aA, aB, aUseClearanceEpsilon )] = rv;
991
992 return rv;
993}
994
995
996bool PNS_KICAD_IFACE_BASE::inheritTrackWidthAndDpGap( PNS::ITEM* aItem, const VECTOR2I& aStartPosition, int* aInheritedWidth, int *aInheritedGap )
997{
998 VECTOR2I p;
999
1000 assert( aItem->Owner() != nullptr );
1001
1002 PNS::NET_HANDLE coupledNet = GetRuleResolver()->DpCoupledNet( aItem->Net() );
1003
1004 if( coupledNet && aInheritedGap )
1005 {
1006 PNS::TOPOLOGY topo( m_world );
1007 PNS::DIFF_PAIR dp;
1008 if( topo.AssembleDiffPair( static_cast<PNS::SEGMENT*>( aItem ), dp ) )
1009 {
1010 *aInheritedGap = dp.GuessMostLikelyGap();
1011 }
1012 else
1013 {
1014 return false;
1015 }
1016 }
1017
1018 auto tryGetTrackWidth =
1019 []( PNS::ITEM* aPnsItem ) -> int
1020 {
1021 switch( aPnsItem->Kind() )
1022 {
1023 case PNS::ITEM::SEGMENT_T: return static_cast<PNS::SEGMENT*>( aPnsItem )->Width();
1024 case PNS::ITEM::ARC_T: return static_cast<PNS::ARC*>( aPnsItem )->Width();
1025 default: return -1;
1026 }
1027 };
1028
1029 int itemTrackWidth = tryGetTrackWidth( aItem );
1030
1031 if( itemTrackWidth > 0 )
1032 {
1033 *aInheritedWidth = itemTrackWidth;
1034 return true;
1035 }
1036
1037 switch( aItem->Kind() )
1038 {
1039 case PNS::ITEM::VIA_T: p = static_cast<PNS::VIA*>( aItem )->Pos(); break;
1040 case PNS::ITEM::SOLID_T: p = static_cast<PNS::SOLID*>( aItem )->Pos(); break;
1041 default: return false;
1042 }
1043
1044 const PNS::JOINT* jt = static_cast<const PNS::NODE*>( aItem->Owner() )->FindJoint( p, aItem );
1045
1046 assert( jt != nullptr );
1047
1048 PNS::ITEM_SET linkedSegs( jt->CLinks() );
1050
1051 if( linkedSegs.Empty() )
1052 return false;
1053
1054 // When a start position is provided, find the connected track whose far end is closest to
1055 // the cursor. Since all tracks share the pad/via endpoint, the far-end direction is a proxy
1056 // for which exit stub the user is pointing at.
1057 if( aStartPosition != VECTOR2I() )
1058 {
1059 PNS::ITEM* closestItem = nullptr;
1061
1062 for( PNS::ITEM* item : linkedSegs.Items() )
1063 {
1064 if( item->Layer() != m_startLayer )
1065 continue;
1066
1067 PNS::LINKED_ITEM* li = static_cast<PNS::LINKED_ITEM*>( item );
1068
1069 VECTOR2I anchor0 = li->Anchor( 0 );
1070 VECTOR2I anchor1 = li->Anchor( 1 );
1071
1072 // The "other end" is the anchor farther from the pad/via center
1073 VECTOR2I otherEnd = ( anchor0 - p ).SquaredEuclideanNorm() > ( anchor1 - p ).SquaredEuclideanNorm()
1074 ? anchor0
1075 : anchor1;
1076
1077 SEG::ecoord dist = ( otherEnd - aStartPosition ).SquaredEuclideanNorm();
1078
1079 if( dist < minDist )
1080 {
1081 minDist = dist;
1082 closestItem = item;
1083 }
1084 }
1085
1086 if( closestItem )
1087 {
1088 int w = tryGetTrackWidth( closestItem );
1089
1090 if( w > 0 )
1091 {
1092 *aInheritedWidth = w;
1093 return true;
1094 }
1095 }
1096 }
1097
1098 // Fallback to minimum width when no start position provided or no valid exit stub found
1099 int min_current_layer = INT_MAX;
1100 int min_all_layers = INT_MAX;
1101
1102 for( PNS::ITEM* item : linkedSegs.Items() )
1103 {
1104 int w = tryGetTrackWidth( item );
1105
1106 if( w > 0 )
1107 {
1108 min_all_layers = std::min( w, min_all_layers );
1109
1110 if( item->Layer() == m_startLayer )
1111 min_current_layer = std::min( w, min_current_layer );
1112 }
1113 }
1114
1115 if( min_all_layers == INT_MAX )
1116 return false;
1117
1118 if( min_current_layer < INT_MAX )
1119 *aInheritedWidth = min_current_layer;
1120 else
1121 *aInheritedWidth = min_all_layers;
1122
1123 return true;
1124}
1125
1126
1128 PNS::NET_HANDLE aNet, VECTOR2D aStartPosition )
1129{
1130 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
1131 PNS::CONSTRAINT constraint;
1132
1133 if( aStartItem && m_startLayer < 0 )
1134 m_startLayer = aStartItem->Layer();
1135
1136 aSizes.SetClearance( bds.m_MinClearance );
1137 aSizes.SetMinClearance( bds.m_MinClearance );
1138 aSizes.SetClearanceSource( _( "board minimum clearance" ) );
1139
1140 int startAnchor = 0;
1141 VECTOR2I startPosInt( aStartPosition.x, aStartPosition.y );
1142
1143 if( aStartItem && aStartItem->Kind() == PNS::ITEM::SEGMENT_T )
1144 {
1145 // Find the start anchor which is closest to the start mouse location
1146 double anchor0Distance = startPosInt.Distance( aStartItem->Anchor( 0 ) );
1147 double anchor1Distance = startPosInt.Distance( aStartItem->Anchor( 1 ) );
1148
1149 if( anchor1Distance < anchor0Distance )
1150 startAnchor = 1;
1151 }
1152
1153 if( aStartItem )
1154 {
1155 PNS::SEGMENT dummyTrack;
1156 dummyTrack.SetEnds( aStartItem->Anchor( startAnchor ), aStartItem->Anchor( startAnchor ) );
1157 dummyTrack.SetLayer( m_startLayer );
1158 dummyTrack.SetNet( static_cast<NETINFO_ITEM*>( aStartItem->Net() ) );
1159
1160 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_CLEARANCE, &dummyTrack,
1161 nullptr, m_startLayer, &constraint ) )
1162 {
1163 if( constraint.m_Value.Min() >= bds.m_MinClearance )
1164 {
1165 aSizes.SetClearance( constraint.m_Value.Min() );
1166 aSizes.SetClearanceSource( constraint.m_RuleName );
1167 }
1168 }
1169 }
1170
1171 int trackWidth = bds.m_TrackMinWidth;
1172 bool found = false;
1173 aSizes.SetWidthSource( _( "board minimum track width" ) );
1174
1175 if( bds.m_UseConnectedTrackWidth && !bds.m_TempOverrideTrackWidth && aStartItem != nullptr )
1176 {
1177 found = inheritTrackWidthAndDpGap( aStartItem, aStartPosition, &trackWidth, nullptr );
1178
1179 if( found )
1180 aSizes.SetWidthSource( _( "existing track" ) );
1181 }
1182
1183 if( !found && bds.UseNetClassTrack() && aStartItem )
1184 {
1185 PNS::SEGMENT dummyTrack;
1186 dummyTrack.SetEnds( aStartItem->Anchor( startAnchor ), aStartItem->Anchor( startAnchor ) );
1187 dummyTrack.SetLayer( m_startLayer );
1188 dummyTrack.SetNet( static_cast<NETINFO_ITEM*>( aStartItem->Net() ) );
1189
1190 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_WIDTH, &dummyTrack, nullptr,
1191 m_startLayer, &constraint ) )
1192 {
1193 trackWidth = std::max( trackWidth, constraint.m_Value.PinnedOpt() );
1194 found = true;
1195
1196 if( trackWidth == constraint.m_Value.Opt() )
1197 aSizes.SetWidthSource( constraint.m_RuleName );
1198 }
1199 }
1200
1201 if( !found )
1202 {
1203 trackWidth = std::max( trackWidth, bds.GetCurrentTrackWidth() );
1204
1205 if( bds.UseNetClassTrack() )
1206 aSizes.SetWidthSource( _( "netclass 'Default'" ) );
1207 else if( trackWidth == bds.GetCurrentTrackWidth() )
1208 aSizes.SetWidthSource( _( "user choice" ) );
1209 }
1210
1211 aSizes.SetTrackWidth( trackWidth );
1214
1215 int viaDiameter = bds.m_ViasMinSize;
1216 int viaDrill = bds.m_MinThroughDrill;
1217
1218 PNS::VIA dummyVia, coupledVia;
1219
1220 if( aStartItem )
1221 {
1222 dummyVia.SetNet( aStartItem->Net() );
1223 coupledVia.SetNet( m_ruleResolver->DpCoupledNet( aStartItem->Net() ) );
1224 }
1225
1226 if( bds.UseNetClassVia() && aStartItem ) // netclass value
1227 {
1228 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_VIA_DIAMETER, &dummyVia,
1229 nullptr, m_startLayer, &constraint ) )
1230 {
1231 viaDiameter = std::max( viaDiameter, constraint.m_Value.PinnedOpt() );
1232 }
1233
1234 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_VIA_HOLE, &dummyVia,
1235 nullptr, m_startLayer, &constraint ) )
1236 {
1237 viaDrill = std::max( viaDrill, constraint.m_Value.PinnedOpt() );
1238 }
1239 }
1240 else
1241 {
1242 viaDiameter = bds.GetCurrentViaSize();
1243 viaDrill = bds.GetCurrentViaDrill();
1244 }
1245
1246 aSizes.SetViaDiameter( viaDiameter );
1247 aSizes.SetViaDrill( viaDrill );
1248
1249 int diffPairWidth = bds.m_TrackMinWidth;
1250 int diffPairGap = bds.m_MinClearance;
1251 int diffPairViaGap = bds.m_MinClearance;
1252
1253 aSizes.SetDiffPairWidthSource( _( "board minimum track width" ) );
1254 aSizes.SetDiffPairGapSource( _( "board minimum clearance" ) );
1255
1256 found = false;
1257
1258 // First try to pick up diff pair width from starting track, if enabled
1259 if( bds.m_UseConnectedTrackWidth && aStartItem )
1260 found = inheritTrackWidthAndDpGap( aStartItem, aStartPosition, &diffPairWidth, &diffPairGap );
1261
1262 // Next, pick up gap from netclass, and width also if we didn't get a starting width above
1263 if( bds.UseNetClassDiffPair() && aStartItem )
1264 {
1265 PNS::NET_HANDLE coupledNet = m_ruleResolver->DpCoupledNet( aStartItem->Net() );
1266
1267 PNS::SEGMENT dummyTrack;
1268 dummyTrack.SetEnds( aStartItem->Anchor( 0 ), aStartItem->Anchor( 0 ) );
1269 dummyTrack.SetLayer( m_startLayer );
1270 dummyTrack.SetNet( static_cast<NETINFO_ITEM*>( aStartItem->Net() ) );
1271
1272 PNS::SEGMENT coupledTrack;
1273 coupledTrack.SetEnds( aStartItem->Anchor( 0 ), aStartItem->Anchor( 0 ) );
1274 coupledTrack.SetLayer( m_startLayer );
1275 coupledTrack.SetNet( static_cast<NETINFO_ITEM*>( coupledNet ) );
1276
1277 if( !found
1278 && m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_WIDTH, &dummyTrack,
1279 &coupledTrack, m_startLayer, &constraint ) )
1280 {
1281 diffPairWidth = std::max( diffPairWidth, constraint.m_Value.Opt() );
1282
1283 if( diffPairWidth == constraint.m_Value.Opt() )
1284 aSizes.SetDiffPairWidthSource( constraint.m_RuleName );
1285 }
1286
1287 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_DIFF_PAIR_GAP, &dummyTrack,
1288 &coupledTrack, m_startLayer, &constraint ) )
1289 {
1290 diffPairGap = std::max( diffPairGap, constraint.m_Value.PinnedOpt() );
1291 diffPairViaGap = std::max( diffPairViaGap, constraint.m_Value.PinnedOpt() );
1292
1293 if( diffPairGap == constraint.m_Value.Opt() )
1294 aSizes.SetDiffPairGapSource( constraint.m_RuleName );
1295 }
1296 }
1297 else
1298 {
1299 diffPairWidth = bds.GetCurrentDiffPairWidth();
1300 diffPairGap = bds.GetCurrentDiffPairGap();
1301 diffPairViaGap = bds.GetCurrentDiffPairViaGap();
1302
1303 aSizes.SetDiffPairWidthSource( _( "user choice" ) );
1304 aSizes.SetDiffPairGapSource( _( "user choice" ) );
1305 }
1306
1307 aSizes.SetDiffPairWidth( diffPairWidth );
1308 aSizes.SetDiffPairGap( diffPairGap );
1309 aSizes.SetDiffPairViaGap( diffPairViaGap );
1310 aSizes.SetDiffPairViaGapSameAsTraceGap( false );
1311
1312 int holeToHoleMin = bds.m_HoleToHoleMin;
1313
1314 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_HOLE_TO_HOLE, &dummyVia,
1315 &dummyVia, UNDEFINED_LAYER, &constraint ) )
1316 {
1317 holeToHoleMin = constraint.m_Value.Min();
1318 }
1319
1320 aSizes.SetHoleToHole( holeToHoleMin );
1321
1322 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_HOLE_TO_HOLE, &dummyVia,
1323 &coupledVia, UNDEFINED_LAYER, &constraint ) )
1324 {
1325 holeToHoleMin = constraint.m_Value.Min();
1326 }
1327
1328 aSizes.SetDiffPairHoleToHole( std::max( holeToHoleMin, aSizes.GetHoleToHole() ) );
1329
1330 // Seed with the board hole-to-copper minimum so a null DRC engine still constrains the gap,
1331 // matching how the hole-to-hole block above falls back to bds.m_HoleToHoleMin.
1332 int copperToHole = bds.m_HoleClearance;
1333
1334 // A net-scoped rule may bind the two vias asymmetrically, so query both orderings the way
1335 // the DRC copper-clearance provider tests each hole in turn.
1338 {
1339 if( m_ruleResolver->QueryConstraint( type, &dummyVia, &coupledVia, UNDEFINED_LAYER,
1340 &constraint ) )
1341 {
1342 copperToHole = std::max( copperToHole, constraint.m_Value.Min() );
1343 }
1344
1345 if( m_ruleResolver->QueryConstraint( type, &coupledVia, &dummyVia, UNDEFINED_LAYER,
1346 &constraint ) )
1347 {
1348 copperToHole = std::max( copperToHole, constraint.m_Value.Min() );
1349 }
1350 }
1351
1352 aSizes.SetDiffPairCopperToHole( copperToHole );
1353
1354 return true;
1355}
1356
1357
1358int PNS_KICAD_IFACE_BASE::StackupHeight( int aFirstLayer, int aSecondLayer ) const
1359{
1360 if( !m_board || !m_board->GetDesignSettings().m_UseHeightForLengthCalcs )
1361 return 0;
1362
1363 BOARD_STACKUP& stackup = m_board->GetDesignSettings().GetStackupDescriptor();
1364
1365 return stackup.GetLayerDistance( GetBoardLayerFromPNSLayer( aFirstLayer ),
1366 GetBoardLayerFromPNSLayer( aSecondLayer ) );
1367}
1368
1369
1371{
1372 return m_board->DpCoupledNet( static_cast<NETINFO_ITEM*>( aNet ) );
1373}
1374
1375
1377{
1378 return m_routerIface->GetNetCode( aNet );
1379}
1380
1381
1383{
1384 return m_routerIface->GetNetName( aNet );
1385}
1386
1387
1389{
1390 wxString refName;
1391
1392 if( NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aNet ) )
1393 refName = net->GetNetname();
1394
1395 wxString dummy1;
1396
1397 return m_board->MatchDpSuffix( refName, dummy1 );
1398}
1399
1400
1402 PNS::NET_HANDLE& aNetN )
1403{
1404 if( !aItem || !aItem->Net() )
1405 return false;
1406
1407 wxString netNameP = static_cast<NETINFO_ITEM*>( aItem->Net() )->GetNetname();
1408 wxString netNameN, netNameCoupled;
1409
1410 int r = m_board->MatchDpSuffix( netNameP, netNameCoupled );
1411
1412 if( r == 0 )
1413 {
1414 return false;
1415 }
1416 else if( r == 1 )
1417 {
1418 netNameN = netNameCoupled;
1419 }
1420 else
1421 {
1422 netNameN = netNameP;
1423 netNameP = netNameCoupled;
1424 }
1425
1426 PNS::NET_HANDLE netInfoP = m_board->FindNet( netNameP );
1427 PNS::NET_HANDLE netInfoN = m_board->FindNet( netNameN );
1428
1429 if( !netInfoP || !netInfoN )
1430 return false;
1431
1432 aNetP = netInfoP;
1433 aNetN = netInfoN;
1434
1435 return true;
1436}
1437
1438
1440{
1441public:
1444 m_iface( aIface ),
1445 m_view( nullptr ),
1446 m_items( nullptr ),
1447 m_depth( 0 )
1448 {}
1449
1451 {
1453
1454 for ( PNS::ITEM* item : m_clonedItems )
1455 {
1456 delete item;
1457 }
1458
1459 delete m_items;
1460 }
1461
1462 void SetView( KIGFX::VIEW* aView )
1463 {
1464 Clear();
1465 delete m_items;
1466 m_items = nullptr;
1467 m_view = aView;
1468
1469 if( m_view == nullptr )
1470 return;
1471
1472 if( m_view->GetGAL() )
1473 m_depth = m_view->GetGAL()->GetMinDepth();
1474
1476 m_items->SetLayer( LAYER_SELECT_OVERLAY ) ;
1477 m_view->Add( m_items );
1478 }
1479
1480 void AddPoint( const VECTOR2I& aP, const KIGFX::COLOR4D& aColor, int aSize, const wxString& aName = wxT( "" ),
1481 const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override
1482
1483 {
1485
1486 sh.SetWidth( 10000 );
1487
1488 sh.Append( aP.x - aSize, aP.y - aSize );
1489 sh.Append( aP.x + aSize, aP.y + aSize );
1490 sh.Append( aP.x, aP.y );
1491 sh.Append( aP.x - aSize, aP.y + aSize );
1492 sh.Append( aP.x + aSize, aP.y - aSize );
1493
1494 AddShape( &sh, aColor, sh.Width(), aName, aSrcLoc );
1495 }
1496
1497 void AddItem( const PNS::ITEM* aItem, const KIGFX::COLOR4D& aColor, int aOverrideWidth = 0,
1498 const wxString& aName = wxT( "" ),
1499 const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override
1500 {
1501 if( !m_view || !aItem )
1502 return;
1503
1504 PNS::ITEM* cloned = aItem->Clone();
1505
1506 if( auto line = dyn_cast<PNS::LINE*>( cloned ))
1507 {
1508 line->ClearLinks();
1509 }
1510
1511 m_clonedItems.push_back( cloned );
1512
1513 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( cloned, m_iface, m_view );
1514
1515 pitem->SetColor( aColor.WithAlpha( 0.5 ) );
1516 pitem->SetWidth( aOverrideWidth );
1517 pitem->SetDepth( nextDepth() );
1518
1519 m_items->Add( pitem );
1520 m_view->Update( m_items );
1521 }
1522
1523 void AddShape( const BOX2I& aBox, const KIGFX::COLOR4D& aColor, int aOverrideWidth = 0,
1524 const wxString& aName = wxT( "" ),
1525 const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override
1526 {
1528 l.SetWidth( aOverrideWidth );
1529
1530 VECTOR2I o = aBox.GetOrigin();
1531 VECTOR2I s = aBox.GetSize();
1532
1533 l.Append( o );
1534 l.Append( o.x + s.x, o.y );
1535 l.Append( o.x + s.x, o.y + s.y );
1536 l.Append( o.x, o.y + s.y );
1537 l.Append( o );
1538
1539 AddShape( &l, aColor, aOverrideWidth, aName, aSrcLoc );
1540 }
1541
1542 void AddShape( const SHAPE* aShape, const KIGFX::COLOR4D& aColor, int aOverrideWidth = 0,
1543 const wxString& aName = wxT( "" ),
1544 const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override
1545 {
1546 if( !m_view || !aShape )
1547 return;
1548
1549 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( *aShape, m_iface, m_view );
1550
1551 pitem->SetColor( aColor.WithAlpha( 0.5 ) );
1552 pitem->SetWidth( aOverrideWidth );
1553 pitem->SetDepth( nextDepth() );
1554
1555 m_items->Add( pitem );
1556 m_view->Update( m_items );
1557 }
1558
1559 void Clear() override
1560 {
1561 if( m_view && m_items )
1562 {
1563 m_items->FreeItems();
1564 m_view->Update( m_items );
1565
1566 if( m_view->GetGAL() )
1567 m_depth = m_view->GetGAL()->GetMinDepth();
1568 }
1569
1570 for( PNS::ITEM* item : m_clonedItems )
1571 delete item;
1572
1573 m_clonedItems.clear();
1574 }
1575
1576 virtual void Message( const wxString& msg, const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override
1577 {
1578 }
1579
1580private:
1581 double nextDepth()
1582 {
1583 // Use different depths so that the transculent shapes won't overwrite each other.
1584
1585 m_depth++;
1586
1587 if( m_depth >= 0 && m_view->GetGAL() )
1588 m_depth = m_view->GetGAL()->GetMinDepth();
1589
1590 return m_depth;
1591 }
1592
1596 std::vector<PNS::ITEM*> m_clonedItems;
1597
1598 double m_depth;
1599};
1600
1601
1606
1607
1609{
1610 m_ruleResolver = nullptr;
1611 m_board = nullptr;
1612 m_world = nullptr;
1613 m_debugDecorator = nullptr;
1614 m_startLayer = -1;
1615}
1616
1617
1619{
1620 m_tool = nullptr;
1621 m_view = nullptr;
1622 m_previewItems = nullptr;
1623 m_commitFlags = 0;
1624}
1625
1626
1632
1633
1635{
1636 if( m_previewItems )
1637 {
1638 m_previewItems->FreeItems();
1639 delete m_previewItems;
1640 }
1641}
1642
1643
1644std::vector<std::unique_ptr<PNS::SOLID>> PNS_KICAD_IFACE_BASE::syncPad( PAD* aPad )
1645{
1646 std::vector<std::unique_ptr<PNS::SOLID>> solids;
1647 PNS_LAYER_RANGE layers( 0, aPad->BoardCopperLayerCount() - 1 );
1648 LSEQ lmsk = aPad->GetLayerSet().CuStack();
1649
1650 // ignore non-copper pads except for those with holes
1651 if( lmsk.empty() && aPad->GetDrillSize().x == 0 )
1652 return solids;
1653
1654 switch( aPad->GetAttribute() )
1655 {
1656 case PAD_ATTRIB::PTH:
1657 case PAD_ATTRIB::NPTH:
1658 break;
1659
1660 case PAD_ATTRIB::CONN:
1661 case PAD_ATTRIB::SMD:
1662 {
1663 bool is_copper = false;
1664
1665 if( !lmsk.empty() && aPad->GetAttribute() != PAD_ATTRIB::NPTH )
1666 {
1667 layers = SetLayersFromPCBNew( lmsk.front(), lmsk.front() );
1668 is_copper = true;
1669 }
1670
1671 if( !is_copper )
1672 return solids;
1673
1674 break;
1675 }
1676
1677 default:
1678 wxLogTrace( wxT( "PNS" ), wxT( "unsupported pad type 0x%x" ), aPad->GetAttribute() );
1679 return solids;
1680 }
1681
1682 auto makeSolidFromPadLayer =
1683 [&]( PCB_LAYER_ID aLayer )
1684 {
1685 // For FRONT_INNER_BACK mode, skip creating a SOLID for inner layers when there are
1686 // no inner layers (2-layer board). Otherwise PNS_LAYER_RANGE(1, 0) would be swapped
1687 // to (0, 1) and indexed on both F_Cu and B_Cu, causing incorrect collision checks.
1689 && aLayer != F_Cu && aLayer != B_Cu
1690 && aPad->BoardCopperLayerCount() <= 2 )
1691 {
1692 return;
1693 }
1694
1695 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
1696
1697 if( aPad->GetAttribute() == PAD_ATTRIB::NPTH )
1698 solid->SetRoutable( false );
1699
1700 if( aPad->Padstack().Mode() == PADSTACK::MODE::CUSTOM )
1701 {
1702 solid->SetLayer( GetPNSLayerFromBoardLayer( aLayer ) );
1703 }
1704 else if( aPad->Padstack().Mode() == PADSTACK::MODE::FRONT_INNER_BACK )
1705 {
1706 if( aLayer == F_Cu || aLayer == B_Cu )
1707 solid->SetLayer( GetPNSLayerFromBoardLayer( aLayer ) );
1708 else
1709 solid->SetLayers( PNS_LAYER_RANGE( 1, aPad->BoardCopperLayerCount() - 2 ) );
1710 }
1711 else
1712 {
1713 solid->SetLayers( layers );
1714 }
1715
1716 solid->SetNet( aPad->GetNet() );
1717 solid->SetParent( aPad );
1718 solid->SetPadToDie( aPad->GetPadToDieLength() );
1719 solid->SetPadToDieDelay( aPad->GetPadToDieDelay() );
1720 solid->SetOrientation( aPad->GetOrientation() );
1721
1722 if( aPad->IsFreePad() )
1723 solid->SetIsFreePad();
1724
1725 VECTOR2I wx_c = aPad->ShapePos( aLayer );
1726 VECTOR2I offset = aPad->GetOffset( aLayer );
1727
1728 VECTOR2I c( wx_c.x, wx_c.y );
1729
1730 RotatePoint( offset, aPad->GetOrientation() );
1731
1732 solid->SetPos( VECTOR2I( c.x - offset.x, c.y - offset.y ) );
1733 solid->SetOffset( VECTOR2I( offset.x, offset.y ) );
1734
1735 if( aPad->GetDrillSize().x > 0 )
1736 {
1737 solid->SetHole( new PNS::HOLE( aPad->GetEffectiveHoleShape()->Clone() ) );
1738 solid->Hole()->SetLayers( PNS_LAYER_RANGE( 0, aPad->BoardCopperLayerCount() - 1 ) );
1739 }
1740
1741 // We generate a single SOLID for a pad, so we have to treat it as ALWAYS_FLASHED and
1742 // then perform layer-specific flashing tests internally.
1743 const std::shared_ptr<SHAPE>& shape = aPad->GetEffectiveShape( aLayer, FLASHING::ALWAYS_FLASHED );
1744
1745 if( shape->HasIndexableSubshapes() && shape->GetIndexableSubshapeCount() == 1 )
1746 {
1747 std::vector<const SHAPE*> subshapes;
1748 shape->GetIndexableSubshapes( subshapes );
1749
1750 solid->SetShape( subshapes[0]->Clone() );
1751 }
1752 // For anything that's not a single shape we use a polygon. Multiple shapes have a tendency
1753 // to confuse the hull generator. https://gitlab.com/kicad/code/kicad/-/issues/15553
1754 else
1755 {
1756 const std::shared_ptr<SHAPE_POLY_SET>& poly = aPad->GetEffectivePolygon( aLayer, ERROR_OUTSIDE );
1757
1758 if( poly->OutlineCount() )
1759 solid->SetShape( new SHAPE_SIMPLE( poly->Outline( 0 ) ) );
1760 }
1761
1762 if( !solid->Shape( 0 ) )
1763 return;
1764
1765 solids.emplace_back( std::move( solid ) );
1766 };
1767
1768 aPad->Padstack().ForEachUniqueLayer( makeSolidFromPadLayer );
1769
1770 return solids;
1771}
1772
1773
1774std::unique_ptr<PNS::SEGMENT> PNS_KICAD_IFACE_BASE::syncTrack( PCB_TRACK* aTrack )
1775{
1776 auto segment = std::make_unique<PNS::SEGMENT>( SEG( aTrack->GetStart(), aTrack->GetEnd() ), aTrack->GetNet() );
1777
1778 segment->SetWidth( aTrack->GetWidth() );
1779 segment->SetLayer( GetPNSLayerFromBoardLayer( aTrack->GetLayer() ) );
1780 segment->SetParent( aTrack );
1781
1782 if( aTrack->IsLocked() )
1783 segment->Mark( PNS::MK_LOCKED );
1784
1785 if( PCB_GENERATOR* generator = dynamic_cast<PCB_GENERATOR*>( aTrack->GetParentGroup() ) )
1786 {
1787 if( !generator->HasFlag( IN_EDIT ) )
1788 segment->Mark( PNS::MK_LOCKED );
1789 }
1790
1791 return segment;
1792}
1793
1794
1795std::unique_ptr<PNS::ARC> PNS_KICAD_IFACE_BASE::syncArc( PCB_ARC* aArc )
1796{
1797 auto arc = std::make_unique<PNS::ARC>( SHAPE_ARC( aArc->GetStart(), aArc->GetMid(),
1798 aArc->GetEnd(), aArc->GetWidth() ),
1799 aArc->GetNet() );
1800
1801 arc->SetLayer( GetPNSLayerFromBoardLayer( aArc->GetLayer() ) );
1802 arc->SetParent( aArc );
1803
1804 if( aArc->IsLocked() )
1805 arc->Mark( PNS::MK_LOCKED );
1806
1807 if( PCB_GENERATOR* generator = dynamic_cast<PCB_GENERATOR*>( aArc->GetParentGroup() ) )
1808 {
1809 if( !generator->HasFlag( IN_EDIT ) )
1810 arc->Mark( PNS::MK_LOCKED );
1811 }
1812
1813 return arc;
1814}
1815
1816
1817std::unique_ptr<PNS::VIA> PNS_KICAD_IFACE_BASE::syncVia( PCB_VIA* aVia )
1818{
1819 PCB_LAYER_ID top, bottom;
1820 aVia->LayerPair( &top, &bottom );
1821
1822 /*
1823 * NOTE about PNS via padstacks:
1824 *
1825 * PNS::VIA has no knowledge about how many layers are in the board, and there is no fixed
1826 * reference to the "back layer" in the PNS. That means that there is no way for a VIA to know
1827 * the difference between its bottom layer and the bottom layer of the overall board (i.e. if
1828 * the via is a blind/buried via). For this reason, PNS::VIA::STACK_MODE::FRONT_INNER_BACK
1829 * cannot be used for blind/buried vias. This mode will always assume that the via's top layer
1830 * is the "front" layer and the via's bottom layer is the "back" layer, but from KiCad's point
1831 * of view, at least at the moment, front/inner/back padstack mode is board-scoped, not
1832 * via-scoped, so a buried via would only use the inner layer size even if its padstack mode is
1833 * set to PADSTACK::MODE::FRONT_INNER_BACK and different sizes are defined for front or back.
1834 * For this kind of via, the PNS VIA stack mode will be set to NORMAL because effectively it has
1835 * the same size on every layer it exists on.
1836 */
1837
1838 auto via = std::make_unique<PNS::VIA>( aVia->GetPosition(),
1839 SetLayersFromPCBNew( aVia->TopLayer(), aVia->BottomLayer() ),
1840 0,
1841 aVia->GetDrillValue(),
1842 aVia->GetNet(),
1843 aVia->GetViaType() );
1844 via->SetUnconnectedLayerMode( aVia->Padstack().UnconnectedLayerMode() );
1845
1846 auto syncDiameter =
1847 [&]( PCB_LAYER_ID aLayer )
1848 {
1849 via->SetDiameter( GetPNSLayerFromBoardLayer( aLayer ), aVia->GetWidth( aLayer ) );
1850 };
1851
1852 switch( aVia->Padstack().Mode() )
1853 {
1855 via->SetDiameter( 0, aVia->GetWidth( PADSTACK::TEMP_ALL_LAYERS ) );
1856 break;
1857
1859 if( aVia->GetViaType() == VIATYPE::BLIND || aVia->GetViaType() == VIATYPE::BURIED )
1860 {
1861 via->SetDiameter( 0, aVia->GetWidth( PADSTACK::INNER_LAYERS ) );
1862 }
1863 else
1864 {
1866 aVia->Padstack().ForEachUniqueLayer( syncDiameter );
1867 }
1868
1869 break;
1870
1872 via->SetStackMode( PNS::VIA::STACK_MODE::CUSTOM );
1873 aVia->Padstack().ForEachUniqueLayer( syncDiameter );
1874 }
1875
1876 via->SetParent( aVia );
1877
1878 if( aVia->IsLocked() )
1879 via->Mark( PNS::MK_LOCKED );
1880
1881 if( PCB_GENERATOR* generator = dynamic_cast<PCB_GENERATOR*>( aVia->GetParentGroup() ) )
1882 {
1883 if( !generator->HasFlag( IN_EDIT ) )
1884 via->Mark( PNS::MK_LOCKED );
1885 }
1886
1887 via->SetIsFree( aVia->GetIsFree() );
1888 via->SetHole( PNS::HOLE::MakeCircularHole( aVia->GetPosition(),
1889 aVia->GetDrillValue() / 2,
1890 SetLayersFromPCBNew( aVia->TopLayer(), aVia->BottomLayer() ) ) );
1891
1892 PCB_LAYER_ID primaryStart = aVia->GetPrimaryDrillStartLayer();
1893 PCB_LAYER_ID primaryEnd = aVia->GetPrimaryDrillEndLayer();
1894
1895 if( primaryStart != UNDEFINED_LAYER && primaryEnd != UNDEFINED_LAYER )
1896 via->SetHoleLayers( SetLayersFromPCBNew( primaryStart, primaryEnd ) );
1897 else
1898 via->SetHoleLayers( SetLayersFromPCBNew( aVia->TopLayer(), aVia->BottomLayer() ) );
1899
1900 via->SetHolePostMachining( aVia->GetFrontPostMachining() );
1901 via->SetSecondaryDrill( aVia->GetSecondaryDrillSize() );
1902
1903 std::optional<PNS_LAYER_RANGE> secondaryLayers;
1904
1907 {
1908 secondaryLayers = SetLayersFromPCBNew( aVia->GetSecondaryDrillStartLayer(),
1909 aVia->GetSecondaryDrillEndLayer() );
1910 }
1911
1912 via->SetSecondaryHoleLayers( secondaryLayers );
1913 via->SetSecondaryHolePostMachining( std::nullopt );
1914
1915 return via;
1916}
1917
1918
1919bool PNS_KICAD_IFACE_BASE::syncZone( PNS::NODE* aWorld, ZONE* aZone, SHAPE_POLY_SET* aBoardOutline )
1920{
1921 // If this ever becomes multi-threaded, we'll need to lose the 'static's. But for now they
1922 // will help performance a tiny bit.
1923 static wxString msg;
1924 static SHAPE_POLY_SET polyStorage;
1925 SHAPE_POLY_SET* poly = &polyStorage;
1926
1927 if( !aZone->GetIsRuleArea() || !aZone->HasKeepoutParametersSet() )
1928 return false;
1929
1930 LSET layers = aZone->GetLayerSet();
1931
1932 // GetBoardOutline() is expensive. Only use it in the router where we have to.
1933 if( aZone->GetParentFootprint() )
1934 polyStorage = aZone->GetBoardOutline();
1935 else
1936 poly = aZone->Outline();
1937
1938 poly->CacheTriangulation();
1939
1940 if( !poly->IsTriangulationUpToDate() )
1941 {
1942 UNITS_PROVIDER unitsProvider( pcbIUScale, GetUnits() );
1943 msg.Printf( _( "%s is malformed." ), aZone->GetItemDescription( &unitsProvider, true ) );
1944
1945 KIDIALOG dlg( nullptr, msg, KIDIALOG::KD_WARNING );
1946 dlg.ShowDetailedText( _( "This zone cannot be handled by the router.\n"
1947 "Please verify it is not a self-intersecting polygon." ) );
1948 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
1949 dlg.ShowModal();
1950
1951 return false;
1952 }
1953
1954 for( PCB_LAYER_ID layer : LAYER_RANGE( F_Cu, B_Cu, m_board->GetCopperLayerCount() ) )
1955 {
1956 if( !layers[ layer ] )
1957 continue;
1958
1959 for( unsigned int polyId = 0; polyId < poly->TriangulatedPolyCount(); polyId++ )
1960 {
1961 const SHAPE_POLY_SET::TRIANGULATED_POLYGON* tri = poly->TriangulatedPolygon( polyId );
1962
1963 for( size_t i = 0; i < tri->GetTriangleCount(); i++)
1964 {
1965 VECTOR2I a, b, c;
1966 tri->GetTriangle( i, a, b, c );
1967 SHAPE_SIMPLE* triShape = new SHAPE_SIMPLE;
1968
1969 triShape->Append( a );
1970 triShape->Append( b );
1971 triShape->Append( c );
1972
1973 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
1974
1975 solid->SetLayer( GetPNSLayerFromBoardLayer( layer ) );
1976 solid->SetNet( nullptr );
1977 solid->SetParent( aZone );
1978 solid->SetShape( triShape );
1979 solid->SetIsCompoundShapePrimitive();
1980 solid->SetRoutable( false );
1981
1982 aWorld->Add( std::move( solid ) );
1983 }
1984 }
1985 }
1986
1987 return true;
1988}
1989
1990
1992{
1993 if( !IsKicadCopperLayer( aLayer ) )
1994 return false;
1995
1996 if( aItem->Type() == PCB_FIELD_T && !static_cast<PCB_FIELD*>( aItem )->IsVisible() )
1997 return false;
1998
1999 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
2000 SHAPE_SIMPLE* shape = new SHAPE_SIMPLE;
2001
2002 solid->SetLayer( GetPNSLayerFromBoardLayer( aLayer ) );
2003 solid->SetNet( nullptr );
2004 solid->SetParent( aItem );
2005 solid->SetShape( shape ); // takes ownership
2006 solid->SetRoutable( false );
2007
2008 SHAPE_POLY_SET cornerBuffer;
2009
2010 aItem->TransformShapeToPolygon( cornerBuffer, aItem->GetLayer(), 0, aItem->GetMaxError(), ERROR_OUTSIDE );
2011
2012 cornerBuffer.Simplify();
2013
2014 if( !cornerBuffer.OutlineCount() )
2015 return false;
2016
2017 for( const VECTOR2I& pt : cornerBuffer.Outline( 0 ).CPoints() )
2018 shape->Append( pt );
2019
2020 aWorld->Add( std::move( solid ) );
2021
2022 return true;
2023}
2024
2025
2027{
2028 if( !IsKicadCopperLayer( aDimension->GetLayer() ) )
2029 return false;
2030
2031 auto addPolysToWorld =
2032 [&]( const SHAPE_POLY_SET& aPolys )
2033 {
2034 for( int ii = 0; ii < aPolys.OutlineCount(); ++ii )
2035 {
2036 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
2037 SHAPE_SIMPLE* shape = new SHAPE_SIMPLE;
2038
2039 solid->SetLayer( GetPNSLayerFromBoardLayer( aDimension->GetLayer() ) );
2040 solid->SetNet( nullptr );
2041 solid->SetParent( aDimension );
2042 solid->SetShape( shape ); // takes ownership
2043 solid->SetRoutable( false );
2044
2045 for( const VECTOR2I& pt : aPolys.Outline( ii ).CPoints() )
2046 shape->Append( pt );
2047
2048 aWorld->Add( std::move( solid ) );
2049 }
2050 };
2051
2052 SHAPE_POLY_SET cornerBuffer;
2053
2054 aDimension->TransformShapeToPolygon( cornerBuffer, aDimension->GetLayer(), 0,
2055 aDimension->GetMaxError(), ERROR_OUTSIDE );
2056
2057 cornerBuffer.Simplify();
2058
2059 if( cornerBuffer.OutlineCount() )
2060 addPolysToWorld( cornerBuffer );
2061
2062 // Footprints can have hidden dimensions
2063 if( aDimension->IsVisible() && !aDimension->GetText().IsEmpty() )
2064 {
2065 SHAPE_POLY_SET textBuffer;
2066
2067 aDimension->PCB_TEXT::TransformShapeToPolygon( textBuffer, aDimension->GetLayer(), 0,
2068 aDimension->GetMaxError(), ERROR_OUTSIDE );
2069
2070 textBuffer.Simplify();
2071
2072 if( textBuffer.OutlineCount() )
2073 addPolysToWorld( textBuffer );
2074 }
2075
2076 return cornerBuffer.OutlineCount() || !aDimension->GetText().IsEmpty();
2077}
2078
2079
2081{
2082 if( aItem->GetLayer() == Edge_Cuts
2083 || aItem->GetLayer() == Margin
2084 || IsKicadCopperLayer( aItem->GetLayer() ) )
2085 {
2086 std::vector<SHAPE*> shapes = aItem->MakeEffectiveShapesWithLineEndings( aItem->GetEffectiveWidth() );
2087
2088 for( SHAPE* shape : shapes )
2089 {
2090 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
2091
2092 if( aItem->GetLayer() == Edge_Cuts || aItem->GetLayer() == Margin )
2093 {
2094 solid->SetLayers( PNS_LAYER_RANGE( 0, m_board->GetCopperLayerCount() - 1 ) );
2095 solid->SetRoutable( false );
2096 }
2097 else
2098 {
2099 solid->SetLayer( GetPNSLayerFromBoardLayer( aItem->GetLayer() ) );
2100 solid->SetRoutable( aItem->Type() != PCB_TABLECELL_T );
2101 }
2102
2103 if( aItem->GetLayer() == Edge_Cuts )
2104 {
2105 switch( shape->Type() )
2106 {
2107 case SH_SEGMENT: static_cast<SHAPE_SEGMENT*>( shape )->SetWidth( 0 ); break;
2108 case SH_ARC: static_cast<SHAPE_ARC*>( shape )->SetWidth( 0 ); break;
2109 case SH_LINE_CHAIN: static_cast<SHAPE_LINE_CHAIN*>( shape )->SetWidth( 0 ); break;
2110 default: /* remaining shapes don't have width */ break;
2111 }
2112 }
2113
2114 solid->SetAnchorPoints( aItem->GetConnectionPoints() );
2115 solid->SetNet( aItem->GetNet() );
2116 solid->SetParent( aItem );
2117 solid->SetShape( shape ); // takes ownership
2118
2119 if( shapes.size() > 1 )
2120 solid->SetIsCompoundShapePrimitive();
2121
2122 aWorld->Add( std::move( solid ) );
2123 }
2124
2125 return true;
2126 }
2127
2128 return false;
2129}
2130
2131
2133{
2134 if( IsKicadCopperLayer( aBarcode->GetLayer() ) )
2135 {
2136 SHAPE_POLY_SET cornerBuffer;
2137
2138 aBarcode->GetBoundingHull( cornerBuffer, aBarcode->GetLayer(), 0, aBarcode->GetMaxError(), ERROR_OUTSIDE );
2139
2140 if( !cornerBuffer.OutlineCount() )
2141 return false;
2142
2143 for( int ii = 0; ii < cornerBuffer.OutlineCount(); ++ii )
2144 {
2145 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
2146 SHAPE_SIMPLE* shape = new SHAPE_SIMPLE;
2147
2148 solid->SetLayer( GetPNSLayerFromBoardLayer( aBarcode->GetLayer() ) );
2149 solid->SetNet( nullptr );
2150 solid->SetParent( aBarcode );
2151 solid->SetShape( shape ); // takes ownership
2152 solid->SetRoutable( false );
2153
2154 for( const VECTOR2I& pt : cornerBuffer.Outline( ii ).CPoints() )
2155 shape->Append( pt );
2156
2157 aWorld->Add( std::move( solid ) );
2158 }
2159
2160 return true;
2161 }
2162
2163 return false;
2164}
2165
2166
2168{
2169 m_board = aBoard;
2170 wxLogTrace( wxT( "PNS" ), wxT( "m_board = %p" ), m_board );
2171}
2172
2173
2175{
2176 return ::IsCopperLayer( GetBoardLayerFromPNSLayer( aPNSLayer ) );
2177}
2178
2179
2180
2182{
2183 return ::IsCopperLayer( aKicadLayer );
2184}
2185
2186
2188{
2189 if( !m_view )
2190 return false;
2191
2192 for( int i = aLayer.Start(); i <= aLayer.End(); i++ )
2193 {
2194 if( m_view->IsLayerVisible( GetBoardLayerFromPNSLayer( i ) ) )
2195 return true;
2196 }
2197
2198 return false;
2199}
2200
2201
2202bool PNS_KICAD_IFACE_BASE::IsFlashedOnLayer( const PNS::ITEM* aItem, int aLayer ) const
2203{
2205 if( aLayer < 0 )
2206 return true;
2207
2208 if( aItem->Parent() )
2209 {
2210 switch( aItem->Parent()->Type() )
2211 {
2212 case PCB_VIA_T:
2213 {
2214 const PCB_VIA* via = static_cast<const PCB_VIA*>( aItem->Parent() );
2215
2216 return via->FlashLayer( GetBoardLayerFromPNSLayer( aLayer ) );
2217 }
2218
2219 case PCB_PAD_T:
2220 {
2221 const PAD* pad = static_cast<const PAD*>( aItem->Parent() );
2222
2223 return pad->FlashLayer( GetBoardLayerFromPNSLayer( aLayer ) );
2224 }
2225
2226 default:
2227 break;
2228 }
2229 }
2230
2231 if( aItem->OfKind( PNS::ITEM::VIA_T ) )
2232 return static_cast<const PNS::VIA*>( aItem )->ConnectsLayer( aLayer );
2233
2234 return aItem->Layers().Overlaps( aLayer );
2235}
2236
2237
2239{
2240 PNS_LAYER_RANGE test = aItem->Layers().Intersection( aLayer );
2241
2242 if( aItem->Parent() )
2243 {
2244 switch( aItem->Parent()->Type() )
2245 {
2246 case PCB_VIA_T:
2247 {
2248 const PCB_VIA* via = static_cast<const PCB_VIA*>( aItem->Parent() );
2249
2250 for( int layer = test.Start(); layer <= test.End(); ++layer )
2251 {
2252 if( via->FlashLayer( GetBoardLayerFromPNSLayer( layer ) ) )
2253 return true;
2254 }
2255
2256 return false;
2257 }
2258
2259 case PCB_PAD_T:
2260 {
2261 const PAD* pad = static_cast<const PAD*>( aItem->Parent() );
2262
2263 for( int layer = test.Start(); layer <= test.End(); ++layer )
2264 {
2265 if( pad->FlashLayer( GetBoardLayerFromPNSLayer( layer ) ) )
2266 return true;
2267 }
2268
2269 return false;
2270 }
2271
2272 default:
2273 break;
2274 }
2275 }
2276
2277 if( aItem->OfKind( PNS::ITEM::VIA_T ) )
2278 {
2279 const PNS::VIA* via = static_cast<const PNS::VIA*>( aItem );
2280
2281 for( int layer = test.Start(); layer <= test.End(); ++layer )
2282 {
2283 if( via->ConnectsLayer( layer ) )
2284 return true;
2285 }
2286
2287 return false;
2288 }
2289
2290 return test.Start() <= test.End();
2291}
2292
2293
2295{
2296 // by default, all items are visible (new ones created by the router have parent == NULL
2297 // as they have not been committed yet to the BOARD)
2298 if( !m_view || !aItem->Parent() )
2299 return true;
2300
2301 BOARD_ITEM* item = aItem->Parent();
2302 bool isOnVisibleLayer = true;
2303 RENDER_SETTINGS* settings = m_view->GetPainter()->GetSettings();
2304
2305 if( settings->GetHighContrast() )
2306 isOnVisibleLayer = item->IsOnLayer( settings->GetPrimaryHighContrastLayer() );
2307
2308 if( m_view->IsVisible( item ) && isOnVisibleLayer )
2309 {
2310 for( PCB_LAYER_ID layer : item->GetLayerSet() )
2311 {
2312 if( item->ViewGetLOD( layer, m_view ) < m_view->GetScale() )
2313 return true;
2314 }
2315 }
2316
2317 // Items hidden in the router are not hidden on the board
2318 if( m_hiddenItems.find( item ) != m_hiddenItems.end() )
2319 return true;
2320
2321 return false;
2322}
2323
2324
2326{
2327 if( !m_board )
2328 {
2329 wxLogTrace( wxT( "PNS" ), wxT( "No board attached, aborting sync." ) );
2330 return;
2331 }
2332
2333 int worstClearance = m_board->GetMaxClearanceValue();
2334
2335 m_world = aWorld;
2336
2337 for( BOARD_ITEM* gitem : m_board->Drawings() )
2338 {
2339 switch( gitem->Type() )
2340 {
2341 case PCB_SHAPE_T:
2342 case PCB_TEXTBOX_T:
2343 syncGraphicalItem( aWorld, static_cast<PCB_SHAPE*>( gitem ) );
2344 break;
2345
2346 case PCB_TEXT_T:
2347 syncTextItem( aWorld, static_cast<PCB_TEXT*>( gitem ), gitem->GetLayer() );
2348 break;
2349
2350 case PCB_TABLE_T:
2351 case PCB_DRILL_CHART_T:
2352 syncTextItem( aWorld, static_cast<PCB_TABLE*>( gitem ), gitem->GetLayer() );
2353 break;
2354
2355 case PCB_BARCODE_T:
2356 syncBarcode( aWorld, static_cast<PCB_BARCODE*>( gitem ) );
2357 break;
2358
2359 case PCB_DIM_ALIGNED_T:
2360 case PCB_DIM_CENTER_T:
2361 case PCB_DIM_RADIAL_T:
2363 case PCB_DIM_LEADER_T:
2364 syncDimension( aWorld, static_cast<PCB_DIMENSION_BASE*>( gitem ) );
2365 break;
2366
2367 case PCB_REFERENCE_IMAGE_T: // ignore
2368 case PCB_TARGET_T:
2369 case PCB_GRID_ITEM_T:
2370 break;
2371
2372 default:
2373 UNIMPLEMENTED_FOR( gitem->GetClass() );
2374 break;
2375 }
2376 }
2377
2378 SHAPE_POLY_SET buffer;
2379 SHAPE_POLY_SET* boardOutline = nullptr;
2380
2381 if( m_board->GetBoardPolygonOutlines( buffer, true ) )
2382 boardOutline = &buffer;
2383
2384 for( ZONE* zone : m_board->Zones() )
2385 {
2386 syncZone( aWorld, zone, boardOutline );
2387 }
2388
2389 for( FOOTPRINT* footprint : m_board->Footprints() )
2390 {
2391 for( PAD* pad : footprint->Pads() )
2392 {
2393 std::vector<std::unique_ptr<PNS::SOLID>> solids = syncPad( pad );
2394
2395 for( std::unique_ptr<PNS::SOLID>& solid : solids )
2396 aWorld->Add( std::move( solid ) );
2397
2398 std::optional<int> clearanceOverride = pad->GetClearanceOverrides( nullptr );
2399
2400 if( clearanceOverride.has_value() )
2401 worstClearance = std::max( worstClearance, clearanceOverride.value() );
2402
2403 if( pad->GetProperty() == PAD_PROP::CASTELLATED )
2404 {
2405 std::unique_ptr<SHAPE> hole;
2406 hole.reset( pad->GetEffectiveHoleShape()->Clone() );
2407 aWorld->AddEdgeExclusion( std::move( hole ) );
2408 }
2409 }
2410
2411 syncTextItem( aWorld, &footprint->Reference(), footprint->Reference().GetLayer() );
2412 syncTextItem( aWorld, &footprint->Value(), footprint->Value().GetLayer() );
2413
2414 for( ZONE* zone : footprint->Zones() )
2415 syncZone( aWorld, zone, boardOutline );
2416
2417 for( PCB_FIELD* field : footprint->GetFields() )
2418 syncTextItem( aWorld, static_cast<PCB_TEXT*>( field ), field->GetLayer() );
2419
2420 for( BOARD_ITEM* item : footprint->GraphicalItems() )
2421 {
2422 switch( item->Type() )
2423 {
2424 case PCB_SHAPE_T:
2425 case PCB_TEXTBOX_T:
2426 syncGraphicalItem( aWorld, static_cast<PCB_SHAPE*>( item ) );
2427 break;
2428
2429 case PCB_TEXT_T:
2430 syncTextItem( aWorld, static_cast<PCB_TEXT*>( item ), item->GetLayer() );
2431 break;
2432
2433 case PCB_TABLE_T:
2434 syncTextItem( aWorld, static_cast<PCB_TABLE*>( item ), item->GetLayer() );
2435 break;
2436
2437 case PCB_BARCODE_T:
2438 syncBarcode( aWorld, static_cast<PCB_BARCODE*>( item ) );
2439 break;
2440
2441 case PCB_DIM_ALIGNED_T:
2442 case PCB_DIM_CENTER_T:
2443 case PCB_DIM_RADIAL_T:
2445 case PCB_DIM_LEADER_T:
2446 syncDimension( aWorld, static_cast<PCB_DIMENSION_BASE*>( item ) );
2447 break;
2448
2449 case PCB_REFERENCE_IMAGE_T: // ignore
2450 break;
2451
2452 default:
2453 UNIMPLEMENTED_FOR( item->GetClass() );
2454 break;
2455 }
2456 }
2457 }
2458
2459 for( PCB_TRACK* t : m_board->Tracks() )
2460 {
2461 KICAD_T type = t->Type();
2462
2463 if( type == PCB_TRACE_T )
2464 {
2465 if( std::unique_ptr<PNS::SEGMENT> segment = syncTrack( t ) )
2466 aWorld->Add( std::move( segment ), true );
2467 }
2468 else if( type == PCB_ARC_T )
2469 {
2470 if( std::unique_ptr<PNS::ARC> arc = syncArc( static_cast<PCB_ARC*>( t ) ) )
2471 aWorld->Add( std::move( arc ), true );
2472 }
2473 else if( type == PCB_VIA_T )
2474 {
2475 if( std::unique_ptr<PNS::VIA> via = syncVia( static_cast<PCB_VIA*>( t ) ) )
2476 aWorld->Add( std::move( via ) );
2477 }
2478 }
2479
2480 // NB: if this were ever to become a long-lived object we would need to dirty its
2481 // clearance cache here....
2482 delete m_ruleResolver;
2484
2486 aWorld->SetMaxClearance( worstClearance + m_ruleResolver->ClearanceEpsilon() );
2487}
2488
2489
2491{
2492 for( BOARD_ITEM* item : m_hiddenItems )
2493 m_view->SetVisible( item, true );
2494
2495 m_hiddenItems.clear();
2496
2497 if( m_previewItems )
2498 {
2499 m_previewItems->FreeItems();
2500 m_view->Update( m_previewItems );
2501 }
2502
2503 if( m_debugDecorator )
2504 m_debugDecorator->Clear();
2505}
2506
2507
2512
2513
2514void PNS_KICAD_IFACE::DisplayItem( const PNS::ITEM* aItem, int aClearance, bool aEdit, int aFlags )
2515{
2516 if( aItem->IsVirtual() )
2517 return;
2518
2519 if( ZONE* zone = dynamic_cast<ZONE*>( aItem->Parent() ) )
2520 {
2521 if( zone->GetIsRuleArea() )
2522 aFlags |= PNS_SEMI_SOLID;
2523 }
2524
2525 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aItem, this, m_view, aFlags );
2526
2527 // Note: SEGMENT_T is used for placed tracks; LINE_T is used for the routing head
2529 static int tracksOrVias = tracks | PNS::ITEM::VIA_T;
2530
2531 if( aClearance >= 0 )
2532 {
2533 pitem->SetClearance( aClearance );
2534
2535 PCBNEW_SETTINGS* settings = static_cast<PCBNEW_SETTINGS*>( m_tool->GetManager()->GetSettings() );
2536
2537 switch( settings->m_Display.m_TrackClearance )
2538 {
2541 pitem->ShowClearance( aItem->OfKind( tracksOrVias ) );
2542 break;
2543
2545 pitem->ShowClearance( aItem->OfKind( tracksOrVias ) && !aEdit );
2546 break;
2547
2548 case SHOW_WHILE_ROUTING:
2549 pitem->ShowClearance( aItem->OfKind( tracks ) && !aEdit );
2550 break;
2551
2552 default:
2553 pitem->ShowClearance( false );
2554 break;
2555 }
2556 }
2557
2558 m_previewItems->Add( pitem );
2559 m_view->Update( m_previewItems );
2560}
2561
2562
2563void PNS_KICAD_IFACE::DisplayPathLine( const SHAPE_LINE_CHAIN& aLine, int aImportance )
2564{
2565 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aLine, this, m_view );
2567
2568 COLOR4D color;
2569
2570 if( aImportance >= 1 )
2571 color = COLOR4D( 1.0, 1.0, 0.0, 0.6 );
2572 else if( aImportance == 0 )
2573 color = COLOR4D( 0.7, 0.7, 0.7, 0.6 );
2574
2575 pitem->SetColor( color );
2576
2577 m_previewItems->Add( pitem );
2578 m_view->Update( m_previewItems );
2579}
2580
2581
2583{
2584 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aRatline, this, m_view );
2585
2586 KIGFX::RENDER_SETTINGS* renderSettings = m_view->GetPainter()->GetSettings();
2587 KIGFX::PCB_RENDER_SETTINGS* rs = static_cast<KIGFX::PCB_RENDER_SETTINGS*>( renderSettings );
2588 bool colorByNet = rs->GetNetColorMode() != NET_COLOR_MODE::OFF;
2589 COLOR4D defaultColor = rs->GetColor( nullptr, LAYER_RATSNEST );
2590 COLOR4D color = defaultColor;
2591
2592 std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_board->GetConnectivity();
2593 std::set<int> highlightedNets = rs->GetHighlightNetCodes();
2594 std::map<int, KIGFX::COLOR4D>& netColors = rs->GetNetColorMap();
2595 int netCode = -1;
2596
2597 if( NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aNet ) )
2598 netCode = net->GetNetCode();
2599
2600 const NETCLASS* nc = nullptr;
2601 const NET_SETTINGS* netSettings = connectivity->GetNetSettings();
2602
2603 if( connectivity->HasNetNameForNetCode( netCode ) )
2604 {
2605 const wxString& netName = connectivity->GetNetNameForNetCode( netCode );
2606
2607 if( netSettings && netSettings->HasEffectiveNetClass( netName ) )
2608 nc = netSettings->GetCachedEffectiveNetClass( netName ).get();
2609 }
2610
2611 if( colorByNet && netColors.count( netCode ) )
2612 color = netColors.at( netCode );
2613 else if( colorByNet && nc && nc->HasPcbColor() )
2614 color = nc->GetPcbColor();
2615 else
2616 color = defaultColor;
2617
2618 if( color == COLOR4D::UNSPECIFIED )
2619 color = defaultColor;
2620
2621 pitem->SetColor( color.Brightened( 0.5 ).WithAlpha( std::min( 1.0, color.a + 0.4 ) ) );
2622
2623 m_previewItems->Add( pitem );
2624 m_view->Update( m_previewItems );
2625}
2626
2627
2629{
2630 BOARD_ITEM* parent = aItem->Parent();
2631
2632 if( parent )
2633 {
2634 if( m_view->IsVisible( parent ) )
2635 m_hiddenItems.insert( parent );
2636
2637 m_view->SetVisible( parent, false );
2638 m_view->Update( parent, KIGFX::APPEARANCE );
2639
2640 for( ZONE* td : m_board->Zones() )
2641 {
2642 if( td->IsTeardropArea()
2643 && td->GetBoundingBox().Intersects( aItem->Parent()->GetBoundingBox() )
2644 && td->Outline()->Collide( aItem->Shape( td->GetLayer() ) ) )
2645 {
2646 m_view->SetVisible( td, false );
2647 m_view->Update( td, KIGFX::APPEARANCE );
2648 }
2649 }
2650 }
2651}
2652
2653
2657
2658
2660{
2661 BOARD_ITEM* parent = aItem->Parent();
2662
2663 if( aItem->OfKind( PNS::ITEM::SOLID_T ) && parent->Type() == PCB_PAD_T )
2664 {
2665 PAD* pad = static_cast<PAD*>( parent );
2666 VECTOR2I pos = static_cast<PNS::SOLID*>( aItem )->Pos();
2667
2668 m_fpOffsets[ pad ].p_old = pos;
2669 return;
2670 }
2671
2672 if( parent )
2673 {
2674 if( EDA_GROUP* group = parent->GetParentGroup() )
2675 m_itemGroups[parent] = group;
2676
2677 m_commit->Remove( parent );
2678 }
2679}
2680
2681
2685
2686
2688{
2689 BOARD_ITEM* board_item = aItem->Parent();
2690
2691 switch( aItem->Kind() )
2692 {
2693 case PNS::ITEM::ARC_T:
2694 {
2695 PNS::ARC* arc = static_cast<PNS::ARC*>( aItem );
2696 PCB_ARC* arc_board = static_cast<PCB_ARC*>( board_item );
2697 const SHAPE_ARC* arc_shape = static_cast<const SHAPE_ARC*>( arc->Shape( -1 ) );
2698
2699 m_commit->Modify( arc_board );
2700
2701 arc_board->SetStart( VECTOR2I( arc_shape->GetP0() ) );
2702 arc_board->SetEnd( VECTOR2I( arc_shape->GetP1() ) );
2703 arc_board->SetMid( VECTOR2I( arc_shape->GetArcMid() ) );
2704 arc_board->SetWidth( arc->Width() );
2705 break;
2706 }
2707
2709 {
2710 PNS::SEGMENT* seg = static_cast<PNS::SEGMENT*>( aItem );
2711 PCB_TRACK* track = static_cast<PCB_TRACK*>( board_item );
2712 const SEG& s = seg->Seg();
2713
2714 m_commit->Modify( track );
2715
2716 track->SetStart( VECTOR2I( s.A.x, s.A.y ) );
2717 track->SetEnd( VECTOR2I( s.B.x, s.B.y ) );
2718 track->SetWidth( seg->Width() );
2719 break;
2720 }
2721
2722 case PNS::ITEM::VIA_T:
2723 {
2724 PCB_VIA* via_board = static_cast<PCB_VIA*>( board_item );
2725 PNS::VIA* via = static_cast<PNS::VIA*>( aItem );
2726
2727 m_commit->Modify( via_board );
2728
2729 via_board->SetPosition( VECTOR2I( via->Pos().x, via->Pos().y ) );
2730 via_board->SetWidth( PADSTACK::TEMP_ALL_LAYERS, via->Diameter( 0 ) );
2731 via_board->SetDrill( via->Drill() );
2732 via_board->SetNet( static_cast<NETINFO_ITEM*>( via->Net() ) );
2733 via_board->SetViaType( via->ViaType() ); // MUST be before SetLayerPair()
2734 via_board->Padstack().SetUnconnectedLayerMode( via->UnconnectedLayerMode() );
2735 via_board->SetIsFree( via->IsFree() );
2736 // A via holds its copper span in the primary drill layers, so this call is the only
2737 // writer of both; a write back from the PNS hole layers can only repeat or corrupt it
2738 via_board->SetLayerPair( GetBoardLayerFromPNSLayer( via->Layers().Start() ),
2739 GetBoardLayerFromPNSLayer( via->Layers().End() ) );
2740
2741 via_board->SetFrontPostMachining( via->HolePostMachining() );
2742 via_board->SetSecondaryDrillSize( via->SecondaryDrill() );
2743
2744 if( std::optional<PNS_LAYER_RANGE> secondaryLayers = via->SecondaryHoleLayers() )
2745 {
2746 via_board->SetSecondaryDrillStartLayer( GetBoardLayerFromPNSLayer( secondaryLayers->Start() ) );
2747 via_board->SetSecondaryDrillEndLayer( GetBoardLayerFromPNSLayer( secondaryLayers->End() ) );
2748 }
2749 else
2750 {
2753 }
2754
2755 break;
2756 }
2757
2758 case PNS::ITEM::SOLID_T:
2759 {
2760 if( aItem->Parent()->Type() == PCB_PAD_T )
2761 {
2762 PAD* pad = static_cast<PAD*>( aItem->Parent() );
2763 VECTOR2I pos = static_cast<PNS::SOLID*>( aItem )->Pos();
2764
2765 // Don't add to commit; we'll add the parent footprints when processing the m_fpOffsets
2766
2767 m_fpOffsets[pad].p_old = pad->GetPosition();
2768 m_fpOffsets[pad].p_new = pos;
2769 }
2770 break;
2771 }
2772
2773 default:
2774 m_commit->Modify( aItem->Parent() );
2775 break;
2776 }
2777}
2778
2779
2781{
2782 modifyBoardItem( aItem );
2783}
2784
2785
2787{
2788}
2789
2790
2792{
2793 BOARD_CONNECTED_ITEM* newBoardItem = nullptr;
2794 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aItem->Net() );
2795
2796 if( !net )
2798
2799 switch( aItem->Kind() )
2800 {
2801 case PNS::ITEM::ARC_T:
2802 {
2803 PNS::ARC* arc = static_cast<PNS::ARC*>( aItem );
2804 PCB_ARC* new_arc = new PCB_ARC( m_board, static_cast<const SHAPE_ARC*>( arc->Shape( -1 ) ) );
2805 new_arc->SetWidth( arc->Width() );
2806 new_arc->SetLayer( GetBoardLayerFromPNSLayer( arc->Layers().Start() ) );
2807 new_arc->SetNet( net );
2808
2809 if( aItem->GetSourceItem() && aItem->GetSourceItem()->IsType( { PCB_TRACE_T, PCB_ARC_T } ) )
2810 {
2811 PCB_TRACK* sourceTrack = static_cast<PCB_TRACK*>( aItem->GetSourceItem() );
2812 new_arc->SetHasSolderMask( sourceTrack->HasSolderMask() );
2813 new_arc->SetLocalSolderMaskMargin( sourceTrack->GetLocalSolderMaskMargin() );
2814 }
2815
2816 newBoardItem = new_arc;
2817 break;
2818 }
2819
2821 {
2822 PNS::SEGMENT* seg = static_cast<PNS::SEGMENT*>( aItem );
2823 PCB_TRACK* track = new PCB_TRACK( m_board );
2824 const SEG& s = seg->Seg();
2825 track->SetStart( VECTOR2I( s.A.x, s.A.y ) );
2826 track->SetEnd( VECTOR2I( s.B.x, s.B.y ) );
2827 track->SetWidth( seg->Width() );
2828 track->SetLayer( GetBoardLayerFromPNSLayer( seg->Layers().Start() ) );
2829 track->SetNet( net );
2830
2831 if( aItem->GetSourceItem() && aItem->GetSourceItem()->IsType( { PCB_TRACE_T, PCB_ARC_T } ) )
2832 {
2833 PCB_TRACK* sourceTrack = static_cast<PCB_TRACK*>( aItem->GetSourceItem() );
2834 track->SetHasSolderMask( sourceTrack->HasSolderMask() );
2835 track->SetLocalSolderMaskMargin( sourceTrack->GetLocalSolderMaskMargin() );
2836 }
2837
2838 newBoardItem = track;
2839 break;
2840 }
2841
2842 case PNS::ITEM::VIA_T:
2843 {
2844 PCB_VIA* via_board = new PCB_VIA( m_board );
2845 PNS::VIA* via = static_cast<PNS::VIA*>( aItem );
2846 via_board->SetPosition( VECTOR2I( via->Pos().x, via->Pos().y ) );
2847 via_board->SetWidth( PADSTACK::TEMP_ALL_LAYERS, via->Diameter( 0 ) );
2848 via_board->SetDrill( via->Drill() );
2849 via_board->SetNet( net );
2850 via_board->SetViaType( via->ViaType() ); // MUST be before SetLayerPair()
2851 via_board->Padstack().SetUnconnectedLayerMode( via->UnconnectedLayerMode() );
2852 via_board->SetIsFree( via->IsFree() );
2853 // A via holds its copper span in the primary drill layers, so this call is the only
2854 // writer of both; a write back from the PNS hole layers can only repeat or corrupt it
2855 via_board->SetLayerPair( GetBoardLayerFromPNSLayer( via->Layers().Start() ),
2856 GetBoardLayerFromPNSLayer( via->Layers().End() ) );
2857
2858 via_board->SetFrontPostMachining( via->HolePostMachining() );
2859 via_board->SetSecondaryDrillSize( via->SecondaryDrill() );
2860
2861 if( std::optional<PNS_LAYER_RANGE> secondaryLayers = via->SecondaryHoleLayers() )
2862 {
2863 via_board->SetSecondaryDrillStartLayer( GetBoardLayerFromPNSLayer( secondaryLayers->Start() ) );
2864 via_board->SetSecondaryDrillEndLayer( GetBoardLayerFromPNSLayer( secondaryLayers->End() ) );
2865 }
2866 else
2867 {
2870 }
2871
2872 if( aItem->GetSourceItem() && aItem->GetSourceItem()->Type() == PCB_VIA_T )
2873 {
2874 PCB_VIA* sourceVia = static_cast<PCB_VIA*>( aItem->GetSourceItem() );
2875 via_board->SetFrontTentingMode( sourceVia->GetFrontTentingMode() );
2876 via_board->SetBackTentingMode( sourceVia->GetBackTentingMode() );
2877 }
2878
2879 newBoardItem = via_board;
2880 break;
2881 }
2882
2883 case PNS::ITEM::SOLID_T:
2884 {
2885 PAD* pad = static_cast<PAD*>( aItem->Parent() );
2886 VECTOR2I pos = static_cast<PNS::SOLID*>( aItem )->Pos();
2887
2888 m_fpOffsets[pad].p_new = pos;
2889 return nullptr;
2890 }
2891
2892 default:
2893 return nullptr;
2894 }
2895
2896 if( net->GetNetCode() <= 0 )
2897 {
2898 NETINFO_ITEM* newNetInfo = newBoardItem->GetNet();
2899
2900 newNetInfo->SetParent( m_board );
2901 newNetInfo->SetNetClass( m_board->GetDesignSettings().m_NetSettings->GetDefaultNetclass() );
2902 }
2903
2904 if( newBoardItem )
2905 {
2906 if( aItem->IsLocked() )
2907 newBoardItem->SetLocked( true );
2908
2909 if( BOARD_ITEM* src = aItem->GetSourceItem() )
2910 {
2911 if( !m_itemGroups.contains( src ) )
2912 {
2913 if( EDA_GROUP* group = src->GetParentGroup() )
2914 m_itemGroups[src] = group;
2915 }
2916
2917 if( m_itemGroups.contains( src ) )
2918 m_replacementMap[src].push_back( newBoardItem );
2919 }
2920 else
2921 {
2922 // This is a new item, which goes in the entered group (if any)
2923 m_replacementMap[ENTERED_GROUP_MAGIC_NUMBER].push_back( newBoardItem );
2924 }
2925 }
2926
2927 return newBoardItem;
2928}
2929
2930
2932{
2933 BOARD_CONNECTED_ITEM* boardItem = createBoardItem( aItem );
2934
2935 if( boardItem )
2936 {
2937 aItem->SetParent( boardItem );
2938 boardItem->ClearFlags();
2939
2940 m_commit->Add( boardItem );
2941 }
2942}
2943
2944
2946{
2947 PCB_SELECTION_TOOL* selTool = m_tool->GetManager()->GetTool<PCB_SELECTION_TOOL>();
2948 std::set<FOOTPRINT*> processedFootprints;
2949
2950 EraseView();
2951
2952 for( const auto& [ pad, fpOffset ] : m_fpOffsets )
2953 {
2954 VECTOR2I offset = fpOffset.p_new - fpOffset.p_old;
2955 FOOTPRINT* footprint = pad->GetParentFootprint();
2956 VECTOR2I p_orig = footprint->GetPosition();
2957 VECTOR2I p_new = p_orig + offset;
2958
2959 if( processedFootprints.find( footprint ) != processedFootprints.end() )
2960 continue;
2961
2962 processedFootprints.insert( footprint );
2963 m_commit->Modify( footprint );
2964 footprint->SetPosition( p_new );
2965 }
2966
2967 m_fpOffsets.clear();
2968
2969 for( const auto& [ src, items ] : m_replacementMap )
2970 {
2971 EDA_GROUP* group = nullptr;
2972
2973 if( src == ENTERED_GROUP_MAGIC_NUMBER )
2974 group = selTool ? selTool->GetEnteredGroup() : nullptr;
2975 else if( auto it = m_itemGroups.find( src ); it != m_itemGroups.end() )
2976 group = it->second;
2977
2978 if( group )
2979 {
2980 m_commit->Modify( group->AsEdaItem(), nullptr, RECURSE_MODE::NO_RECURSE );
2981
2982 for( BOARD_ITEM* bi : items )
2983 group->AddItem( bi );
2984 }
2985 }
2986
2987 m_itemGroups.clear();
2988 m_replacementMap.clear();
2989
2990 m_commit->Push( _( "Routing" ), m_commitFlags | SKIP_ENTERED_GROUP );
2991 m_commit = std::make_unique<BOARD_COMMIT>( m_tool );
2992}
2993
2994
2996{
2997 return static_cast<EDA_UNITS>( m_tool->GetManager()->GetSettings()->m_System.units );
2998}
2999
3000
3002{
3003 wxLogTrace( wxT( "PNS" ), wxT( "SetView %p" ), aView );
3004
3005 if( m_previewItems )
3006 {
3007 m_previewItems->FreeItems();
3008 delete m_previewItems;
3009 }
3010
3011 m_view = aView;
3014
3015 if(m_view)
3016 m_view->Add( m_previewItems );
3017
3018 delete m_debugDecorator;
3019
3020 auto dec = new PNS_PCBNEW_DEBUG_DECORATOR( this );
3021 m_debugDecorator = dec;
3022
3023 dec->SetDebugEnabled( ADVANCED_CFG::GetCfg().m_ShowRouterDebugGraphics );
3024
3025 if( ADVANCED_CFG::GetCfg().m_ShowRouterDebugGraphics )
3026 dec->SetView( m_view );
3027}
3028
3029
3031{
3032 if( aNet )
3033 return static_cast<NETINFO_ITEM*>( aNet )->GetNetCode();
3034 else
3035 return -1;
3036}
3037
3038
3040{
3041 if( aNet )
3042 return static_cast<NETINFO_ITEM*>( aNet )->GetNetname();
3043 else
3044 return wxEmptyString;
3045}
3046
3047
3049{
3050 wxLogTrace( wxT( "PNS" ), wxT( "Update-net %s" ), GetNetName( aNet ) );
3051}
3052
3053
3058
3059
3064
3065
3067{
3068 m_tool = aTool;
3069 m_commit = std::make_unique<BOARD_COMMIT>( m_tool );
3070}
3071
3072
3074{
3075 if( aLayer < 0 || aLayer >= m_board->GetCopperLayerCount() )
3077
3078 if( aLayer == 0 )
3079 return F_Cu;
3080
3081 if( aLayer == m_board->GetCopperLayerCount() - 1 )
3082 return B_Cu;
3083
3084 return static_cast<PCB_LAYER_ID>( ( aLayer + 1 ) * 2 );
3085}
3086
3087
3089{
3090 if( aLayer < 0 )
3091 return -1;
3092
3093 if( aLayer == F_Cu )
3094 return 0;
3095
3096 if( aLayer == B_Cu )
3097 return m_board->GetCopperLayerCount() - 1;
3098
3099 return ( aLayer / 2 ) - 1;
3100}
3101
3103 long long& aExtraLength, long long& aExtraDelay ) const
3104{
3105 aExtraLength = 0;
3106 aExtraDelay = 0;
3107 if( !m_board || !aNetP || !aNetN )
3108 return false;
3109
3110 auto* netP = static_cast<NETINFO_ITEM*>( aNetP );
3111 auto* netN = static_cast<NETINFO_ITEM*>( aNetN );
3112 wxString sig = netP->GetNetChain();
3113 if( sig.IsEmpty() || sig != netN->GetNetChain() )
3114 return false;
3115
3116 // Build the set of net codes to exclude (the nets the caller is already accounting for).
3117 std::set<int> exclude;
3118 exclude.insert( netP->GetNetCode() );
3119 if( netP != netN )
3120 exclude.insert( netN->GetNetCode() );
3121
3122 // Sum routed length/delay of every other net in the chain.
3123 for( NETINFO_ITEM* net : m_board->GetNetInfo() )
3124 {
3125 if( net->GetNetChain() != sig )
3126 continue;
3127 if( exclude.count( net->GetNetCode() ) )
3128 continue;
3129
3130 PCB_TRACK* rep = nullptr;
3131
3132 for( BOARD_ITEM* bi : m_board->Tracks() )
3133 {
3134 if( auto tr = dynamic_cast<PCB_TRACK*>( bi ) )
3135 {
3136 if( tr->GetNetCode() == net->GetNetCode() )
3137 {
3138 rep = tr;
3139 break;
3140 }
3141 }
3142 }
3143
3144 if( rep )
3145 {
3146 int count = 0; double trk = 0, pad = 0, tDelay = 0, padDelay = 0;
3147 std::tie( count, trk, pad, tDelay, padDelay ) = m_board->GetTrackLength( *rep );
3148 aExtraLength += KiROUND<double, long long>( trk + pad );
3149
3150 if( tDelay > 0.0 || padDelay > 0.0 )
3151 aExtraDelay += KiROUND<double, long long>( tDelay + padDelay );
3152 }
3153 }
3154
3155 // Chain is valid; return true even if no sibling nets carry routed length yet so the
3156 // placer applies the full chain budget to the net being routed first.
3157 return true;
3158}
3159
3161 long long& aExtraLength, long long& aExtraDelay ) const
3162{
3163 return PNS_KICAD_IFACE_BASE::GetSignalAggregate( aNetP, aNetN, aExtraLength, aExtraDelay );
3164}
3165
3166
3168{
3169 if( !m_board || !aNet )
3170 return 0;
3171
3172 auto* ni = static_cast<NETINFO_ITEM*>( aNet );
3173
3174 for( BOARD_ITEM* bi : m_board->Tracks() )
3175 {
3176 if( auto tr = dynamic_cast<PCB_TRACK*>( bi ) )
3177 {
3178 if( tr->GetNetCode() == ni->GetNetCode() )
3179 {
3180 int count = 0; double trk = 0, pad = 0, tDelay = 0, padDelay = 0;
3181 std::tie( count, trk, pad, tDelay, padDelay ) = m_board->GetTrackLength( *tr );
3182 return KiROUND<double, long long>( trk + pad );
3183 }
3184 }
3185 }
3186
3187 return 0;
3188}
3189
3190
3191void PNS_KICAD_IFACE_BASE::RemoveBoardConnected( const std::vector<const PNS::ITEM*>& aJoined,
3192 std::set<PNS::ITEM*>& aItems ) const
3193{
3194 if( !m_board )
3195 return;
3196
3197 std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_board->GetConnectivity();
3198 std::set<const BOARD_ITEM*> boardJoined;
3199
3200 for( const PNS::ITEM* item : aJoined )
3201 {
3202 BOARD_ITEM* parent = item->Parent();
3203
3204 if( !parent || !parent->IsConnected() || !boardJoined.insert( parent ).second )
3205 continue;
3206
3207 for( BOARD_CONNECTED_ITEM* connected :
3208 connectivity->GetConnectedItems( static_cast<BOARD_CONNECTED_ITEM*>( parent ) ) )
3209 {
3210 boardJoined.insert( connected );
3211 }
3212 }
3213
3214 std::erase_if( aItems,
3215 [&]( PNS::ITEM* aItem )
3216 {
3217 return aItem->Parent() && boardJoined.count( aItem->Parent() );
3218 } );
3219}
3220
3221
3226
3227
3232
3233
3235 const PNS::SOLID* aEndPad, const NETCLASS* aNetClass )
3236{
3237 std::vector<LENGTH_DELAY_CALCULATION_ITEM> lengthItems = GetLengthDelayCalculationItems( aLine, aNetClass );
3238
3239 const PAD* startPad = nullptr;
3240 const PAD* endPad = nullptr;
3241
3242 if( aStartPad )
3243 startPad = static_cast<PAD*>( aStartPad->Parent() );
3244
3245 if( aEndPad )
3246 endPad = static_cast<PAD*>( aEndPad->Parent() );
3247
3248 constexpr PATH_OPTIMISATIONS opts = {
3249 .OptimiseVias = false,
3250 .MergeTracks = false,
3251 .OptimiseTracesInPads = false,
3252 .InferViaInPad = true
3253 };
3254 const BOARD* board = GetBoard();
3255 return board->GetLengthCalculation()->CalculateLength( lengthItems, opts, startPad, endPad );
3256}
3257
3258
3260 const PNS::SOLID* aEndPad, const NETCLASS* aNetClass )
3261{
3262 std::vector<LENGTH_DELAY_CALCULATION_ITEM> lengthItems = GetLengthDelayCalculationItems( aLine, aNetClass );
3263
3264 const PAD* startPad = nullptr;
3265 const PAD* endPad = nullptr;
3266
3267 if( aStartPad )
3268 startPad = static_cast<PAD*>( aStartPad->Parent() );
3269
3270 if( aEndPad )
3271 endPad = static_cast<PAD*>( aEndPad->Parent() );
3272
3273 constexpr PATH_OPTIMISATIONS opts = {
3274 .OptimiseVias = false,
3275 .MergeTracks = false,
3276 .OptimiseTracesInPads = false,
3277 .InferViaInPad = true
3278 };
3279 const BOARD* board = GetBoard();
3280 return board->GetLengthCalculation()->CalculateDelay( lengthItems, opts, startPad, endPad );
3281}
3282
3283
3284int64_t PNS_KICAD_IFACE_BASE::CalculateLengthForDelay( int64_t aDesiredDelay, const int aWidth,
3285 const bool aIsDiffPairCoupled, const int aDiffPairCouplingGap,
3286 const int aPNSLayer, const NETCLASS* aNetClass )
3287{
3289 ctx.NetClass = aNetClass;
3290 ctx.Width = aWidth;
3291 ctx.IsDiffPairCoupled = aIsDiffPairCoupled;
3292 ctx.DiffPairCouplingGap = aDiffPairCouplingGap;
3293 ctx.Layer = GetBoardLayerFromPNSLayer( aPNSLayer );
3294
3295 const BOARD* board = GetBoard();
3296 return board->GetLengthCalculation()->CalculateLengthForDelay( aDesiredDelay, ctx );
3297}
3298
3299
3301 bool aIsDiffPairCoupled, int aDiffPairCouplingGap,
3302 int aPNSLayer, const NETCLASS* aNetClass )
3303{
3305 ctx.NetClass = aNetClass;
3306 ctx.Width = aWidth;
3307 ctx.IsDiffPairCoupled = aIsDiffPairCoupled;
3308 ctx.DiffPairCouplingGap = aDiffPairCouplingGap;
3309 ctx.Layer = GetBoardLayerFromPNSLayer( aPNSLayer );
3310
3311 const BOARD* board = GetBoard();
3313}
3314
3315
3316std::vector<LENGTH_DELAY_CALCULATION_ITEM>
3318{
3319 std::vector<LENGTH_DELAY_CALCULATION_ITEM> lengthItems;
3320
3321 for( int idx = 0; idx < aLine.Size(); idx++ )
3322 {
3323 const PNS::ITEM* lineItem = aLine[idx];
3324
3325 if( const PNS::LINE* l = dyn_cast<const PNS::LINE*>( lineItem ) )
3326 {
3328 item.SetLine( l->CLine() );
3329
3330 const PCB_LAYER_ID layer = GetBoardLayerFromPNSLayer( lineItem->Layer() );
3331 item.SetLayers( layer );
3332 item.SetEffectiveNetClass( aNetClass );
3333 item.SetWidth( l->Width() );
3334
3335 lengthItems.emplace_back( std::move( item ) );
3336 }
3337 else if( lineItem->OfKind( PNS::ITEM::VIA_T ) && idx > 0 && idx < aLine.Size() - 1 )
3338 {
3339 const int layerPrev = aLine[idx - 1]->Layer();
3340 const int layerNext = aLine[idx + 1]->Layer();
3341 const PCB_LAYER_ID pcbLayerPrev = GetBoardLayerFromPNSLayer( layerPrev );
3342 const PCB_LAYER_ID pcbLayerNext = GetBoardLayerFromPNSLayer( layerNext );
3343
3344 if( layerPrev != layerNext )
3345 {
3347 item.SetVia( static_cast<PCB_VIA*>( lineItem->GetSourceItem() ) );
3348 item.SetLayers( pcbLayerPrev, pcbLayerNext ); // TODO: BUG IS HERE!!!
3349 item.SetEffectiveNetClass( aNetClass );
3350 lengthItems.emplace_back( std::move( item ) );
3351 }
3352 }
3353 }
3354
3355 return lengthItems;
3356}
@ ERROR_OUTSIDE
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:128
#define SKIP_ENTERED_GROUP
@ OFF
Net (and netclass) colors are not shown.
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:982
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
virtual void SetNet(NETINFO_ITEM *aNetInfo)
Set a NET_INFO object for the item.
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
NETINFO_ITEM * GetNet() const
Return NETINFO_ITEM object for a given item.
Container for design settings for a BOARD object.
bool UseNetClassVia() const
Return true if netclass values should be used to obtain appropriate via size.
bool UseNetClassTrack() const
Return true if netclass values should be used to obtain appropriate track width.
bool UseNetClassDiffPair() const
Return true if netclass values should be used to obtain appropriate diff pair dimensions.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
void SetLocked(bool aLocked) override
Definition board_item.h:418
virtual bool IsConnected() const
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Definition board_item.h:172
bool IsLocked() const override
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
virtual void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const
Convert the item shape to a closed polygon.
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
Definition board_item.h:409
FOOTPRINT * GetParentFootprint() const
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition board_item.h:346
virtual bool HasDrilledHole() const
Definition board_item.h:212
virtual int BoardCopperLayerCount() const
Return the total number of copper layers for the board that this item resides on.
virtual bool IsOnCopperLayer() const
Definition board_item.h:189
int GetMaxError() const
Manage layers needed to make a physical board.
int GetLayerDistance(PCB_LAYER_ID aFirstLayer, PCB_LAYER_ID aSecondLayer) const
Calculate the distance (height) between the two given copper layers.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:410
LENGTH_DELAY_CALCULATION * GetLengthCalculation() const
Returns the track length calculator.
Definition board.h:1672
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:553
constexpr void SetOrigin(const Vec &pos)
Definition box2.h:234
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:143
constexpr const Vec & GetOrigin() const
Definition box2.h:207
constexpr const SizeVec & GetSize() const
Definition box2.h:203
constexpr void SetEnd(coord_type x, coord_type y)
Definition box2.h:294
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:308
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition color4d.h:400
wxString GetName() const
Definition drc_rule.h:237
SEVERITY GetSeverity() const
Definition drc_rule.h:256
const MINOPTMAX< int > & GetValue() const
Definition drc_rule.h:204
MINOPTMAX< int > m_Value
Definition drc_rule.h:279
bool GetOption(OPTIONS option) const
Definition drc_rule.h:268
DRC_RULE * GetParentRule() const
Definition drc_rule.h:222
bool IsNull() const
Definition drc_rule.h:197
bool IsImplicit() const
Definition drc_rule.h:145
DRC_IMPLICIT_SOURCE GetImplicitSource() const
Definition drc_rule.h:149
A set of EDA_ITEMs (i.e., without duplicates).
Definition eda_group.h:43
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:270
virtual EDA_GROUP * GetParentGroup() const
Definition eda_item.h:116
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:160
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition eda_item.h:214
std::vector< SHAPE * > MakeEffectiveShapesWithLineEndings(int aLineWidth) const
Make effective geometry for the shape body shortened for line endings plus the line-ending geometry i...
virtual int GetEffectiveWidth() const
Definition eda_shape.h:164
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:118
virtual bool IsVisible() const
Definition eda_text.h:226
void SetPosition(const VECTOR2I &aPos) override
bool IsNetTie() const
Definition footprint.h:567
VECTOR2I GetPosition() const override
Definition footprint.h:436
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition kidialog.h:38
@ KD_WARNING
Definition kidialog.h:43
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
Definition kidialog.cpp:51
int ShowModal() override
Definition kidialog.cpp:89
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
COLOR4D WithAlpha(double aAlpha) const
Return a color with the same color, but the given alpha.
Definition color4d.h:309
double a
Alpha component.
Definition color4d.h:394
COLOR4D Brightened(double aFactor) const
Return a color that is brighter by a given factor, without modifying object.
Definition color4d.h:265
PCB specific render settings.
Definition pcb_painter.h:84
NET_COLOR_MODE GetNetColorMode() const
COLOR4D GetColor(const VIEW_ITEM *aItem, int aLayer) const override
Returns the color that should be used to draw the specific VIEW_ITEM on the specific layer using curr...
std::map< int, KIGFX::COLOR4D > & GetNetColorMap()
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
const std::set< int > & GetHighlightNetCodes() const
Return the netcode of currently highlighted net.
PCB_LAYER_ID GetPrimaryHighContrastLayer() const
Return the board layer which is in high-contrast mode.
Extend VIEW_ITEM by possibility of grouping items into a single object.
Definition view_group.h:39
virtual double ViewGetLOD(int aLayer, const VIEW *aView) const
Return the level of detail (LOD) of the item.
Definition view_item.h:151
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:63
Lightweight class which holds a pad, via, or a routed trace outline.
void SetLine(const SHAPE_LINE_CHAIN &aLine)
Sets the source SHAPE_LINE_CHAIN of this item.
void SetVia(const PCB_VIA *aVia)
Sets the VIA associated with this item.
void SetWidth(const int aWidth)
Sets the line width.
void SetEffectiveNetClass(const NETCLASS *aNetClass)
Sets the effective net class for the item.
void SetLayers(const PCB_LAYER_ID aStart, const PCB_LAYER_ID aEnd=PCB_LAYER_ID::UNDEFINED_LAYER)
Sets the first and last layers associated with this item.
int64_t CalculateLengthForDelay(int64_t aDesiredDelay, const TUNING_PROFILE_GEOMETRY_CONTEXT &aCtx) const
Calculates the length of track required for the given delay in a specific geometry context.
int64_t CalculatePropagationDelayForShapeLineChain(const SHAPE_LINE_CHAIN &aShape, const TUNING_PROFILE_GEOMETRY_CONTEXT &aCtx) const
Gets the propagation delay for the given shape line chain.
int64_t CalculateDelay(std::vector< LENGTH_DELAY_CALCULATION_ITEM > &aItems, PATH_OPTIMISATIONS aOptimisations, const PAD *aStartPad=nullptr, const PAD *aEndPad=nullptr) const
Calculates the electrical propagation delay of the given items.
int64_t CalculateLength(std::vector< LENGTH_DELAY_CALCULATION_ITEM > &aItems, PATH_OPTIMISATIONS aOptimisations, const PAD *aStartPad=nullptr, const PAD *aEndPad=nullptr) const
Calculates the electrical length of the given items.
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition lseq.h:47
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
LSEQ CuStack() const
Return a sequence of copper layers in starting from the front/top and extending to the back/bottom.
Definition lset.cpp:259
T Min() const
Definition minoptmax.h:29
void SetMin(T v)
Definition minoptmax.h:41
T PinnedOpt() const
Definition minoptmax.h:32
bool HasMin() const
Definition minoptmax.h:37
T Opt() const
Definition minoptmax.h:31
A collection of nets and the parameters used to route or test these nets.
Definition netclass.h:43
COLOR4D GetPcbColor(bool aIsForSave=false) const
Definition netclass.h:206
bool HasPcbColor() const
Definition netclass.h:205
Handle the data for a net.
Definition netinfo.h:50
const wxString & GetNetChain() const
Definition netinfo.h:122
const wxString & GetNetname() const
Definition netinfo.h:110
int GetNetCode() const
Definition netinfo.h:104
void SetParent(BOARD *aParent)
Definition netinfo.h:176
void SetNetClass(const std::shared_ptr< NETCLASS > &aNetClass)
static NETINFO_ITEM * OrphanedItem()
NETINFO_ITEM meaning that there was no net assigned for an item, as there was no board storing net li...
Definition netinfo.h:289
NET_SETTINGS stores various net-related settings in a project context.
bool HasEffectiveNetClass(const wxString &aNetName) const
Determines if an effective netclass for the given net name has been cached.
std::shared_ptr< NETCLASS > GetCachedEffectiveNetClass(const wxString &aNetName) const
Returns an already cached effective netclass for the given net name.
void ForEachUniqueLayer(const std::function< void(PCB_LAYER_ID)> &aMethod) const
Runs the given callable for each active unique copper layer in this padstack, meaning F_Cu for MODE::...
void SetUnconnectedLayerMode(UNCONNECTED_LAYER_MODE aMode)
Definition padstack.h:374
UNCONNECTED_LAYER_MODE UnconnectedLayerMode() const
Definition padstack.h:373
@ NORMAL
Shape is the same on all layers.
Definition padstack.h:170
@ CUSTOM
Shapes can be defined on arbitrary layers.
Definition padstack.h:172
@ FRONT_INNER_BACK
Up to three shapes can be defined (F_Cu, inner copper layers, B_Cu)
Definition padstack.h:171
MODE Mode() const
Definition padstack.h:344
static constexpr PCB_LAYER_ID TEMP_ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition padstack.h:176
static constexpr PCB_LAYER_ID INNER_LAYERS
! The layer identifier to use for "inner layers" on top/inner/bottom padstacks
Definition padstack.h:182
Definition pad.h:61
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition pad.h:557
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const override
Return a SHAPE_SEGMENT object representing the pad's hole.
Definition pad.cpp:1328
PAD_ATTRIB GetAttribute() const
Definition pad.h:560
VECTOR2I GetOffset(PCB_LAYER_ID aLayer) const
Definition pad.cpp:838
VECTOR2I GetDrillSize() const
Definition pad.h:320
int GetPadToDieDelay() const
Definition pad.h:581
const PADSTACK & Padstack() const
Definition pad.h:331
bool IsFreePad() const
Definition pad.cpp:610
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition pad.cpp:1757
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(PCB_LAYER_ID aLayer, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition pad.cpp:1240
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition pad.cpp:1253
VECTOR2I ShapePos(PCB_LAYER_ID aLayer) const
Definition pad.cpp:1868
int GetPadToDieLength() const
Definition pad.h:578
DISPLAY_OPTIONS m_Display
void SetMid(const VECTOR2I &aMid)
Definition pcb_track.h:294
const VECTOR2I & GetMid() const
Definition pcb_track.h:295
void GetBoundingHull(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Add two rectangular polygons separately bounding the barcode's symbol and the barcode's text.
Abstract dimension API.
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool aIgnoreLineWidth=false) const override
Convert the item shape to a closed polygon.
The selection tool: currently supports:
PCB_GROUP * GetEnteredGroup()
std::vector< VECTOR2I > GetConnectionPoints() const
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition pcb_shape.h:68
void SetHasSolderMask(bool aVal)
Definition pcb_track.h:121
void SetEnd(const VECTOR2I &aEnd)
Definition pcb_track.h:94
bool HasSolderMask() const
Definition pcb_track.h:122
void SetStart(const VECTOR2I &aStart)
Definition pcb_track.h:97
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
Definition pcb_track.h:124
std::optional< int > GetLocalSolderMaskMargin() const
Definition pcb_track.h:125
const VECTOR2I & GetStart() const
Definition pcb_track.h:98
const VECTOR2I & GetEnd() const
Definition pcb_track.h:95
virtual void SetWidth(int aWidth)
Definition pcb_track.h:91
virtual int GetWidth() const
Definition pcb_track.h:92
bool GetIsFree() const
Check if the via is a free via (as opposed to one created on a track by the router).
Definition pcb_track.h:860
PCB_LAYER_ID BottomLayer() const
VECTOR2I GetPosition() const override
Definition pcb_track.h:599
const PADSTACK & Padstack() const
Definition pcb_track.h:427
void SetFrontTentingMode(TENTING_MODE aMode)
TENTING_MODE GetFrontTentingMode() const
std::optional< int > GetSecondaryDrillSize() const
void SetSecondaryDrillStartLayer(PCB_LAYER_ID aLayer)
std::optional< PAD_DRILL_POST_MACHINING_MODE > GetFrontPostMachining() const
Definition pcb_track.h:724
void SetDrill(int aDrill)
Definition pcb_track.h:798
PCB_LAYER_ID GetSecondaryDrillEndLayer() const
Definition pcb_track.h:834
void SetBackTentingMode(TENTING_MODE aMode)
void SetIsFree(bool aFree=true)
Definition pcb_track.h:861
PCB_LAYER_ID GetPrimaryDrillStartLayer() const
Definition pcb_track.h:718
void SetFrontPostMachining(const std::optional< PAD_DRILL_POST_MACHINING_MODE > &aMode)
void SetSecondaryDrillEndLayer(PCB_LAYER_ID aLayer)
PCB_LAYER_ID GetPrimaryDrillEndLayer() const
Definition pcb_track.h:721
void SetPosition(const VECTOR2I &aPoint) override
Definition pcb_track.h:600
void SetLayerPair(PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer)
For a via m_layer contains the top layer, the other layer is in m_bottomLayer/.
int GetWidth() const override
void SetViaType(VIATYPE aViaType)
Definition pcb_track.h:419
TENTING_MODE GetBackTentingMode() const
PCB_LAYER_ID TopLayer() const
void SetSecondaryDrillSize(const VECTOR2I &aSize)
int GetDrillValue() const
Calculate the drill value for vias (m_drill if > 0, or default drill value for the board).
VIATYPE GetViaType() const
Definition pcb_track.h:418
PCB_LAYER_ID GetSecondaryDrillStartLayer() const
Definition pcb_track.h:831
void SetWidth(int aWidth) override
void LayerPair(PCB_LAYER_ID *top_layer, PCB_LAYER_ID *bottom_layer) const
Return the 2 layers used by the via (the via actually uses all layers between these 2 layers)
int Width() const override
Definition pns_arc.h:88
const SHAPE * Shape(int aLayer) const override
Return the geometrical shape of the item.
Definition pns_arc.h:78
Basic class for a differential pair.
int GuessMostLikelyGap() const
static HOLE * MakeCircularHole(const VECTOR2I &pos, int radius, PNS_LAYER_RANGE aLayers)
Definition pns_hole.cpp:131
bool Empty() const
Definition pns_itemset.h:90
int Size() const
ITEM_SET & ExcludeItem(const ITEM *aItem)
ITEM_SET & FilterKinds(int aKindMask, bool aInvert=false)
std::vector< ITEM * > & Items()
Definition pns_itemset.h:95
Base class for PNS router board items.
Definition pns_item.h:98
BOARD_ITEM * Parent() const
Definition pns_item.h:199
bool IsFreePad() const
Definition pns_item.h:292
virtual ITEM * ParentPadVia() const
Definition pns_item.h:297
virtual const SHAPE * Shape(int aLayer) const
Return the geometrical shape of the item.
Definition pns_item.h:246
const PNS_LAYER_RANGE & Layers() const
Definition pns_item.h:212
virtual NET_HANDLE Net() const
Definition pns_item.h:210
PnsKind Kind() const
Return the type (kind) of the item.
Definition pns_item.h:173
virtual ITEM * Clone() const =0
Return a deep copy of the item.
void SetNet(NET_HANDLE aNet)
Definition pns_item.h:209
BOARD_ITEM * GetSourceItem() const
Definition pns_item.h:202
virtual int Layer() const
Definition pns_item.h:216
void SetLayer(int aLayer)
Definition pns_item.h:215
void SetParent(BOARD_ITEM *aParent)
Definition pns_item.h:191
bool OfKind(int aKindMask) const
Definition pns_item.h:181
bool IsVirtual() const
Definition pns_item.h:299
virtual VECTOR2I Anchor(int n) const
Definition pns_item.h:272
virtual const SHAPE_LINE_CHAIN Hull(int aClearance=0, int aWalkaroundThickness=0, int aLayer=-1) const
Definition pns_item.h:164
virtual BOARD_ITEM * BoardItem() const
Definition pns_item.h:207
bool IsLocked() const
Definition pns_item.h:282
A 2D point on a given set of layers and belonging to a certain net, that links together a number of b...
Definition pns_joint.h:43
const ITEM_SET & CLinks() const
Definition pns_joint.h:312
Represents a track on a PCB, connecting two non-trivial joints (that is, vias, pads,...
Definition pns_line.h:62
const SHAPE_LINE_CHAIN & CLine() const
Definition pns_line.h:146
Keep the router "world" - i.e.
Definition pns_node.h:244
void SetMaxClearance(int aClearance)
Set the worst-case clearance between any pair of items.
Definition pns_node.h:282
const JOINT * FindJoint(const VECTOR2I &aPos, int aLayer, NET_HANDLE aNet) const
Search for a joint at a given position, layer and belonging to given net.
bool Add(std::unique_ptr< SEGMENT > aSegment, bool aAllowRedundant=false)
Add an item to the current node.
Definition pns_node.cpp:747
void SetRuleResolver(RULE_RESOLVER *aFunc)
Assign a clearance resolution function object.
Definition pns_node.h:288
void AddEdgeExclusion(std::unique_ptr< SHAPE > aShape)
Definition pns_node.cpp:791
const ITEM_OWNER * Owner() const
Return the owner of this item, or NULL if there's none.
Definition pns_item.h:72
virtual NET_HANDLE DpCoupledNet(NET_HANDLE aNet)=0
const SEG & Seg() const
void SetEnds(const VECTOR2I &a, const VECTOR2I &b)
int Width() const override
Definition pns_segment.h:96
void SetTrackWidth(int aWidth)
void SetBoardMinTrackWidth(int aWidth)
void SetDiffPairViaGapSameAsTraceGap(bool aEnable)
void SetDiffPairWidth(int aWidth)
void SetDiffPairCopperToHole(int aCopperToHole)
void SetDiffPairWidthSource(const wxString &aSource)
void SetDiffPairGapSource(const wxString &aSource)
void SetDiffPairGap(int aGap)
void SetHoleToHole(int aHoleToHole)
void SetViaDrill(int aDrill)
void SetDiffPairViaGap(int aGap)
void SetDiffPairHoleToHole(int aHoleToHole)
void SetMinClearance(int aClearance)
void SetClearance(int aClearance)
void SetViaDiameter(int aDiameter)
void SetClearanceSource(const wxString &aSource)
void SetWidthSource(const wxString &aSource)
void SetTrackWidthIsExplicit(bool aIsExplicit)
const DIFF_PAIR AssembleDiffPair(SEGMENT *aStart)
bool syncGraphicalItem(PNS::NODE *aWorld, PCB_SHAPE *aItem)
void AddItem(PNS::ITEM *aItem) override
bool syncDimension(PNS::NODE *aWorld, PCB_DIMENSION_BASE *aDimension)
virtual EDA_UNITS GetUnits() const
PNS::DEBUG_DECORATOR * m_debugDecorator
void SetDebugDecorator(PNS::DEBUG_DECORATOR *aDec)
bool syncZone(PNS::NODE *aWorld, ZONE *aZone, SHAPE_POLY_SET *aBoardOutline)
void SetBoard(BOARD *aBoard)
long long int CalculateRoutedPathLength(const PNS::ITEM_SET &aLine, const PNS::SOLID *aStartPad, const PNS::SOLID *aEndPad, const NETCLASS *aNetClass) override
int64_t CalculateRoutedPathDelay(const PNS::ITEM_SET &aLine, const PNS::SOLID *aStartPad, const PNS::SOLID *aEndPad, const NETCLASS *aNetClass) override
void RemoveBoardConnected(const std::vector< const PNS::ITEM * > &aJoined, std::set< PNS::ITEM * > &aItems) const override
Remove from aItems every item the board already joins to one of aJoined through objects the router do...
std::unique_ptr< PNS::ARC > syncArc(PCB_ARC *aArc)
void RemoveItem(PNS::ITEM *aItem) override
bool GetSignalAggregate(PNS::NET_HANDLE aNetP, PNS::NET_HANDLE aNetN, long long &aExtraLength, long long &aExtraDelay) const override
bool IsPNSCopperLayer(int aPNSLayer) const override
int64_t CalculateLengthForDelay(int64_t aDesiredDelay, int aWidth, bool aIsDiffPairCoupled, int aDiffPairCouplingGap, int aPNSLayer, const NETCLASS *aNetClass) override
PNS::RULE_RESOLVER * GetRuleResolver() override
bool syncTextItem(PNS::NODE *aWorld, BOARD_ITEM *aItem, PCB_LAYER_ID aLayer)
bool IsKicadCopperLayer(PCB_LAYER_ID aPcbnewLayer) const
bool inheritTrackWidthAndDpGap(PNS::ITEM *aItem, const VECTOR2I &aStartPosition, int *aInheritedWidth, int *aInheritedGap)
std::vector< std::unique_ptr< PNS::SOLID > > syncPad(PAD *aPad)
void SetStartLayerFromPCBNew(PCB_LAYER_ID aLayer)
bool syncBarcode(PNS::NODE *aWorld, PCB_BARCODE *aBarcode)
bool IsFlashedOnLayer(const PNS::ITEM *aItem, int aLayer) const override
long long GetNetBoardLength(PNS::NET_HANDLE aNet) const override
PCB_LAYER_ID GetBoardLayerFromPNSLayer(int aLayer) const override
BOARD * GetBoard() const
void SyncWorld(PNS::NODE *aWorld) override
int StackupHeight(int aFirstLayer, int aSecondLayer) const override
int64_t CalculateDelayForShapeLineChain(const SHAPE_LINE_CHAIN &aShape, int aWidth, bool aIsDiffPairCoupled, int aDiffPairCouplingGap, int aPNSLayer, const NETCLASS *aNetClass) override
PNS::DEBUG_DECORATOR * GetDebugDecorator() override
std::unique_ptr< PNS::SEGMENT > syncTrack(PCB_TRACK *aTrack)
PNS_PCBNEW_RULE_RESOLVER * m_ruleResolver
PNS::NET_HANDLE GetOrphanedNetHandle() override
std::unique_ptr< PNS::VIA > syncVia(PCB_VIA *aVia)
int GetPNSLayerFromBoardLayer(PCB_LAYER_ID aLayer) const override
PNS_LAYER_RANGE SetLayersFromPCBNew(PCB_LAYER_ID aStartLayer, PCB_LAYER_ID aEndLayer)
std::vector< LENGTH_DELAY_CALCULATION_ITEM > GetLengthDelayCalculationItems(const PNS::ITEM_SET &aLine, const NETCLASS *aNetClass) const
void UpdateItem(PNS::ITEM *aItem) override
bool ImportSizes(PNS::SIZES_SETTINGS &aSizes, PNS::ITEM *aStartItem, PNS::NET_HANDLE aNet, VECTOR2D aStartPosition) override
void SetView(KIGFX::VIEW *aView)
void RemoveItem(PNS::ITEM *aItem) override
void AddItem(PNS::ITEM *aItem) override
void UpdateItem(PNS::ITEM *aItem) override
std::map< PAD *, OFFSET > m_fpOffsets
int GetNetCode(PNS::NET_HANDLE aNet) const override
virtual void SetHostTool(PCB_TOOL_BASE *aTool)
void DisplayItem(const PNS::ITEM *aItem, int aClearance, bool aEdit=false, int aFlags=0) override
std::unique_ptr< BOARD_COMMIT > m_commit
void EraseView() override
void HideItem(PNS::ITEM *aItem) override
void UpdateNet(PNS::NET_HANDLE aNet) override
BOARD_CONNECTED_ITEM * createBoardItem(PNS::ITEM *aItem)
KIGFX::VIEW * m_view
void DisplayPathLine(const SHAPE_LINE_CHAIN &aLine, int aImportance) override
std::unordered_map< BOARD_ITEM *, EDA_GROUP * > m_itemGroups
bool IsItemVisible(const PNS::ITEM *aItem) const override
std::unordered_set< BOARD_ITEM * > m_hiddenItems
EDA_UNITS GetUnits() const override
bool IsAnyLayerVisible(const PNS_LAYER_RANGE &aLayer) const override
PCB_TOOL_BASE * m_tool
bool GetSignalAggregate(PNS::NET_HANDLE aNetP, PNS::NET_HANDLE aNetN, long long &aExtraLength, long long &aExtraDelay) const override
void modifyBoardItem(PNS::ITEM *aItem)
void Commit() override
KIGFX::VIEW_GROUP * m_previewItems
void DisplayRatline(const SHAPE_LINE_CHAIN &aRatline, PNS::NET_HANDLE aNet) override
std::unordered_map< BOARD_ITEM *, std::vector< BOARD_ITEM * > > m_replacementMap
wxString GetNetName(PNS::NET_HANDLE aNet) const override
~PNS_KICAD_IFACE() override
Represent a contiguous set of PCB layers.
int Start() const
bool Overlaps(const PNS_LAYER_RANGE &aOther) const
int End() const
PNS_LAYER_RANGE Intersection(const PNS_LAYER_RANGE &aOther) const
PNS_PCBNEW_DEBUG_DECORATOR(PNS::ROUTER_IFACE *aIface)
void AddPoint(const VECTOR2I &aP, const KIGFX::COLOR4D &aColor, int aSize, const wxString &aName=wxT(""), const SRC_LOCATION_INFO &aSrcLoc=SRC_LOCATION_INFO()) override
void AddShape(const BOX2I &aBox, const KIGFX::COLOR4D &aColor, int aOverrideWidth=0, const wxString &aName=wxT(""), const SRC_LOCATION_INFO &aSrcLoc=SRC_LOCATION_INFO()) override
void AddItem(const PNS::ITEM *aItem, const KIGFX::COLOR4D &aColor, int aOverrideWidth=0, const wxString &aName=wxT(""), const SRC_LOCATION_INFO &aSrcLoc=SRC_LOCATION_INFO()) override
virtual void Message(const wxString &msg, const SRC_LOCATION_INFO &aSrcLoc=SRC_LOCATION_INFO()) override
void SetView(KIGFX::VIEW *aView)
void AddShape(const SHAPE *aShape, const KIGFX::COLOR4D &aColor, int aOverrideWidth=0, const wxString &aName=wxT(""), const SRC_LOCATION_INFO &aSrcLoc=SRC_LOCATION_INFO()) override
std::vector< PNS::ITEM * > m_clonedItems
int NetCode(PNS::NET_HANDLE aNet) override
std::unordered_map< TEMP_CLEARANCE_CACHE_KEY, int > m_tempClearanceCache
PNS_PCBNEW_RULE_RESOLVER(BOARD *aBoard, PNS::ROUTER_IFACE *aRouterIface)
bool IsDrilledHole(const PNS::ITEM *aItem) override
void ClearTemporaryCaches() override
bool QueryConstraint(PNS::CONSTRAINT_TYPE aType, const PNS::ITEM *aItemA, const PNS::ITEM *aItemB, int aLayer, PNS::CONSTRAINT *aConstraint) override
int ClearanceEpsilon() const override
BOARD_ITEM * getBoardItem(const PNS::ITEM *aItem, PCB_LAYER_ID aBoardLayer, int aIdx=0)
bool IsKeepout(const PNS::ITEM *aObstacle, const PNS::ITEM *aItem, bool *aEnforce) override
const SHAPE_LINE_CHAIN & HullCache(const PNS::ITEM *aItem, int aClearance, int aWalkaroundThickness, int aLayer) override
int Clearance(const PNS::ITEM *aA, const PNS::ITEM *aB, bool aUseClearanceEpsilon=true) override
void ClearCacheForItems(std::vector< const PNS::ITEM * > &aItems) override
bool IsNonPlatedSlot(const PNS::ITEM *aItem) override
bool HasUserDefinedPhysicalConstraint() override
std::unordered_map< CLEARANCE_CACHE_KEY, int > m_clearanceCache
int DpNetPolarity(PNS::NET_HANDLE aNet) override
bool IsNetTieExclusion(const PNS::ITEM *aItem, const VECTOR2I &aCollisionPos, const PNS::ITEM *aCollidingItem) override
bool IsInNetTie(const PNS::ITEM *aA) override
PNS::NET_HANDLE DpCoupledNet(PNS::NET_HANDLE aNet) override
bool DpNetPair(const PNS::ITEM *aItem, PNS::NET_HANDLE &aNetP, PNS::NET_HANDLE &aNetN) override
PNS::ROUTER_IFACE * m_routerIface
std::unordered_map< HULL_CACHE_KEY, SHAPE_LINE_CHAIN > m_hullCache
std::optional< bool > m_hasUserPhysicalConstraint
wxString NetName(PNS::NET_HANDLE aNet) override
void SetWidth(int aWidth)
void SetClearance(int aClearance)
static constexpr double PathOverlayDepth
void SetColor(const KIGFX::COLOR4D &aColor)
double GetOriginDepth() const
void SetDepth(double aDepth)
void ShowClearance(bool aEnabled)
Definition seg.h:38
VECTOR2I A
Definition seg.h:45
VECTOR2I::extended_type ecoord
Definition seg.h:40
VECTOR2I B
Definition seg.h:46
const VECTOR2I & GetArcMid() const
Definition shape_arc.h:116
const VECTOR2I & GetP1() const
Definition shape_arc.h:115
const VECTOR2I & GetP0() const
Definition shape_arc.h:114
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
int Width() const
Get the current width of the segments in the chain.
void SetWidth(int aWidth) override
Set the width of all segments in the chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
int SegmentCount() const
Return the number of segments in this line chain.
const std::vector< VECTOR2I > & CPoints() const
void GetTriangle(int index, VECTOR2I &a, VECTOR2I &b, VECTOR2I &c) const
Represent a set of closed polygons.
bool IsTriangulationUpToDate() const
virtual void CacheTriangulation(bool aSimplify=false, const TASK_SUBMITTER &aSubmitter={})
Build a polygon triangulation, needed to draw a polygon on OpenGL and in some other calculations.
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
const TRIANGULATED_POLYGON * TriangulatedPolygon(int aIndex) const
unsigned int TriangulatedPolyCount() const
Return the number of triangulated polygons.
int OutlineCount() const
Return the number of outlines in the set.
SHAPE * Clone() const override
Return a dynamically allocated copy of the shape.
Represent a simple polygon consisting of a zero-thickness closed chain of connected line segments.
void Append(int aX, int aY)
Append a new point at the end of the polygon.
An abstract shape on 2D plane.
Definition shape.h:124
double Distance(const VECTOR2< extended_type > &aVector) const
Compute the distance between two vectors.
Definition vector2d.h:574
static constexpr extended_type ECOORD_MAX
Definition vector2d.h:72
VECTOR2_TRAITS< int32_t >::extended_type extended_type
Definition vector2d.h:69
Handle a list of polygons defining a copper zone.
Definition zone.h:70
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
Definition zone.cpp:1484
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition zone.h:832
bool GetDoNotAllowVias() const
Definition zone.h:843
bool GetDoNotAllowPads() const
Definition zone.h:845
bool GetDoNotAllowTracks() const
Definition zone.h:844
SHAPE_POLY_SET * Outline()
Definition zone.h:421
SHAPE_POLY_SET GetBoardOutline() const
Definition zone.cpp:916
bool GetDoNotAllowFootprints() const
Definition zone.h:846
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition zone.h:133
bool HasKeepoutParametersSet() const
Accessor to determine if any keepout parameters are set.
Definition zone.h:823
DRC_CONSTRAINT_T
Definition drc_rule.h:49
@ VIA_DIAMETER_CONSTRAINT
Definition drc_rule.h:72
@ DIFF_PAIR_GAP_CONSTRAINT
Definition drc_rule.h:78
@ TRACK_WIDTH_CONSTRAINT
Definition drc_rule.h:61
@ EDGE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:55
@ LENGTH_CONSTRAINT
Definition drc_rule.h:73
@ PHYSICAL_HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:83
@ CLEARANCE_CONSTRAINT
Definition drc_rule.h:51
@ MAX_UNCOUPLED_CONSTRAINT
Definition drc_rule.h:79
@ SKEW_CONSTRAINT
Definition drc_rule.h:77
@ HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:53
@ HOLE_SIZE_CONSTRAINT
Definition drc_rule.h:56
@ PHYSICAL_CLEARANCE_CONSTRAINT
Definition drc_rule.h:82
@ HOLE_TO_HOLE_CONSTRAINT
Definition drc_rule.h:54
#define _(s)
@ NO_RECURSE
Definition eda_item.h:52
#define ROUTER_TRANSIENT
transient items that should NOT be cached
#define IN_EDIT
Item currently edited.
EDA_UNITS
Definition eda_units.h:44
static constexpr void hash_combine(std::size_t &seed)
This is a dummy function to take the final case of hash_combine below.
Definition hash.h:28
constexpr PCB_LAYER_ID PCBNEW_LAYER_ID_START
Definition layer_ids.h:170
@ ALWAYS_FLASHED
Always flashed for connectivity.
Definition layer_ids.h:182
@ LAYER_RATSNEST
Definition layer_ids.h:249
@ LAYER_SELECT_OVERLAY
Selected items overlay.
Definition layer_ids.h:276
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ Edge_Cuts
Definition layer_ids.h:108
@ B_Cu
Definition layer_ids.h:61
@ Margin
Definition layer_ids.h:109
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ PCB_LAYER_ID_COUNT
Definition layer_ids.h:167
@ F_Cu
Definition layer_ids.h:60
This file contains miscellaneous commonly used macros and functions.
#define UNIMPLEMENTED_FOR(type)
Definition macros.h:92
@ APPEARANCE
Visibility flag has changed.
Definition view_item.h:49
Push and Shove diff pair dimensions (gap) settings dialog.
CONSTRAINT_TYPE
Definition pns_node.h:52
void * NET_HANDLE
Definition pns_item.h:55
@ MK_LOCKED
Definition pns_item.h:45
STL namespace.
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:102
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:98
@ PTH
Plated through hole pad.
Definition padstack.h:97
@ CONN
Like smd, does not appear on the solder paste layer (default) Note: also has a special attribute in G...
Definition padstack.h:99
@ CASTELLATED
a pad with a castellated through hole
Definition padstack.h:120
BARCODE class definition.
VIATYPE
@ SHOW_WITH_VIA_WHILE_ROUTING_OR_DRAGGING
@ SHOW_WHILE_ROUTING
@ SHOW_WITH_VIA_ALWAYS
@ SHOW_WITH_VIA_WHILE_ROUTING
static bool isEdge(const PNS::ITEM *aItem)
static bool isHole(const PNS::ITEM *aItem)
static bool isCopper(const PNS::ITEM *aItem)
#define ENTERED_GROUP_MAGIC_NUMBER
@ RPT_SEVERITY_IGNORE
#define PNS_SEMI_SOLID
@ SH_SEGMENT
line segment
Definition shape.h:44
@ SH_ARC
circular arc
Definition shape.h:50
@ SH_LINE_CHAIN
line chain (polyline)
Definition shape.h:45
VECTOR2I::extended_type ecoord
const PNS::ITEM * A
bool operator==(const CLEARANCE_CACHE_KEY &other) const
const PNS::ITEM * B
CLEARANCE_CACHE_KEY(const PNS::ITEM *aA, const PNS::ITEM *aB, bool aFlag)
const PNS::ITEM * item
bool operator==(const HULL_CACHE_KEY &other) const
Struct to control which optimisations the length calculation code runs on the given path objects.
TRACK_CLEARANCE_MODE m_TrackClearance
An abstract function object, returning a design rule (clearance, diff pair gap, etc) required between...
Definition pns_node.h:74
wxString m_RuleName
Definition pns_node.h:78
bool m_IsTimeDomain
Definition pns_node.h:81
MINOPTMAX< int > m_Value
Definition pns_node.h:76
CONSTRAINT_TYPE m_Type
Definition pns_node.h:75
bool operator<(const SIDE &o) const
bool operator==(const SIDE &o) const
TEMP_CLEARANCE_CACHE_KEY(const PNS::ITEM *aA, const PNS::ITEM *aB, bool aFlag)
bool operator==(const TEMP_CLEARANCE_CACHE_KEY &o) const
static SIDE makeSide(const PNS::ITEM *aItem)
A data structure to contain basic geometry data which can affect signal propagation calculations.
int64_t DiffPairCouplingGap
The gap between coupled tracks.
const NETCLASS * NetClass
The net class this track belongs to.
int64_t Width
The width (in internal units) of the track.
bool IsDiffPairCoupled
Whether this track or via is a member of a coupled differential pair.
PCB_LAYER_ID Layer
The layer this track is on.
std::size_t operator()(const CLEARANCE_CACHE_KEY &k) const
std::size_t operator()(const HULL_CACHE_KEY &k) const
std::size_t operator()(const TEMP_CLEARANCE_CACHE_KEY &k) const
KIBIS top(path, &reporter)
const SHAPE_LINE_CHAIN chain
arc1_slc SetWidth(0)
wxString result
Test unit parsing edge cases and error handling.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:227
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:70
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:80
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition typeinfo.h:98
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition typeinfo.h:95
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:89
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition typeinfo.h:96
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:85
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition typeinfo.h:100
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:84
@ PCB_REFERENCE_IMAGE_T
class PCB_REFERENCE_IMAGE, bitmap on a layer
Definition typeinfo.h:81
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition typeinfo.h:82
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
Definition typeinfo.h:93
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
Definition typeinfo.h:99
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:87
@ PCB_GRID_ITEM_T
a subgrid placed on a board
Definition typeinfo.h:238
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition typeinfo.h:94
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:79
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:90
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition typeinfo.h:86
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:88
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition typeinfo.h:97
@ PCB_DRILL_CHART_T
class PCB_DRILL_CHART, a live drill chart derived from PCB_TABLE
Definition typeinfo.h:239
Casted dyn_cast(From aObject)
A lightweight dynamic downcast.
Definition typeinfo.h:55
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707