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 (C) 2016-2024 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 along
19 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include <board.h>
25#include <netinfo.h>
26#include <footprint.h>
27#include <pad.h>
28#include <pcb_track.h>
29#include <zone.h>
30#include <pcb_shape.h>
31#include <pcb_generator.h>
32#include <pcb_text.h>
33#include <board_commit.h>
34#include <layer_ids.h>
36#include <confirm.h>
37#include <tools/pcb_tool_base.h>
38#include <tool/tool_manager.h>
40
42#include <pcb_painter.h>
43
44#include <geometry/shape.h>
46#include <geometry/shape_arc.h>
48
49#include <drc/drc_rule.h>
50#include <drc/drc_engine.h>
51
53
54#include <wx/log.h>
55
56#include <memory>
57
58#include <advanced_config.h>
59#include <pcbnew_settings.h>
60#include <macros.h>
61
62#include "pns_kicad_iface.h"
63#include "pns_arc.h"
64#include "pns_sizes_settings.h"
65#include "pns_item.h"
66#include "pns_line.h"
67#include "pns_solid.h"
68#include "pns_segment.h"
69#include "pns_node.h"
70#include "pns_router.h"
71#include "pns_debug_decorator.h"
72#include "router_preview_item.h"
73
75
76
78{
79 const PNS::ITEM* A;
80 const PNS::ITEM* B;
81 bool Flag;
82
83 bool operator==(const CLEARANCE_CACHE_KEY& other) const
84 {
85 return A == other.A && B == other.B && Flag == other.Flag;
86 }
87};
88
89namespace std
90{
91 template <>
93 {
94 std::size_t operator()( const CLEARANCE_CACHE_KEY& k ) const
95 {
96 return hash<const void*>()( k.A ) ^ hash<const void*>()( k.B ) ^ hash<int>()( k.Flag );
97 }
98 };
99}
100
101
103{
104public:
105 PNS_PCBNEW_RULE_RESOLVER( BOARD* aBoard, PNS::ROUTER_IFACE* aRouterIface );
107
108 int Clearance( const PNS::ITEM* aA, const PNS::ITEM* aB,
109 bool aUseClearanceEpsilon = true ) override;
110
112 int DpNetPolarity( PNS::NET_HANDLE aNet ) override;
113 bool DpNetPair( const PNS::ITEM* aItem, PNS::NET_HANDLE& aNetP,
114 PNS::NET_HANDLE& aNetN ) override;
115
116 int NetCode( PNS::NET_HANDLE aNet ) override;
117 wxString NetName( PNS::NET_HANDLE aNet ) override;
118
119 bool IsInNetTie( const PNS::ITEM* aA ) override;
120 bool IsNetTieExclusion( const PNS::ITEM* aItem, const VECTOR2I& aCollisionPos,
121 const PNS::ITEM* aCollidingItem ) override;
122
123 bool IsDrilledHole( const PNS::ITEM* aItem ) override;
124 bool IsNonPlatedSlot( const PNS::ITEM* aItem ) override;
125
130 bool IsKeepout( const PNS::ITEM* aObstacle, const PNS::ITEM* aItem, bool* aEnforce ) override;
131
132 bool QueryConstraint( PNS::CONSTRAINT_TYPE aType, const PNS::ITEM* aItemA,
133 const PNS::ITEM* aItemB, int aLayer,
134 PNS::CONSTRAINT* aConstraint ) override;
135
136 int ClearanceEpsilon() const override { return m_clearanceEpsilon; }
137
138 void ClearCacheForItems( std::vector<const PNS::ITEM*>& aItems ) override;
139 void ClearCaches() override;
140 void ClearTemporaryCaches() override;
141
142private:
143 BOARD_ITEM* getBoardItem( const PNS::ITEM* aItem, int aLayer, int aIdx = 0 );
144
145private:
152
153 std::unordered_map<CLEARANCE_CACHE_KEY, int> m_clearanceCache;
154 std::unordered_map<CLEARANCE_CACHE_KEY, int> m_tempClearanceCache;
155};
156
157
159 PNS::ROUTER_IFACE* aRouterIface ) :
160 m_routerIface( aRouterIface ),
161 m_board( aBoard ),
162 m_dummyTracks{ { aBoard }, { aBoard } },
163 m_dummyArcs{ { aBoard }, { aBoard } },
164 m_dummyVias{ { aBoard }, { aBoard } }
165{
166 for( PCB_TRACK& track : m_dummyTracks )
167 track.SetFlags( ROUTER_TRANSIENT );
168
169 for( PCB_ARC& arc : m_dummyArcs )
170 arc.SetFlags( ROUTER_TRANSIENT );
171
172 for ( PCB_VIA& via : m_dummyVias )
173 via.SetFlags( ROUTER_TRANSIENT );
174
175 if( aBoard )
176 m_clearanceEpsilon = aBoard->GetDesignSettings().GetDRCEpsilon();
177 else
178 m_clearanceEpsilon = 0;
179}
180
181
183{
184}
185
186
188{
189 BOARD_ITEM* item = aA->BoardItem();
190
191 return item && item->GetParentFootprint() && item->GetParentFootprint()->IsNetTie();
192}
193
194
196 const VECTOR2I& aCollisionPos,
197 const PNS::ITEM* aCollidingItem )
198{
199 wxCHECK( aItem && aCollidingItem, false );
200
201 std::shared_ptr<DRC_ENGINE> drcEngine = m_board->GetDesignSettings().m_DRCEngine;
202 BOARD_ITEM* item = aItem->BoardItem();
203 BOARD_ITEM* collidingItem = aCollidingItem->BoardItem();
204
205 FOOTPRINT* collidingFp = collidingItem->GetParentFootprint();
206 FOOTPRINT* itemFp = item ? item->GetParentFootprint() : nullptr;
207
208 if( collidingFp && itemFp && ( collidingFp == itemFp ) && itemFp->IsNetTie() )
209 {
210 // Two items colliding from the same net tie footprint are not checked
211 return true;
212 }
213
214 if( drcEngine )
215 {
216 return drcEngine->IsNetTieExclusion( NetCode( aItem->Net() ), ToLAYER_ID( aItem->Layer() ),
217 aCollisionPos, collidingItem );
218 }
219
220 return false;
221}
222
223
224bool PNS_PCBNEW_RULE_RESOLVER::IsKeepout( const PNS::ITEM* aObstacle, const PNS::ITEM* aItem,
225 bool* aEnforce )
226{
227 auto checkKeepout =
228 []( const ZONE* aKeepout, const BOARD_ITEM* aOther )
229 {
230 if( !aOther )
231 return false;
232
233 if( aKeepout->GetDoNotAllowTracks() && aOther->IsType( { PCB_ARC_T, PCB_TRACE_T } ) )
234 return true;
235
236 if( aKeepout->GetDoNotAllowVias() && aOther->Type() == PCB_VIA_T )
237 return true;
238
239 if( aKeepout->GetDoNotAllowPads() && aOther->Type() == PCB_PAD_T )
240 return true;
241
242 // Incomplete test, but better than nothing:
243 if( aKeepout->GetDoNotAllowFootprints() && aOther->Type() == PCB_PAD_T )
244 {
245 return !aKeepout->GetParentFootprint()
246 || aKeepout->GetParentFootprint() != aOther->GetParentFootprint();
247 }
248
249 return false;
250 };
251
252 if( aObstacle->Parent() && aObstacle->Parent()->Type() == PCB_ZONE_T )
253 {
254 const ZONE* zone = static_cast<ZONE*>( aObstacle->Parent() );
255
256 if( zone->GetIsRuleArea() )
257 {
258 *aEnforce = checkKeepout( zone, getBoardItem( aItem, aObstacle->Layer() ) );
259 return true;
260 }
261 }
262
263 return false;
264}
265
266
267static bool isCopper( const PNS::ITEM* aItem )
268{
269 if ( !aItem )
270 return false;
271
272 const BOARD_ITEM *parent = aItem->Parent();
273
274 return !parent || parent->IsOnCopperLayer();
275}
276
277
278static bool isHole( const PNS::ITEM* aItem )
279{
280 if ( !aItem )
281 return false;
282
283 return aItem->OfKind( PNS::ITEM::HOLE_T );
284}
285
286
287static bool isEdge( const PNS::ITEM* aItem )
288{
289 if ( !aItem )
290 return false;
291
292 const PCB_SHAPE *parent = dynamic_cast<PCB_SHAPE*>( aItem->BoardItem() );
293
294 return parent && ( parent->IsOnLayer( Edge_Cuts ) || parent->IsOnLayer( Margin ) );
295}
296
297
299{
300 if( !isHole( aItem ) )
301 return false;
302
303 if( PAD* pad = dynamic_cast<PAD*>( aItem->Parent() ) )
304 return pad->GetDrillSizeX() && pad->GetDrillSizeX() == pad->GetDrillSizeY();
305
306 // Via holes are (currently) always round
307
308 return true;
309}
310
311
313{
314 if( !isHole( aItem ) )
315 return false;
316
317 BOARD_ITEM* parent = aItem->Parent();
318
319 if( !parent && aItem->ParentPadVia() )
320 parent = aItem->ParentPadVia()->Parent();
321
322 if( parent )
323 {
324 if( parent->Type() == PCB_PAD_T )
325 {
326 PAD* pad = static_cast<PAD*>( parent );
327
328 return pad->GetAttribute() == PAD_ATTRIB::NPTH
329 && pad->GetDrillSizeX() != pad->GetDrillSizeY();
330 }
331
332 // Via holes are (currently) always round, and always plated
333 }
334
335 return false;
336}
337
338
339BOARD_ITEM* PNS_PCBNEW_RULE_RESOLVER::getBoardItem( const PNS::ITEM* aItem, int aLayer, int aIdx )
340{
341 switch( aItem->Kind() )
342 {
343 case PNS::ITEM::ARC_T:
344 m_dummyArcs[aIdx].SetLayer( ToLAYER_ID( aLayer ) );
345 m_dummyArcs[aIdx].SetNet( static_cast<NETINFO_ITEM*>( aItem->Net() ) );
346 m_dummyArcs[aIdx].SetStart( aItem->Anchor( 0 ) );
347 m_dummyArcs[aIdx].SetEnd( aItem->Anchor( 1 ) );
348 return &m_dummyArcs[aIdx];
349
350 case PNS::ITEM::VIA_T:
352 m_dummyVias[aIdx].SetLayer( ToLAYER_ID( aLayer ) );
353 m_dummyVias[aIdx].SetNet( static_cast<NETINFO_ITEM*>( aItem->Net() ) );
354 m_dummyVias[aIdx].SetStart( aItem->Anchor( 0 ) );
355 return &m_dummyVias[aIdx];
356
359 m_dummyTracks[aIdx].SetLayer( ToLAYER_ID( aLayer ) );
360 m_dummyTracks[aIdx].SetNet( static_cast<NETINFO_ITEM*>( aItem->Net() ) );
361 m_dummyTracks[aIdx].SetStart( aItem->Anchor( 0 ) );
362 m_dummyTracks[aIdx].SetEnd( aItem->Anchor( 1 ) );
363 return &m_dummyTracks[aIdx];
364
365 default:
366 return nullptr;
367 }
368}
369
370
372 const PNS::ITEM* aItemA, const PNS::ITEM* aItemB,
373 int aLayer, PNS::CONSTRAINT* aConstraint )
374{
375 std::shared_ptr<DRC_ENGINE> drcEngine = m_board->GetDesignSettings().m_DRCEngine;
376
377 if( !drcEngine )
378 return false;
379
380 DRC_CONSTRAINT_T hostType;
381
382 switch ( aType )
383 {
396 default: return false; // should not happen
397 }
398
399 BOARD_ITEM* parentA = aItemA ? aItemA->BoardItem() : nullptr;
400 BOARD_ITEM* parentB = aItemB ? aItemB->BoardItem() : nullptr;
401 DRC_CONSTRAINT hostConstraint;
402
403 // A track being routed may not have a BOARD_ITEM associated yet.
404 if( aItemA && !parentA )
405 parentA = getBoardItem( aItemA, aLayer, 0 );
406
407 if( aItemB && !parentB )
408 parentB = getBoardItem( aItemB, aLayer, 1 );
409
410 if( parentA )
411 hostConstraint = drcEngine->EvalRules( hostType, parentA, parentB, ToLAYER_ID( aLayer ) );
412
413 if( hostConstraint.IsNull() )
414 return false;
415
416 if( hostConstraint.GetSeverity() == RPT_SEVERITY_IGNORE )
417 {
418 aConstraint->m_Value.SetMin( -1 );
419 aConstraint->m_RuleName = hostConstraint.GetName();
420 aConstraint->m_Type = aType;
421 return true;
422 }
423
424 switch ( aType )
425 {
438 aConstraint->m_Value = hostConstraint.GetValue();
439 aConstraint->m_RuleName = hostConstraint.GetName();
440 aConstraint->m_Type = aType;
441 return true;
442
443 default:
444 return false;
445 }
446}
447
448
449void PNS_PCBNEW_RULE_RESOLVER::ClearCacheForItems( std::vector<const PNS::ITEM*>& aItems )
450{
451 int n_pruned = 0;
452 std::set<const PNS::ITEM*> remainingItems( aItems.begin(), aItems.end() );
453
454/* We need to carefully check both A and B item pointers in the cache against dirty/invalidated
455 items in the set, as the clearance relation is commutative ( CL[a,b] == CL[b,a] ). The code
456 below is a bit ugly, but works in O(n*log(m)) and is run once or twice during ROUTER::Move() call
457 - so I hope it still gets better performance than no cache at all */
458 for( auto it = m_clearanceCache.begin(); it != m_clearanceCache.end(); )
459 {
460 bool dirty = remainingItems.find( it->first.A ) != remainingItems.end();
461 dirty |= remainingItems.find( it->first.B) != remainingItems.end();
462
463 if( dirty )
464 {
465 it = m_clearanceCache.erase( it );
466 n_pruned++;
467 } else
468 it++;
469 }
470#if 0
471 printf("ClearCache : n_pruned %d\n", n_pruned );
472#endif
473}
474
475
477{
478 m_clearanceCache.clear();
479 m_tempClearanceCache.clear();
480}
481
482
484{
485 m_tempClearanceCache.clear();
486}
487
488
490 bool aUseClearanceEpsilon )
491{
492 CLEARANCE_CACHE_KEY key = { aA, aB, aUseClearanceEpsilon };
493
494 // Search cache (used for actual board items)
495 auto it = m_clearanceCache.find( key );
496 if( it != m_clearanceCache.end() )
497 return it->second;
498
499 // Search cache (used for temporary items within an algorithm)
500 it = m_tempClearanceCache.find( key );
501 if( it != m_tempClearanceCache.end() )
502 return it->second;
503
504 PNS::CONSTRAINT constraint;
505 int rv = 0;
506 LAYER_RANGE layers;
507
508 if( !aB )
509 layers = aA->Layers();
510 else if( isEdge( aA ) )
511 layers = aB->Layers();
512 else if( isEdge( aB ) )
513 layers = aA->Layers();
514 else
515 layers = aA->Layers().Intersection( aB->Layers() );
516
517 // Normalize layer range (no -1 magic numbers)
519
520 for( int layer = layers.Start(); layer <= layers.End(); ++layer )
521 {
522 if( IsDrilledHole( aA ) && IsDrilledHole( aB ) )
523 {
524 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_HOLE_TO_HOLE, aA, aB, layer, &constraint ) )
525 {
526 if( constraint.m_Value.Min() > rv )
527 rv = constraint.m_Value.Min();
528 }
529 }
530 else if( isHole( aA ) || isHole( aB ) )
531 {
532 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_HOLE_CLEARANCE, aA, aB, layer, &constraint ) )
533 {
534 if( constraint.m_Value.Min() > rv )
535 rv = constraint.m_Value.Min();
536 }
537 }
538 else if( isCopper( aA ) && ( !aB || isCopper( aB ) ) )
539 {
540 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_CLEARANCE, aA, aB, layer, &constraint ) )
541 {
542 if( constraint.m_Value.Min() > rv )
543 rv = constraint.m_Value.Min();
544 }
545 }
546
547 // No 'else'; non-plated milled holes get both HOLE_CLEARANCE and EDGE_CLEARANCE
548 if( isEdge( aA ) || IsNonPlatedSlot( aA ) || isEdge( aB ) || IsNonPlatedSlot( aB ) )
549 {
550 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_EDGE_CLEARANCE, aA, aB, layer, &constraint ) )
551 {
552 if( constraint.m_Value.Min() > rv )
553 rv = constraint.m_Value.Min();
554 }
555 }
556
557 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_PHYSICAL_CLEARANCE, aA, aB, layer, &constraint ) )
558 {
559 if( constraint.m_Value.Min() > rv )
560 rv = constraint.m_Value.Min();
561 }
562 }
563
564 if( aUseClearanceEpsilon && rv > 0 )
565 rv = std::max( 0, rv - m_clearanceEpsilon );
566
567
568/* It makes no sense to put items that have no owning NODE in the cache - they can be allocated on stack
569 and we can't really invalidate them in the cache when they are destroyed. Probably a better idea would be
570 to use a static unique counter in PNS::ITEM constructor to generate the cache keys. */
571/* However, algorithms DO greatly benefit from using the cache, so ownerless items need to be cached.
572 In order to easily clear those only, a temporary cache is created. If this doesn't seem nice, an alternative
573 is clearing the full cache once it reaches a certain size. Also not pretty, but VERY effective
574 to keep things interactive. */
575 if( aA && aB )
576 {
577 if ( aA->Owner() && aB->Owner() )
578 m_clearanceCache[ key ] = rv;
579 else
580 m_tempClearanceCache[ key ] = rv;
581 }
582
583 return rv;
584}
585
586
587bool PNS_KICAD_IFACE_BASE::inheritTrackWidth( PNS::ITEM* aItem, int* aInheritedWidth )
588{
589 VECTOR2I p;
590
591 assert( aItem->Owner() != nullptr );
592
593 auto tryGetTrackWidth =
594 []( PNS::ITEM* aPnsItem ) -> int
595 {
596 switch( aPnsItem->Kind() )
597 {
598 case PNS::ITEM::SEGMENT_T: return static_cast<PNS::SEGMENT*>( aPnsItem )->Width();
599 case PNS::ITEM::ARC_T: return static_cast<PNS::ARC*>( aPnsItem )->Width();
600 default: return -1;
601 }
602 };
603
604 int itemTrackWidth = tryGetTrackWidth( aItem );
605
606 if( itemTrackWidth > 0 )
607 {
608 *aInheritedWidth = itemTrackWidth;
609 return true;
610 }
611
612 switch( aItem->Kind() )
613 {
614 case PNS::ITEM::VIA_T: p = static_cast<PNS::VIA*>( aItem )->Pos(); break;
615 case PNS::ITEM::SOLID_T: p = static_cast<PNS::SOLID*>( aItem )->Pos(); break;
616 default: return false;
617 }
618
619 const PNS::JOINT* jt = static_cast<const PNS::NODE*>( aItem->Owner() )->FindJoint( p, aItem );
620
621 assert( jt != nullptr );
622
623 int mval = INT_MAX;
624
625 PNS::ITEM_SET linkedSegs( jt->CLinks() );
627
628 for( PNS::ITEM* item : linkedSegs.Items() )
629 {
630 int w = tryGetTrackWidth( item );
631
632 if( w > 0 )
633 mval = std::min( w, mval );
634 }
635
636 if( mval == INT_MAX )
637 return false;
638
639 *aInheritedWidth = mval;
640 return true;
641}
642
643
645 PNS::NET_HANDLE aNet )
646{
648 PNS::CONSTRAINT constraint;
649
650 if( aStartItem && m_startLayer < 0 )
651 m_startLayer = aStartItem->Layer();
652
653 aSizes.SetClearance( bds.m_MinClearance );
654 aSizes.SetMinClearance( bds.m_MinClearance );
655 aSizes.SetClearanceSource( _( "board minimum clearance" ) );
656
658 m_startLayer, &constraint ) )
659 {
660 if( constraint.m_Value.Min() > bds.m_MinClearance )
661 {
662 aSizes.SetClearance( constraint.m_Value.Min() );
663 aSizes.SetClearanceSource( constraint.m_RuleName );
664 }
665 }
666
667 int trackWidth = bds.m_TrackMinWidth;
668 bool found = false;
669 aSizes.SetWidthSource( _( "board minimum track width" ) );
670
671 if( bds.m_UseConnectedTrackWidth && !bds.m_TempOverrideTrackWidth && aStartItem != nullptr )
672 {
673 found = inheritTrackWidth( aStartItem, &trackWidth );
674
675 if( found )
676 aSizes.SetWidthSource( _( "existing track" ) );
677 }
678
679 if( !found && bds.UseNetClassTrack() && aStartItem )
680 {
682 m_startLayer, &constraint ) )
683 {
684 trackWidth = std::max( trackWidth, constraint.m_Value.Opt() );
685 found = true;
686
687 if( trackWidth == constraint.m_Value.Opt() )
688 aSizes.SetWidthSource( constraint.m_RuleName );
689 }
690 }
691
692 if( !found )
693 {
694 trackWidth = std::max( trackWidth, bds.GetCurrentTrackWidth() );
695
696 if( bds.UseNetClassTrack() )
697 aSizes.SetWidthSource( _( "netclass 'Default'" ) );
698 else if( trackWidth == bds.GetCurrentTrackWidth() )
699 aSizes.SetWidthSource( _( "user choice" ) );
700 }
701
702 aSizes.SetTrackWidth( trackWidth );
705
706 int viaDiameter = bds.m_ViasMinSize;
707 int viaDrill = bds.m_MinThroughDrill;
708
709 PNS::VIA dummyVia, coupledVia;
710
711 if( aStartItem )
712 {
713 dummyVia.SetNet( aStartItem->Net() );
714 coupledVia.SetNet( m_ruleResolver->DpCoupledNet( aStartItem->Net() ) );
715 }
716
717 if( bds.UseNetClassVia() && aStartItem ) // netclass value
718 {
720 nullptr, m_startLayer, &constraint ) )
721 {
722 viaDiameter = std::max( viaDiameter, constraint.m_Value.Opt() );
723 }
724
726 nullptr, m_startLayer, &constraint ) )
727 {
728 viaDrill = std::max( viaDrill, constraint.m_Value.Opt() );
729 }
730 }
731 else
732 {
733 viaDiameter = bds.GetCurrentViaSize();
734 viaDrill = bds.GetCurrentViaDrill();
735 }
736
737 aSizes.SetViaDiameter( viaDiameter );
738 aSizes.SetViaDrill( viaDrill );
739
740 int diffPairWidth = bds.m_TrackMinWidth;
741 int diffPairGap = bds.m_MinClearance;
742 int diffPairViaGap = bds.m_MinClearance;
743
744 aSizes.SetDiffPairWidthSource( _( "board minimum track width" ) );
745 aSizes.SetDiffPairGapSource( _( "board minimum clearance" ) );
746
747 found = false;
748
749 // First try to pick up diff pair width from starting track, if enabled
750 if( bds.m_UseConnectedTrackWidth && aStartItem )
751 found = inheritTrackWidth( aStartItem, &diffPairWidth );
752
753 // Next, pick up gap from netclass, and width also if we didn't get a starting width above
754 if( bds.UseNetClassDiffPair() && aStartItem )
755 {
757 nullptr, m_startLayer, &constraint ) )
758 {
759 diffPairWidth = std::max( diffPairWidth, constraint.m_Value.Opt() );
760
761 if( diffPairWidth == constraint.m_Value.Opt() )
762 aSizes.SetDiffPairWidthSource( constraint.m_RuleName );
763 }
764
766 nullptr, m_startLayer, &constraint ) )
767 {
768 diffPairGap = std::max( diffPairGap, constraint.m_Value.Opt() );
769 diffPairViaGap = std::max( diffPairViaGap, constraint.m_Value.Opt() );
770
771 if( diffPairGap == constraint.m_Value.Opt() )
772 aSizes.SetDiffPairGapSource( constraint.m_RuleName );
773 }
774 }
775 else
776 {
777 diffPairWidth = bds.GetCurrentDiffPairWidth();
778 diffPairGap = bds.GetCurrentDiffPairGap();
779 diffPairViaGap = bds.GetCurrentDiffPairViaGap();
780
781 aSizes.SetDiffPairWidthSource( _( "user choice" ) );
782 aSizes.SetDiffPairGapSource( _( "user choice" ) );
783 }
784
785 aSizes.SetDiffPairWidth( diffPairWidth );
786 aSizes.SetDiffPairGap( diffPairGap );
787 aSizes.SetDiffPairViaGap( diffPairViaGap );
788 aSizes.SetDiffPairViaGapSameAsTraceGap( false );
789
790 int holeToHoleMin = bds.m_HoleToHoleMin;
791
793 &dummyVia, UNDEFINED_LAYER, &constraint ) )
794 {
795 holeToHoleMin = constraint.m_Value.Min();
796 }
797
798 aSizes.SetHoleToHole( holeToHoleMin );
799
801 &coupledVia, UNDEFINED_LAYER, &constraint ) )
802 {
803 holeToHoleMin = constraint.m_Value.Min();
804 }
805
806 aSizes.SetDiffPairHoleToHole( holeToHoleMin );
807
808 return true;
809}
810
811
812int PNS_KICAD_IFACE_BASE::StackupHeight( int aFirstLayer, int aSecondLayer ) const
813{
815 return 0;
816
818
819 return stackup.GetLayerDistance( ToLAYER_ID( aFirstLayer ), ToLAYER_ID( aSecondLayer ) );
820}
821
822
824{
825 return m_board->DpCoupledNet( static_cast<NETINFO_ITEM*>( aNet ) );
826}
827
828
830{
831 return m_routerIface->GetNetCode( aNet );
832}
833
834
836{
837 return m_routerIface->GetNetName( aNet );
838}
839
840
842{
843 wxString refName;
844
845 if( NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aNet ) )
846 refName = net->GetNetname();
847
848 wxString dummy1;
849
850 return m_board->MatchDpSuffix( refName, dummy1 );
851}
852
853
855 PNS::NET_HANDLE& aNetN )
856{
857 if( !aItem || !aItem->Net() )
858 return false;
859
860 wxString netNameP = static_cast<NETINFO_ITEM*>( aItem->Net() )->GetNetname();
861 wxString netNameN, netNameCoupled;
862
863 int r = m_board->MatchDpSuffix( netNameP, netNameCoupled );
864
865 if( r == 0 )
866 {
867 return false;
868 }
869 else if( r == 1 )
870 {
871 netNameN = netNameCoupled;
872 }
873 else
874 {
875 netNameN = netNameP;
876 netNameP = netNameCoupled;
877 }
878
879 PNS::NET_HANDLE netInfoP = m_board->FindNet( netNameP );
880 PNS::NET_HANDLE netInfoN = m_board->FindNet( netNameN );
881
882 if( !netInfoP || !netInfoN )
883 return false;
884
885 aNetP = netInfoP;
886 aNetN = netInfoN;
887
888 return true;
889}
890
891
893{
894public:
897 m_view( nullptr ),
898 m_items( nullptr ),
899 m_depth( 0 )
900 {
901 SetView( aView );
902 }
903
905 {
907 delete m_items;
908 }
909
910 void SetView( KIGFX::VIEW* aView )
911 {
912 Clear();
913 delete m_items;
914 m_items = nullptr;
915 m_view = aView;
916
917 if( m_view == nullptr )
918 return;
919
920 if( m_view->GetGAL() )
922
925 m_view->Add( m_items );
926 }
927
928 void AddPoint( const VECTOR2I& aP, const KIGFX::COLOR4D& aColor, int aSize,
929 const wxString& aName = wxT( "" ),
930 const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override
931
932 {
934
935 sh.SetWidth( 10000 );
936
937 sh.Append( aP.x - aSize, aP.y - aSize );
938 sh.Append( aP.x + aSize, aP.y + aSize );
939 sh.Append( aP.x, aP.y );
940 sh.Append( aP.x - aSize, aP.y + aSize );
941 sh.Append( aP.x + aSize, aP.y - aSize );
942
943 AddShape( &sh, aColor, sh.Width(), aName, aSrcLoc );
944 }
945
946 void AddItem( const PNS::ITEM* aItem, const KIGFX::COLOR4D& aColor, int aOverrideWidth = 0,
947 const wxString& aName = wxT( "" ),
948 const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override
949 {
950 if( !m_view || !aItem )
951 return;
952
953 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aItem, m_view );
954
955 pitem->SetColor( aColor.WithAlpha( 0.5 ) );
956 pitem->SetWidth( aOverrideWidth );
957 pitem->SetDepth( nextDepth() );
958
959 m_items->Add( pitem );
961 }
962
963 void AddShape( const BOX2I& aBox, const KIGFX::COLOR4D& aColor, int aOverrideWidth = 0,
964 const wxString& aName = wxT( "" ),
965 const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override
966 {
968 l.SetWidth( aOverrideWidth );
969
970 VECTOR2I o = aBox.GetOrigin();
971 VECTOR2I s = aBox.GetSize();
972
973 l.Append( o );
974 l.Append( o.x + s.x, o.y );
975 l.Append( o.x + s.x, o.y + s.y );
976 l.Append( o.x, o.y + s.y );
977 l.Append( o );
978
979 AddShape( &l, aColor, aOverrideWidth, aName, aSrcLoc );
980 }
981
982 void AddShape( const SHAPE* aShape, const KIGFX::COLOR4D& aColor, int aOverrideWidth = 0,
983 const wxString& aName = wxT( "" ),
984 const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override
985 {
986 if( !m_view || !aShape )
987 return;
988
989 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( *aShape, m_view );
990
991 pitem->SetColor( aColor.WithAlpha( 0.5 ) );
992 pitem->SetWidth( aOverrideWidth );
993 pitem->SetDepth( nextDepth() );
994
995 m_items->Add( pitem );
997 }
998
999 void Clear() override
1000 {
1001 if( m_view && m_items )
1002 {
1003 m_items->FreeItems();
1004 m_view->Update( m_items );
1005
1006 if( m_view->GetGAL() )
1008 }
1009 }
1010
1011private:
1012 double nextDepth()
1013 {
1014 // Use different depths so that the transculent shapes won't overwrite each other.
1015
1016 m_depth++;
1017
1018 if( m_depth >= 0 && m_view->GetGAL() )
1020
1021 return m_depth;
1022 }
1023
1026
1027 double m_depth;
1028};
1029
1030
1032{
1033 return m_debugDecorator;
1034}
1035
1036
1038{
1039 m_ruleResolver = nullptr;
1040 m_board = nullptr;
1041 m_world = nullptr;
1042 m_debugDecorator = nullptr;
1043 m_startLayer = -1;
1044}
1045
1046
1048{
1049 m_tool = nullptr;
1050 m_view = nullptr;
1051 m_previewItems = nullptr;
1052 m_commitFlags = 0;
1053}
1054
1055
1057{
1058}
1059
1060
1062{
1063 delete m_ruleResolver;
1064 delete m_debugDecorator;
1065
1066 if( m_previewItems )
1067 {
1069 delete m_previewItems;
1070 }
1071}
1072
1073
1074std::unique_ptr<PNS::SOLID> PNS_KICAD_IFACE_BASE::syncPad( PAD* aPad )
1075{
1076 LAYER_RANGE layers( 0, MAX_CU_LAYERS - 1 );
1077
1078 // ignore non-copper pads except for those with holes
1079 if( ( aPad->GetLayerSet() & LSET::AllCuMask() ).none() && aPad->GetDrillSize().x == 0 )
1080 return nullptr;
1081
1082 switch( aPad->GetAttribute() )
1083 {
1084 case PAD_ATTRIB::PTH:
1085 case PAD_ATTRIB::NPTH:
1086 break;
1087
1088 case PAD_ATTRIB::CONN:
1089 case PAD_ATTRIB::SMD:
1090 {
1091 LSET lmsk = aPad->GetLayerSet();
1092 bool is_copper = false;
1093
1094 for( int i = 0; i < MAX_CU_LAYERS; i++ )
1095 {
1096 if( lmsk[i] )
1097 {
1098 is_copper = true;
1099
1100 if( aPad->GetAttribute() != PAD_ATTRIB::NPTH )
1101 layers = LAYER_RANGE( i );
1102
1103 break;
1104 }
1105 }
1106
1107 if( !is_copper )
1108 return nullptr;
1109
1110 break;
1111 }
1112
1113 default:
1114 wxLogTrace( wxT( "PNS" ), wxT( "unsupported pad type 0x%x" ), aPad->GetAttribute() );
1115 return nullptr;
1116 }
1117
1118 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
1119
1120 if( aPad->GetAttribute() == PAD_ATTRIB::NPTH )
1121 solid->SetRoutable( false );
1122
1123 solid->SetLayers( layers );
1124 solid->SetNet( aPad->GetNet() );
1125 solid->SetParent( aPad );
1126 solid->SetPadToDie( aPad->GetPadToDieLength() );
1127 solid->SetOrientation( aPad->GetOrientation() );
1128
1129 if( aPad->IsFreePad() )
1130 solid->SetIsFreePad();
1131
1132 VECTOR2I wx_c = aPad->ShapePos();
1133 VECTOR2I offset = aPad->GetOffset();
1134
1135 VECTOR2I c( wx_c.x, wx_c.y );
1136
1137 RotatePoint( offset, aPad->GetOrientation() );
1138
1139 solid->SetPos( VECTOR2I( c.x - offset.x, c.y - offset.y ) );
1140 solid->SetOffset( VECTOR2I( offset.x, offset.y ) );
1141
1142 if( aPad->GetDrillSize().x > 0 )
1143 solid->SetHole( new PNS::HOLE( aPad->GetEffectiveHoleShape()->Clone() ) );
1144
1145 // We generate a single SOLID for a pad, so we have to treat it as ALWAYS_FLASHED and then
1146 // perform layer-specific flashing tests internally.
1147 const std::shared_ptr<SHAPE>& shape = aPad->GetEffectiveShape( UNDEFINED_LAYER,
1148 FLASHING::ALWAYS_FLASHED );
1149
1150 if( shape->HasIndexableSubshapes() && shape->GetIndexableSubshapeCount() == 1 )
1151 {
1152 std::vector<const SHAPE*> subshapes;
1153 shape->GetIndexableSubshapes( subshapes );
1154
1155 solid->SetShape( subshapes[0]->Clone() );
1156 }
1157 // For anything that's not a single shape we use a polygon. Multiple shapes have a tendency
1158 // to confuse the hull generator. https://gitlab.com/kicad/code/kicad/-/issues/15553
1159 else
1160 {
1161 const std::shared_ptr<SHAPE_POLY_SET>& poly = aPad->GetEffectivePolygon( ERROR_OUTSIDE );
1162
1163 if( poly->OutlineCount() )
1164 solid->SetShape( new SHAPE_SIMPLE( poly->Outline( 0 ) ) );
1165 }
1166
1167 return solid;
1168}
1169
1170
1171std::unique_ptr<PNS::SEGMENT> PNS_KICAD_IFACE_BASE::syncTrack( PCB_TRACK* aTrack )
1172{
1173 auto segment = std::make_unique<PNS::SEGMENT>( SEG( aTrack->GetStart(), aTrack->GetEnd() ),
1174 aTrack->GetNet() );
1175
1176 segment->SetWidth( aTrack->GetWidth() );
1177 segment->SetLayers( LAYER_RANGE( aTrack->GetLayer() ) );
1178 segment->SetParent( aTrack );
1179
1180 if( aTrack->IsLocked() )
1181 segment->Mark( PNS::MK_LOCKED );
1182
1183 if( PCB_GENERATOR* generator = dynamic_cast<PCB_GENERATOR*>( aTrack->GetParentGroup() ) )
1184 {
1185 if( !generator->HasFlag( IN_EDIT ) )
1186 segment->Mark( PNS::MK_LOCKED );
1187 }
1188
1189 return segment;
1190}
1191
1192
1193std::unique_ptr<PNS::ARC> PNS_KICAD_IFACE_BASE::syncArc( PCB_ARC* aArc )
1194{
1195 auto arc = std::make_unique<PNS::ARC>( SHAPE_ARC( aArc->GetStart(), aArc->GetMid(),
1196 aArc->GetEnd(), aArc->GetWidth() ),
1197 aArc->GetNet() );
1198
1199 arc->SetLayers( LAYER_RANGE( aArc->GetLayer() ) );
1200 arc->SetParent( aArc );
1201
1202 if( aArc->IsLocked() )
1203 arc->Mark( PNS::MK_LOCKED );
1204
1205 if( PCB_GENERATOR* generator = dynamic_cast<PCB_GENERATOR*>( aArc->GetParentGroup() ) )
1206 {
1207 if( !generator->HasFlag( IN_EDIT ) )
1208 arc->Mark( PNS::MK_LOCKED );
1209 }
1210
1211 return arc;
1212}
1213
1214
1215std::unique_ptr<PNS::VIA> PNS_KICAD_IFACE_BASE::syncVia( PCB_VIA* aVia )
1216{
1217 PCB_LAYER_ID top, bottom;
1218 aVia->LayerPair( &top, &bottom );
1219
1220 auto via = std::make_unique<PNS::VIA>( aVia->GetPosition(),
1221 LAYER_RANGE( aVia->TopLayer(), aVia->BottomLayer() ),
1222 aVia->GetWidth(),
1223 aVia->GetDrillValue(),
1224 aVia->GetNet(),
1225 aVia->GetViaType() );
1226
1227 via->SetParent( aVia );
1228
1229 if( aVia->IsLocked() )
1230 via->Mark( PNS::MK_LOCKED );
1231
1232 if( PCB_GENERATOR* generator = dynamic_cast<PCB_GENERATOR*>( aVia->GetParentGroup() ) )
1233 {
1234 if( !generator->HasFlag( IN_EDIT ) )
1235 via->Mark( PNS::MK_LOCKED );
1236 }
1237
1238 via->SetIsFree( aVia->GetIsFree() );
1239 via->SetHole( PNS::HOLE::MakeCircularHole( aVia->GetPosition(), aVia->GetDrillValue() / 2 ) );
1240
1241 return via;
1242}
1243
1244
1245bool PNS_KICAD_IFACE_BASE::syncZone( PNS::NODE* aWorld, ZONE* aZone, SHAPE_POLY_SET* aBoardOutline )
1246{
1247 static wxString msg;
1248 SHAPE_POLY_SET* poly;
1249
1250 if( !aZone->GetIsRuleArea() )
1251 return false;
1252
1253 LSET layers = aZone->GetLayerSet();
1254
1255 poly = aZone->Outline();
1256 poly->CacheTriangulation( false );
1257
1258 if( !poly->IsTriangulationUpToDate() )
1259 {
1260 UNITS_PROVIDER unitsProvider( pcbIUScale, GetUnits() );
1261 msg.Printf( _( "%s is malformed." ), aZone->GetItemDescription( &unitsProvider ) );
1262
1263 KIDIALOG dlg( nullptr, msg, KIDIALOG::KD_WARNING );
1264 dlg.ShowDetailedText( _( "This zone cannot be handled by the router.\n"
1265 "Please verify it is not a self-intersecting polygon." ) );
1266 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
1267 dlg.ShowModal();
1268
1269 return false;
1270 }
1271
1272 for( int layer = F_Cu; layer <= B_Cu; layer++ )
1273 {
1274 if( !layers[ layer ] )
1275 continue;
1276
1277 for( int outline = 0; outline < poly->OutlineCount(); outline++ )
1278 {
1279 const SHAPE_POLY_SET::TRIANGULATED_POLYGON* tri = poly->TriangulatedPolygon( outline );
1280
1281 for( size_t i = 0; i < tri->GetTriangleCount(); i++)
1282 {
1283 VECTOR2I a, b, c;
1284 tri->GetTriangle( i, a, b, c );
1285 SHAPE_SIMPLE* triShape = new SHAPE_SIMPLE;
1286
1287 triShape->Append( a );
1288 triShape->Append( b );
1289 triShape->Append( c );
1290
1291 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
1292
1293 solid->SetLayer( layer );
1294 solid->SetNet( nullptr );
1295 solid->SetParent( aZone );
1296 solid->SetShape( triShape );
1297 solid->SetIsCompoundShapePrimitive();
1298 solid->SetRoutable( false );
1299
1300 aWorld->Add( std::move( solid ) );
1301 }
1302 }
1303 }
1304
1305 return true;
1306}
1307
1308
1310{
1311 if( !IsCopperLayer( aLayer ) )
1312 return false;
1313
1314 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
1315 SHAPE_SIMPLE* shape = new SHAPE_SIMPLE;
1316
1317 solid->SetLayer( aLayer );
1318 solid->SetNet( nullptr );
1319 solid->SetParent( aText );
1320 solid->SetShape( shape ); // takes ownership
1321 solid->SetRoutable( false );
1322
1323 SHAPE_POLY_SET cornerBuffer;
1324
1325 aText->TransformShapeToPolygon( cornerBuffer, aText->GetLayer(), 0,
1327
1328 if( !cornerBuffer.OutlineCount() )
1329 return false;
1330
1331 for( const VECTOR2I& pt : cornerBuffer.Outline( 0 ).CPoints() )
1332 shape->Append( pt );
1333
1334 aWorld->Add( std::move( solid ) );
1335
1336 return true;
1337}
1338
1339
1341{
1342 if( aItem->GetLayer() == Edge_Cuts
1343 || aItem->GetLayer() == Margin
1344 || IsCopperLayer( aItem->GetLayer() ) )
1345 {
1346 std::vector<SHAPE*> shapes = aItem->MakeEffectiveShapes();
1347
1348 for( SHAPE* shape : shapes )
1349 {
1350 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
1351
1352 if( aItem->GetLayer() == Edge_Cuts || aItem->GetLayer() == Margin )
1353 solid->SetLayers( LAYER_RANGE( F_Cu, B_Cu ) );
1354 else
1355 solid->SetLayer( aItem->GetLayer() );
1356
1357 if( aItem->GetLayer() == Edge_Cuts )
1358 {
1359 switch( shape->Type() )
1360 {
1361 case SH_SEGMENT: static_cast<SHAPE_SEGMENT*>( shape )->SetWidth( 0 ); break;
1362 case SH_ARC: static_cast<SHAPE_ARC*>( shape )->SetWidth( 0 ); break;
1363 case SH_LINE_CHAIN: static_cast<SHAPE_LINE_CHAIN*>( shape )->SetWidth( 0 ); break;
1364 default: /* remaining shapes don't have width */ break;
1365 }
1366 }
1367
1368 solid->SetAnchorPoints( aItem->GetConnectionPoints() );
1369 solid->SetNet( aItem->GetNet() );
1370 solid->SetParent( aItem );
1371 solid->SetShape( shape ); // takes ownership
1372
1373 if( shapes.size() > 1 )
1374 solid->SetIsCompoundShapePrimitive();
1375
1376 aWorld->Add( std::move( solid ) );
1377 }
1378
1379 return true;
1380 }
1381
1382 return false;
1383}
1384
1385
1387{
1388 m_board = aBoard;
1389 wxLogTrace( wxT( "PNS" ), wxT( "m_board = %p" ), m_board );
1390}
1391
1392
1394{
1395 if( !m_view )
1396 return false;
1397
1398 for( int i = aLayer.Start(); i <= aLayer.End(); i++ )
1399 {
1400 if( m_view->IsLayerVisible( i ) )
1401 return true;
1402 }
1403
1404 return false;
1405}
1406
1407
1408bool PNS_KICAD_IFACE_BASE::IsFlashedOnLayer( const PNS::ITEM* aItem, int aLayer ) const
1409{
1411 if( aLayer < 0 )
1412 return true;
1413
1414 if( aItem->Parent() )
1415 {
1416 switch( aItem->Parent()->Type() )
1417 {
1418 case PCB_VIA_T:
1419 {
1420 const PCB_VIA* via = static_cast<const PCB_VIA*>( aItem->Parent() );
1421
1422 return via->FlashLayer( ToLAYER_ID( aLayer ) );
1423 }
1424
1425 case PCB_PAD_T:
1426 {
1427 const PAD* pad = static_cast<const PAD*>( aItem->Parent() );
1428
1429 return pad->FlashLayer( ToLAYER_ID( aLayer ) );
1430 }
1431
1432 default:
1433 break;
1434 }
1435 }
1436
1437 return aItem->Layers().Overlaps( aLayer );
1438}
1439
1440
1442 const LAYER_RANGE& aLayer ) const
1443{
1444 LAYER_RANGE test = aItem->Layers().Intersection( aLayer );
1445
1446 if( aItem->Parent() )
1447 {
1448 switch( aItem->Parent()->Type() )
1449 {
1450 case PCB_VIA_T:
1451 {
1452 const PCB_VIA* via = static_cast<const PCB_VIA*>( aItem->Parent() );
1453
1454 for( int layer = test.Start(); layer <= test.End(); ++layer )
1455 {
1456 if( via->FlashLayer( ToLAYER_ID( layer ) ) )
1457 return true;
1458 }
1459
1460 return false;
1461 }
1462
1463 case PCB_PAD_T:
1464 {
1465 const PAD* pad = static_cast<const PAD*>( aItem->Parent() );
1466
1467 for( int layer = test.Start(); layer <= test.End(); ++layer )
1468 {
1469 if( pad->FlashLayer( ToLAYER_ID( layer ) ) )
1470 return true;
1471 }
1472
1473 return false;
1474 }
1475
1476 default:
1477 break;
1478 }
1479 }
1480
1481 return test.Start() <= test.End();
1482}
1483
1484
1486{
1487 // by default, all items are visible (new ones created by the router have parent == NULL
1488 // as they have not been committed yet to the BOARD)
1489 if( !m_view || !aItem->Parent() )
1490 return true;
1491
1492 BOARD_ITEM* item = aItem->Parent();
1493 bool isOnVisibleLayer = true;
1494 RENDER_SETTINGS* settings = m_view->GetPainter()->GetSettings();
1495
1496 if( settings->GetHighContrast() )
1497 isOnVisibleLayer = item->IsOnLayer( settings->GetPrimaryHighContrastLayer() );
1498
1499 if( m_view->IsVisible( item ) && isOnVisibleLayer )
1500 {
1501 for( PCB_LAYER_ID layer : item->GetLayerSet().Seq() )
1502 {
1503 if( item->ViewGetLOD( layer, m_view ) < m_view->GetScale() )
1504 return true;
1505 }
1506 }
1507
1508 // Items hidden in the router are not hidden on the board
1509 if( m_hiddenItems.find( item ) != m_hiddenItems.end() )
1510 return true;
1511
1512 return false;
1513}
1514
1515
1517{
1518 if( !m_board )
1519 {
1520 wxLogTrace( wxT( "PNS" ), wxT( "No board attached, aborting sync." ) );
1521 return;
1522 }
1523
1524 int worstClearance = m_board->GetMaxClearanceValue();
1525
1526 m_world = aWorld;
1527
1528 for( BOARD_ITEM* gitem : m_board->Drawings() )
1529 {
1530 if ( gitem->Type() == PCB_SHAPE_T || gitem->Type() == PCB_TEXTBOX_T )
1531 {
1532 syncGraphicalItem( aWorld, static_cast<PCB_SHAPE*>( gitem ) );
1533 }
1534 else if( gitem->Type() == PCB_TEXT_T )
1535 {
1536 syncTextItem( aWorld, static_cast<PCB_TEXT*>( gitem ), gitem->GetLayer() );
1537 }
1538 }
1539
1540 SHAPE_POLY_SET buffer;
1541 SHAPE_POLY_SET* boardOutline = nullptr;
1542
1543 if( m_board->GetBoardPolygonOutlines( buffer ) )
1544 boardOutline = &buffer;
1545
1546 for( ZONE* zone : m_board->Zones() )
1547 {
1548 syncZone( aWorld, zone, boardOutline );
1549 }
1550
1551 for( FOOTPRINT* footprint : m_board->Footprints() )
1552 {
1553 for( PAD* pad : footprint->Pads() )
1554 {
1555 if( std::unique_ptr<PNS::SOLID> solid = syncPad( pad ) )
1556 aWorld->Add( std::move( solid ) );
1557
1558 std::optional<int> clearanceOverride = pad->GetClearanceOverrides( nullptr );
1559
1560 if( clearanceOverride.has_value() )
1561 worstClearance = std::max( worstClearance, clearanceOverride.value() );
1562
1563 if( pad->GetProperty() == PAD_PROP::CASTELLATED )
1564 {
1565 std::unique_ptr<SHAPE> hole;
1566 hole.reset( pad->GetEffectiveHoleShape()->Clone() );
1567 aWorld->AddEdgeExclusion( std::move( hole ) );
1568 }
1569 }
1570
1571 syncTextItem( aWorld, &footprint->Reference(), footprint->Reference().GetLayer() );
1572 syncTextItem( aWorld, &footprint->Value(), footprint->Value().GetLayer() );
1573
1574 for( ZONE* zone : footprint->Zones() )
1575 syncZone( aWorld, zone, boardOutline );
1576
1577 for( PCB_FIELD* field : footprint->Fields() )
1578 syncTextItem( aWorld, static_cast<PCB_TEXT*>( field ), field->GetLayer() );
1579
1580 for( BOARD_ITEM* item : footprint->GraphicalItems() )
1581 {
1582 if( item->Type() == PCB_SHAPE_T || item->Type() == PCB_TEXTBOX_T )
1583 {
1584 syncGraphicalItem( aWorld, static_cast<PCB_SHAPE*>( item ) );
1585 }
1586 else if( item->Type() == PCB_TEXT_T )
1587 {
1588 syncTextItem( aWorld, static_cast<PCB_TEXT*>( item ), item->GetLayer() );
1589 }
1590 }
1591 }
1592
1593 for( PCB_TRACK* t : m_board->Tracks() )
1594 {
1595 KICAD_T type = t->Type();
1596
1597 if( type == PCB_TRACE_T )
1598 {
1599 if( std::unique_ptr<PNS::SEGMENT> segment = syncTrack( t ) )
1600 aWorld->Add( std::move( segment ) );
1601 }
1602 else if( type == PCB_ARC_T )
1603 {
1604 if( std::unique_ptr<PNS::ARC> arc = syncArc( static_cast<PCB_ARC*>( t ) ) )
1605 aWorld->Add( std::move( arc ) );
1606 }
1607 else if( type == PCB_VIA_T )
1608 {
1609 if( std::unique_ptr<PNS::VIA> via = syncVia( static_cast<PCB_VIA*>( t ) ) )
1610 aWorld->Add( std::move( via ) );
1611 }
1612 }
1613
1614 // NB: if this were ever to become a long-lived object we would need to dirty its
1615 // clearance cache here....
1616 delete m_ruleResolver;
1618
1620 aWorld->SetMaxClearance( worstClearance + m_ruleResolver->ClearanceEpsilon() );
1621}
1622
1623
1625{
1626 for( BOARD_ITEM* item : m_hiddenItems )
1627 m_view->SetVisible( item, true );
1628
1629 m_hiddenItems.clear();
1630
1631 if( m_previewItems )
1632 {
1635 }
1636
1637 if( m_debugDecorator )
1639}
1640
1641
1643{
1644 m_debugDecorator = aDec;
1645}
1646
1647
1648void PNS_KICAD_IFACE::DisplayItem( const PNS::ITEM* aItem, int aClearance, bool aEdit, int aFlags )
1649{
1650 if( aItem->IsVirtual() )
1651 return;
1652
1653 if( ZONE* zone = dynamic_cast<ZONE*>( aItem->Parent() ) )
1654 {
1655 if( zone->GetIsRuleArea() )
1656 aFlags |= PNS_SEMI_SOLID;
1657 }
1658
1659 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aItem, m_view, aFlags );
1660
1661 // Note: SEGMENT_T is used for placed tracks; LINE_T is used for the routing head
1663 static int tracksOrVias = tracks | PNS::ITEM::VIA_T;
1664
1665 if( aClearance >= 0 )
1666 {
1667 pitem->SetClearance( aClearance );
1668
1669 auto* settings = static_cast<PCBNEW_SETTINGS*>( m_tool->GetManager()->GetSettings() );
1670
1671 switch( settings->m_Display.m_TrackClearance )
1672 {
1675 pitem->ShowClearance( aItem->OfKind( tracksOrVias ) );
1676 break;
1677
1679 pitem->ShowClearance( aItem->OfKind( tracksOrVias ) && !aEdit );
1680 break;
1681
1682 case SHOW_WHILE_ROUTING:
1683 pitem->ShowClearance( aItem->OfKind( tracks ) && !aEdit );
1684 break;
1685
1686 default:
1687 pitem->ShowClearance( false );
1688 break;
1689 }
1690 }
1691
1692 m_previewItems->Add( pitem );
1694}
1695
1696
1697void PNS_KICAD_IFACE::DisplayPathLine( const SHAPE_LINE_CHAIN& aLine, int aImportance )
1698{
1699 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aLine, m_view );
1701
1702 COLOR4D color;
1703
1704 if( aImportance >= 1 )
1705 color = COLOR4D( 1.0, 1.0, 0.0, 0.6 );
1706 else if( aImportance == 0 )
1707 color = COLOR4D( 0.7, 0.7, 0.7, 0.6 );
1708
1709 pitem->SetColor( color );
1710
1711 m_previewItems->Add( pitem );
1713}
1714
1715
1717{
1718 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aRatline, m_view );
1719
1720 KIGFX::RENDER_SETTINGS* renderSettings = m_view->GetPainter()->GetSettings();
1721 KIGFX::PCB_RENDER_SETTINGS* rs = static_cast<KIGFX::PCB_RENDER_SETTINGS*>( renderSettings );
1722 bool colorByNet = rs->GetNetColorMode() != NET_COLOR_MODE::OFF;
1723 COLOR4D defaultColor = rs->GetColor( nullptr, LAYER_RATSNEST );
1724 COLOR4D color = defaultColor;
1725
1726 std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_board->GetConnectivity();
1727 std::set<int> highlightedNets = rs->GetHighlightNetCodes();
1728 std::map<int, KIGFX::COLOR4D>& netColors = rs->GetNetColorMap();
1729 std::map<wxString, KIGFX::COLOR4D>& ncColors = rs->GetNetclassColorMap();
1730 const std::map<int, wxString>& ncMap = connectivity->GetNetclassMap();
1731 int netCode = -1;
1732
1733 if( NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aNet ) )
1734 netCode = net->GetNetCode();
1735
1736 if( colorByNet && netColors.count( netCode ) )
1737 color = netColors.at( netCode );
1738 else if( colorByNet && ncMap.count( netCode ) && ncColors.count( ncMap.at( netCode ) ) )
1739 color = ncColors.at( ncMap.at( netCode ) );
1740 else
1741 color = defaultColor;
1742
1743 if( color == COLOR4D::UNSPECIFIED )
1744 color = defaultColor;
1745
1746 pitem->SetColor( color.Brightened( 0.5 ).WithAlpha( std::min( 1.0, color.a + 0.4 ) ) );
1747
1748 m_previewItems->Add( pitem );
1750}
1751
1752
1754{
1755 BOARD_ITEM* parent = aItem->Parent();
1756
1757 if( parent )
1758 {
1759 if( m_view->IsVisible( parent ) )
1760 m_hiddenItems.insert( parent );
1761
1762 m_view->SetVisible( parent, false );
1763 m_view->Update( parent, KIGFX::APPEARANCE );
1764
1765 for( ZONE* td : m_board->Zones() )
1766 {
1767 if( td->IsTeardropArea()
1768 && td->GetBoundingBox().Intersects( aItem->Parent()->GetBoundingBox() )
1769 && td->Outline()->Collide( aItem->Shape() ) )
1770 {
1771 m_view->SetVisible( td, false );
1773 }
1774 }
1775 }
1776}
1777
1778
1780{
1781}
1782
1783
1785{
1786 BOARD_ITEM* parent = aItem->Parent();
1787
1788 if( aItem->OfKind( PNS::ITEM::SOLID_T ) )
1789 {
1790 PAD* pad = static_cast<PAD*>( parent );
1791 VECTOR2I pos = static_cast<PNS::SOLID*>( aItem )->Pos();
1792
1793 m_fpOffsets[ pad ].p_old = pos;
1794 return;
1795 }
1796
1797 if( parent )
1798 {
1799 m_commit->Remove( parent );
1800 }
1801}
1802
1803
1805{
1806}
1807
1808
1810{
1811 BOARD_ITEM* board_item = aItem->Parent();
1812
1813 switch( aItem->Kind() )
1814 {
1815 case PNS::ITEM::ARC_T:
1816 {
1817 PNS::ARC* arc = static_cast<PNS::ARC*>( aItem );
1818 PCB_ARC* arc_board = static_cast<PCB_ARC*>( board_item );
1819 const SHAPE_ARC* arc_shape = static_cast<const SHAPE_ARC*>( arc->Shape() );
1820
1821 m_commit->Modify( arc_board );
1822
1823 arc_board->SetStart( VECTOR2I( arc_shape->GetP0() ) );
1824 arc_board->SetEnd( VECTOR2I( arc_shape->GetP1() ) );
1825 arc_board->SetMid( VECTOR2I( arc_shape->GetArcMid() ) );
1826 arc_board->SetWidth( arc->Width() );
1827 break;
1828 }
1829
1831 {
1832 PNS::SEGMENT* seg = static_cast<PNS::SEGMENT*>( aItem );
1833 PCB_TRACK* track = static_cast<PCB_TRACK*>( board_item );
1834 const SEG& s = seg->Seg();
1835
1836 m_commit->Modify( track );
1837
1838 track->SetStart( VECTOR2I( s.A.x, s.A.y ) );
1839 track->SetEnd( VECTOR2I( s.B.x, s.B.y ) );
1840 track->SetWidth( seg->Width() );
1841 break;
1842 }
1843
1844 case PNS::ITEM::VIA_T:
1845 {
1846 PCB_VIA* via_board = static_cast<PCB_VIA*>( board_item );
1847 PNS::VIA* via = static_cast<PNS::VIA*>( aItem );
1848
1849 m_commit->Modify( via_board );
1850
1851 via_board->SetPosition( VECTOR2I( via->Pos().x, via->Pos().y ) );
1852 via_board->SetWidth( via->Diameter() );
1853 via_board->SetDrill( via->Drill() );
1854 via_board->SetNet( static_cast<NETINFO_ITEM*>( via->Net() ) );
1855 via_board->SetViaType( via->ViaType() ); // MUST be before SetLayerPair()
1856 via_board->SetIsFree( via->IsFree() );
1857 via_board->SetLayerPair( ToLAYER_ID( via->Layers().Start() ),
1858 ToLAYER_ID( via->Layers().End() ) );
1859 break;
1860 }
1861
1862 case PNS::ITEM::SOLID_T:
1863 {
1864 PAD* pad = static_cast<PAD*>( aItem->Parent() );
1865 VECTOR2I pos = static_cast<PNS::SOLID*>( aItem )->Pos();
1866
1867 // Don't add to commit; we'll add the parent footprints when processing the m_fpOffsets
1868
1869 m_fpOffsets[pad].p_old = pad->GetPosition();
1870 m_fpOffsets[pad].p_new = pos;
1871 break;
1872 }
1873
1874 default:
1875 m_commit->Modify( aItem->Parent() );
1876 break;
1877 }
1878}
1879
1880
1882{
1883 modifyBoardItem( aItem );
1884}
1885
1886
1888{
1889}
1890
1891
1893{
1894 BOARD_CONNECTED_ITEM* newBI = nullptr;
1895 auto net = static_cast<NETINFO_ITEM*>( aItem->Net() );
1896
1897 switch( aItem->Kind() )
1898 {
1899 case PNS::ITEM::ARC_T:
1900 {
1901 PNS::ARC* arc = static_cast<PNS::ARC*>( aItem );
1902 PCB_ARC* new_arc = new PCB_ARC( m_board, static_cast<const SHAPE_ARC*>( arc->Shape() ) );
1903 new_arc->SetWidth( arc->Width() );
1904 new_arc->SetLayer( ToLAYER_ID( arc->Layers().Start() ) );
1905 new_arc->SetNet( net );
1906 newBI = new_arc;
1907 break;
1908 }
1909
1911 {
1912 PNS::SEGMENT* seg = static_cast<PNS::SEGMENT*>( aItem );
1913 PCB_TRACK* track = new PCB_TRACK( m_board );
1914 const SEG& s = seg->Seg();
1915 track->SetStart( VECTOR2I( s.A.x, s.A.y ) );
1916 track->SetEnd( VECTOR2I( s.B.x, s.B.y ) );
1917 track->SetWidth( seg->Width() );
1918 track->SetLayer( ToLAYER_ID( seg->Layers().Start() ) );
1919 track->SetNet( net );
1920 newBI = track;
1921 break;
1922 }
1923
1924 case PNS::ITEM::VIA_T:
1925 {
1926 PCB_VIA* via_board = new PCB_VIA( m_board );
1927 PNS::VIA* via = static_cast<PNS::VIA*>( aItem );
1928 via_board->SetPosition( VECTOR2I( via->Pos().x, via->Pos().y ) );
1929 via_board->SetWidth( via->Diameter() );
1930 via_board->SetDrill( via->Drill() );
1931 via_board->SetNet( net );
1932 via_board->SetViaType( via->ViaType() ); // MUST be before SetLayerPair()
1933 via_board->SetIsFree( via->IsFree() );
1934 via_board->SetLayerPair( ToLAYER_ID( via->Layers().Start() ),
1935 ToLAYER_ID( via->Layers().End() ) );
1936 newBI = via_board;
1937 break;
1938 }
1939
1940 case PNS::ITEM::SOLID_T:
1941 {
1942 PAD* pad = static_cast<PAD*>( aItem->Parent() );
1943 VECTOR2I pos = static_cast<PNS::SOLID*>( aItem )->Pos();
1944
1945 m_fpOffsets[pad].p_new = pos;
1946 return nullptr;
1947 }
1948
1949 default:
1950 return nullptr;
1951 }
1952
1953 if( net->GetNetCode() <= 0 )
1954 {
1955 NETINFO_ITEM* newNetInfo = newBI->GetNet();
1956 newNetInfo->SetParent( m_board );
1957 newNetInfo->SetNetClass( m_board->GetDesignSettings().m_NetSettings->m_DefaultNetClass );
1958 }
1959
1960 return newBI;
1961}
1962
1963
1965{
1966 BOARD_CONNECTED_ITEM* boardItem = createBoardItem( aItem );
1967
1968 if( boardItem )
1969 {
1970 aItem->SetParent( boardItem );
1971 boardItem->ClearFlags();
1972
1973 m_commit->Add( boardItem );
1974 }
1975}
1976
1977
1979{
1980 std::set<FOOTPRINT*> processedFootprints;
1981
1982 EraseView();
1983
1984 for( const auto& [ pad, fpOffset ] : m_fpOffsets )
1985 {
1986 VECTOR2I offset = fpOffset.p_new - fpOffset.p_old;
1987 FOOTPRINT* footprint = pad->GetParentFootprint();
1988 VECTOR2I p_orig = footprint->GetPosition();
1989 VECTOR2I p_new = p_orig + offset;
1990
1991 if( processedFootprints.find( footprint ) != processedFootprints.end() )
1992 continue;
1993
1994 processedFootprints.insert( footprint );
1995 m_commit->Modify( footprint );
1996 footprint->SetPosition( p_new );
1997 }
1998
1999 m_fpOffsets.clear();
2000
2001 m_commit->Push( _( "Routing" ), m_commitFlags );
2002 m_commit = std::make_unique<BOARD_COMMIT>( m_tool );
2003}
2004
2005
2007{
2008 return static_cast<EDA_UNITS>( m_tool->GetManager()->GetSettings()->m_System.units );
2009}
2010
2011
2013{
2014 wxLogTrace( wxT( "PNS" ), wxT( "SetView %p" ), aView );
2015
2016 if( m_previewItems )
2017 {
2019 delete m_previewItems;
2020 }
2021
2022 m_view = aView;
2025
2026 if(m_view)
2028
2029 delete m_debugDecorator;
2030
2031 auto dec = new PNS_PCBNEW_DEBUG_DECORATOR();
2032 m_debugDecorator = dec;
2033
2034 dec->SetDebugEnabled( ADVANCED_CFG::GetCfg().m_ShowRouterDebugGraphics );
2035
2036 if( ADVANCED_CFG::GetCfg().m_ShowRouterDebugGraphics )
2037 dec->SetView( m_view );
2038}
2039
2040
2042{
2043 if( aNet )
2044 return static_cast<NETINFO_ITEM*>( aNet )->GetNetCode();
2045 else
2046 return -1;
2047}
2048
2049
2051{
2052 if( aNet )
2053 return static_cast<NETINFO_ITEM*>( aNet )->GetNetname();
2054 else
2055 return wxEmptyString;
2056}
2057
2058
2060{
2061 wxLogTrace( wxT( "PNS" ), wxT( "Update-net %s" ), GetNetName( aNet ) );
2062}
2063
2064
2066{
2068}
2069
2070
2072{
2073 return m_ruleResolver;
2074}
2075
2076
2078{
2079 m_tool = aTool;
2080 m_commit = std::make_unique<BOARD_COMMIT>( m_tool );
2081}
int color
Definition: DXF_plotter.cpp:58
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:109
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,...
NETINFO_ITEM * GetNet() const
Return #NET_INFO object for a given item.
void SetNet(NETINFO_ITEM *aNetInfo)
Set a NET_INFO object for the item.
Container for design settings for a BOARD object.
std::shared_ptr< NET_SETTINGS > m_NetSettings
std::shared_ptr< DRC_ENGINE > m_DRCEngine
bool UseNetClassVia() const
Return true if netclass values should be used to obtain appropriate via size.
BOARD_STACKUP & GetStackupDescriptor()
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.
bool m_UseHeightForLengthCalcs
Enable inclusion of stackup height in track length measurements and length tuning.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:77
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:226
PCB_GROUP * GetParentGroup() const
Definition: board_item.h:91
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
Definition: board_item.h:291
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:260
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:248
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:231
virtual bool IsLocked() const
Definition: board_item.cpp:74
virtual bool IsOnCopperLayer() const
Definition: board_item.h:151
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:276
bool GetBoardPolygonOutlines(SHAPE_POLY_SET &aOutlines, OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr, bool aAllowUseArcsInPolygons=false, bool aIncludeNPTHAsOutlines=false)
Extract the board outlines and build a closed polygon from lines, arcs and circle items on edge cut l...
Definition: board.cpp:2204
NETINFO_ITEM * DpCoupledNet(const NETINFO_ITEM *aNet)
Definition: board.cpp:1716
ZONES & Zones()
Definition: board.h:324
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1645
int GetMaxClearanceValue() const
Returns the maximum clearance value for any object on the board.
Definition: board.h:1136
FOOTPRINTS & Footprints()
Definition: board.h:318
int MatchDpSuffix(const wxString &aNetName, wxString &aComplementNet)
Fetch the coupled netname for a given net.
Definition: board.cpp:1666
TRACKS & Tracks()
Definition: board.h:315
DRAWINGS & Drawings()
Definition: board.h:321
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:775
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:441
const Vec & GetOrigin() const
Definition: box2.h:184
const Vec & GetSize() const
Definition: box2.h:180
wxString GetName() const
Definition: drc_rule.h:149
SEVERITY GetSeverity() const
Definition: drc_rule.h:162
const MINOPTMAX< int > & GetValue() const
Definition: drc_rule.h:141
bool IsNull() const
Definition: drc_rule.h:136
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:74
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:123
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:125
virtual std::vector< SHAPE * > MakeEffectiveShapes(bool aEdgeOnly=false) const
Make a set of SHAPE objects representing the EDA_SHAPE.
Definition: eda_shape.h:305
void SetPosition(const VECTOR2I &aPos) override
Definition: footprint.cpp:2047
bool IsNetTie() const
Definition: footprint.h:276
VECTOR2I GetPosition() const override
Definition: footprint.h:206
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition: confirm.h:47
@ KD_WARNING
Definition: confirm.h:50
void DoNotShowCheckbox(wxString file, int line)
Checks the 'do not show again' setting for the dialog.
Definition: confirm.cpp:56
int ShowModal() override
Definition: confirm.cpp:100
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
COLOR4D WithAlpha(double aAlpha) const
Return a color with the same color, but the given alpha.
Definition: color4d.h:311
double GetMinDepth() const
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
PCB specific render settings.
Definition: pcb_painter.h:77
NET_COLOR_MODE GetNetColorMode() const
Definition: pcb_painter.h:116
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()
Definition: pcb_painter.h:121
std::map< wxString, KIGFX::COLOR4D > & GetNetclassColorMap()
Definition: pcb_painter.h:119
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.
bool GetHighContrast() const
Extend VIEW_ITEM by possibility of grouping items into a single object.
Definition: view_group.h:48
void FreeItems()
Free all the items that were added to the group.
Definition: view_group.cpp:204
virtual void SetLayer(int aLayer)
Set layer used to draw the group.
Definition: view_group.h:99
virtual void Add(VIEW_ITEM *aItem)
Add an item to the group.
Definition: view_group.cpp:58
virtual double ViewGetLOD(int aLayer, VIEW *aView) const
Return the level of detail (LOD) of the item.
Definition: view_item.h:141
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:68
double GetScale() const
Definition: view.h:271
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:315
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition: view.cpp:1636
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:197
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition: view.h:412
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:215
bool IsVisible(const VIEW_ITEM *aItem) const
Return information if the item is visible (or not).
Definition: view.cpp:1606
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition: view.cpp:1563
Represent a contiguous set of PCB layers.
Definition: pns_layerset.h:32
int Start() const
Definition: pns_layerset.h:82
int End() const
Definition: pns_layerset.h:87
LAYER_RANGE Intersection(const LAYER_RANGE &aOther) const
Shortcut for comparisons/overlap tests.
Definition: pns_layerset.h:108
bool Overlaps(const LAYER_RANGE &aOther) const
Definition: pns_layerset.h:67
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:573
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:418
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:863
T Min() const
Definition: minoptmax.h:33
void SetMin(T v)
Definition: minoptmax.h:41
T Opt() const
Definition: minoptmax.h:35
Handle the data for a net.
Definition: netinfo.h:56
void SetParent(BOARD *aParent)
Definition: netinfo.h:167
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:383
Definition: pad.h:59
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pad.h:371
const VECTOR2I & GetDrillSize() const
Definition: pad.h:254
PAD_ATTRIB GetAttribute() const
Definition: pad.h:374
const VECTOR2I & GetOffset() const
Definition: pad.h:261
VECTOR2I ShapePos() const
Definition: pad.cpp:757
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition: pad.cpp:355
bool IsFreePad() const
Definition: pad.cpp:183
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition: pad.h:342
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING flashPTHPads=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: pad.cpp:364
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
Return a SHAPE_SEGMENT object representing the pad's hole.
Definition: pad.cpp:401
int GetPadToDieLength() const
Definition: pad.h:387
void SetMid(const VECTOR2I &aMid)
Definition: pcb_track.h:310
const VECTOR2I & GetMid() const
Definition: pcb_track.h:311
std::vector< VECTOR2I > GetConnectionPoints() const
Definition: pcb_shape.cpp:106
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: pcb_shape.h:67
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc, bool aIgnoreLineWidth=false) const override
Convert the item shape to a closed polygon.
Definition: pcb_text.cpp:518
void SetWidth(int aWidth)
Definition: pcb_track.h:106
int GetWidth() const
Definition: pcb_track.h:107
void SetEnd(const VECTOR2I &aEnd)
Definition: pcb_track.h:109
void SetStart(const VECTOR2I &aStart)
Definition: pcb_track.h:112
const VECTOR2I & GetStart() const
Definition: pcb_track.h:113
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:110
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:571
PCB_LAYER_ID BottomLayer() const
Definition: pcb_track.cpp:763
VECTOR2I GetPosition() const override
Definition: pcb_track.h:458
void SetDrill(int aDrill)
Set the drill value for vias.
Definition: pcb_track.h:543
void SetIsFree(bool aFree=true)
Definition: pcb_track.h:572
void SetPosition(const VECTOR2I &aPoint) override
Definition: pcb_track.h:459
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/.
Definition: pcb_track.cpp:714
void SetViaType(VIATYPE aViaType)
Definition: pcb_track.h:404
PCB_LAYER_ID TopLayer() const
Definition: pcb_track.cpp:757
int GetDrillValue() const
Calculate the drill value for vias (m_drill if > 0, or default drill value for the board).
Definition: pcb_track.cpp:383
VIATYPE GetViaType() const
Definition: pcb_track.h:403
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)
Definition: pcb_track.cpp:735
int Width() const override
Definition: pns_arc.h:88
const SHAPE * Shape() const override
Return the geometrical shape of the item.
Definition: pns_arc.h:78
void SetDebugEnabled(bool aEnabled)
static HOLE * MakeCircularHole(const VECTOR2I &pos, int radius)
Definition: pns_hole.cpp:131
ITEM_SET & ExcludeItem(const ITEM *aItem)
ITEM_SET & FilterKinds(int aKindMask, bool aInvert=false)
Definition: pns_itemset.cpp:70
std::vector< ITEM * > & Items()
Definition: pns_itemset.h:87
Base class for PNS router board items.
Definition: pns_item.h:97
BOARD_ITEM * Parent() const
Definition: pns_item.h:185
virtual ITEM * ParentPadVia() const
Definition: pns_item.h:261
virtual NET_HANDLE Net() const
Definition: pns_item.h:193
PnsKind Kind() const
Return the type (kind) of the item.
Definition: pns_item.h:166
void SetNet(NET_HANDLE aNet)
Definition: pns_item.h:192
virtual int Layer() const
Definition: pns_item.h:199
virtual const SHAPE * Shape() const
Return the geometrical shape of the item.
Definition: pns_item.h:224
@ SEGMENT_T
Definition: pns_item.h:105
void SetParent(BOARD_ITEM *aParent)
Definition: pns_item.h:184
const LAYER_RANGE & Layers() const
Definition: pns_item.h:195
bool OfKind(int aKindMask) const
Definition: pns_item.h:174
bool IsVirtual() const
Definition: pns_item.h:263
virtual VECTOR2I Anchor(int n) const
Definition: pns_item.h:236
virtual BOARD_ITEM * BoardItem() const
Definition: pns_item.h:190
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:279
Keep the router "world" - i.e.
Definition: pns_node.h:207
void SetMaxClearance(int aClearance)
Assign a clearance resolution function object.
Definition: pns_node.h:234
bool Add(std::unique_ptr< SEGMENT > aSegment, bool aAllowRedundant=false)
Add an item to the current node.
Definition: pns_node.cpp:657
void SetRuleResolver(RULE_RESOLVER *aFunc)
Definition: pns_node.h:240
void AddEdgeExclusion(std::unique_ptr< SHAPE > aShape)
Definition: pns_node.cpp:701
const ITEM_OWNER * Owner() const
Return the owner of this item, or NULL if there's none.
Definition: pns_item.h:71
virtual wxString GetNetName(PNS::NET_HANDLE aNet) const =0
virtual int GetNetCode(NET_HANDLE aNet) const =0
const SEG & Seg() const
Definition: pns_segment.h:84
int Width() const override
Definition: pns_segment.h:79
void SetTrackWidth(int aWidth)
void SetBoardMinTrackWidth(int aWidth)
void SetDiffPairViaGapSameAsTraceGap(bool aEnable)
void SetDiffPairWidth(int aWidth)
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)
bool syncGraphicalItem(PNS::NODE *aWorld, PCB_SHAPE *aItem)
bool inheritTrackWidth(PNS::ITEM *aItem, int *aInheritedWidth)
bool ImportSizes(PNS::SIZES_SETTINGS &aSizes, PNS::ITEM *aStartItem, PNS::NET_HANDLE aNet) override
void AddItem(PNS::ITEM *aItem) override
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)
std::unique_ptr< PNS::ARC > syncArc(PCB_ARC *aArc)
void RemoveItem(PNS::ITEM *aItem) override
PNS::RULE_RESOLVER * GetRuleResolver() override
bool syncTextItem(PNS::NODE *aWorld, PCB_TEXT *aText, PCB_LAYER_ID aLayer)
bool IsFlashedOnLayer(const PNS::ITEM *aItem, int aLayer) const override
std::unique_ptr< PNS::SOLID > syncPad(PAD *aPad)
void SyncWorld(PNS::NODE *aWorld) override
int StackupHeight(int aFirstLayer, int aSecondLayer) const 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)
void UpdateItem(PNS::ITEM *aItem) 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
bool IsItemVisible(const PNS::ITEM *aItem) const override
std::unordered_set< BOARD_ITEM * > m_hiddenItems
EDA_UNITS GetUnits() const override
bool IsAnyLayerVisible(const LAYER_RANGE &aLayer) const override
PCB_TOOL_BASE * m_tool
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
wxString GetNetName(PNS::NET_HANDLE aNet) const override
void AddPoint(const VECTOR2I &aP, const KIGFX::COLOR4D &aColor, int aSize, const wxString &aName=wxT(""), const SRC_LOCATION_INFO &aSrcLoc=SRC_LOCATION_INFO()) override
PNS_PCBNEW_DEBUG_DECORATOR(KIGFX::VIEW *aView=nullptr)
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
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
int NetCode(PNS::NET_HANDLE aNet) override
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
bool IsKeepout(const PNS::ITEM *aObstacle, const PNS::ITEM *aItem, bool *aEnforce) override
BOARD_ITEM * getBoardItem(const PNS::ITEM *aItem, int aLayer, int aIdx=0)
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
std::unordered_map< CLEARANCE_CACHE_KEY, int > m_clearanceCache
int DpNetPolarity(PNS::NET_HANDLE aNet) override
std::unordered_map< CLEARANCE_CACHE_KEY, int > m_tempClearanceCache
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
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:42
VECTOR2I A
Definition: seg.h:49
VECTOR2I B
Definition: seg.h:50
const VECTOR2I & GetArcMid() const
Definition: shape_arc.h:114
const VECTOR2I & GetP1() const
Definition: shape_arc.h:113
const VECTOR2I & GetP0() const
Definition: shape_arc.h:112
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 Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
void SetWidth(int aWidth)
Set the width of all segments in the 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 aPartition=true, bool aSimplify=false)
Build a polygon triangulation, needed to draw a polygon on OpenGL and in some other calculations.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
const TRIANGULATED_POLYGON * TriangulatedPolygon(int aIndex) const
int OutlineCount() const
Return the number of outlines in the set.
Represent a simple polygon consisting of a zero-thickness closed chain of connected line segments.
Definition: shape_simple.h:42
void Append(int aX, int aY)
Append a new point at the end of the polygon.
Definition: shape_simple.h:135
An abstract shape on 2D plane.
Definition: shape.h:126
TOOL_MANAGER * GetManager() const
Return the instance of TOOL_MANAGER that takes care of the tool.
Definition: tool_base.h:145
APP_SETTINGS_BASE * GetSettings() const
Definition: tool_manager.h:387
VECTOR2_TRAITS< int >::extended_type extended_type
Definition: vector2d.h:72
Handle a list of polygons defining a copper zone.
Definition: zone.h:72
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider) const override
Return a user-visible description string of this item.
Definition: zone.cpp:820
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: zone.h:710
bool GetDoNotAllowVias() const
Definition: zone.h:712
bool GetDoNotAllowPads() const
Definition: zone.h:714
bool GetDoNotAllowTracks() const
Definition: zone.h:713
SHAPE_POLY_SET * Outline()
Definition: zone.h:336
bool GetDoNotAllowFootprints() const
Definition: zone.h:715
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.h:129
This file is part of the common library.
DRC_CONSTRAINT_T
Definition: drc_rule.h:45
@ VIA_DIAMETER_CONSTRAINT
Definition: drc_rule.h:63
@ DIFF_PAIR_GAP_CONSTRAINT
Definition: drc_rule.h:66
@ TRACK_WIDTH_CONSTRAINT
Definition: drc_rule.h:56
@ EDGE_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:50
@ LENGTH_CONSTRAINT
Definition: drc_rule.h:64
@ CLEARANCE_CONSTRAINT
Definition: drc_rule.h:47
@ MAX_UNCOUPLED_CONSTRAINT
Definition: drc_rule.h:67
@ SKEW_CONSTRAINT
Definition: drc_rule.h:65
@ HOLE_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:48
@ HOLE_SIZE_CONSTRAINT
Definition: drc_rule.h:51
@ PHYSICAL_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:70
@ HOLE_TO_HOLE_CONSTRAINT
Definition: drc_rule.h:49
#define _(s)
#define ROUTER_TRANSIENT
transient items that should NOT be cached
#define IN_EDIT
Item currently edited.
EDA_UNITS
Definition: eda_units.h:46
@ ERROR_OUTSIDE
#define MAX_CU_LAYERS
Definition: layer_ids.h:141
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:879
@ LAYER_RATSNEST
Definition: layer_ids.h:207
@ LAYER_SELECT_OVERLAY
currently selected items overlay
Definition: layer_ids.h:222
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ PCBNEW_LAYER_ID_START
Definition: layer_ids.h:64
@ Edge_Cuts
Definition: layer_ids.h:114
@ B_Cu
Definition: layer_ids.h:96
@ Margin
Definition: layer_ids.h:115
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
@ PCB_LAYER_ID_COUNT
Definition: layer_ids.h:138
@ F_Cu
Definition: layer_ids.h:65
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:1022
This file contains miscellaneous commonly used macros and functions.
@ APPEARANCE
Visibility flag has changed.
Definition: view_item.h:52
Push and Shove diff pair dimensions (gap) settings dialog.
CONSTRAINT_TYPE
Definition: pns_node.h:52
void * NET_HANDLE
Definition: pns_item.h:54
@ MK_LOCKED
Definition: pns_item.h:44
STL namespace.
@ 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)
VECTOR2I::extended_type ecoord
@ RPT_SEVERITY_IGNORE
#define PNS_SEMI_SOLID
@ SH_SEGMENT
line segment
Definition: shape.h:48
@ SH_ARC
circular arc
Definition: shape.h:54
@ SH_LINE_CHAIN
line chain (polyline)
Definition: shape.h:49
const PNS::ITEM * A
bool operator==(const CLEARANCE_CACHE_KEY &other) const
const PNS::ITEM * B
An abstract function object, returning a design rule (clearance, diff pair gap, etc) required between...
Definition: pns_node.h:73
wxString m_RuleName
Definition: pns_node.h:77
MINOPTMAX< int > m_Value
Definition: pns_node.h:75
CONSTRAINT_TYPE m_Type
Definition: pns_node.h:74
std::size_t operator()(const CLEARANCE_CACHE_KEY &k) const
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:228
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:78
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:88
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition: typeinfo.h:93
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:107
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:92
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588