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