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 along
19 * with this program. If not, see <http://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 // No 'else'; non-plated milled holes get both HOLE_CLEARANCE and EDGE_CLEARANCE
938 if( isEdge( aA ) || IsNonPlatedSlot( aA ) || isEdge( aB ) || IsNonPlatedSlot( aB ) )
939 {
940 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_EDGE_CLEARANCE, aA, aB, layer, &constraint ) )
941 {
942 if( constraint.m_Value.Min() > rv )
943 rv = constraint.m_Value.Min();
944 }
945 }
946 }
947
948 // Physical clearances are net-blind: a physical_clearance rule applies regardless
949 if( isHole( aA ) || isHole( aB ) )
950 {
951 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_PHYSICAL_HOLE_CLEARANCE, aA, aB, layer, &constraint ) )
952 {
953 if( constraint.m_Value.Min() > rv )
954 rv = constraint.m_Value.Min();
955 }
956 }
957
958 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_PHYSICAL_CLEARANCE, aA, aB, layer, &constraint ) )
959 {
960 if( constraint.m_Value.Min() > rv )
961 rv = constraint.m_Value.Min();
962 }
963 }
964
965 // Same-net pairs short-circuit clearance unless a physical_clearance rule gave a positive value
966 if( ( sameNet || freePad ) && rv == 0 )
967 rv = -1;
968
969 if( aUseClearanceEpsilon && rv > 0 )
970 rv = std::max( 0, rv - m_clearanceEpsilon );
971
972 // Remember this result so we don't recompute it. Real board items go in the long-lived
973 // cache. Temporary items the router creates while routing go in a separate cache we can
974 // clear on their own.
975 if( bothOwned )
976 m_clearanceCache[CLEARANCE_CACHE_KEY( aA, aB, aUseClearanceEpsilon )] = rv;
977 else if( aA && aB )
978 m_tempClearanceCache[TEMP_CLEARANCE_CACHE_KEY( aA, aB, aUseClearanceEpsilon )] = rv;
979
980 return rv;
981}
982
983
984bool PNS_KICAD_IFACE_BASE::inheritTrackWidth( PNS::ITEM* aItem, int* aInheritedWidth,
985 const VECTOR2I& aStartPosition )
986{
987 VECTOR2I p;
988
989 assert( aItem->Owner() != nullptr );
990
991 auto tryGetTrackWidth =
992 []( PNS::ITEM* aPnsItem ) -> int
993 {
994 switch( aPnsItem->Kind() )
995 {
996 case PNS::ITEM::SEGMENT_T: return static_cast<PNS::SEGMENT*>( aPnsItem )->Width();
997 case PNS::ITEM::ARC_T: return static_cast<PNS::ARC*>( aPnsItem )->Width();
998 default: return -1;
999 }
1000 };
1001
1002 int itemTrackWidth = tryGetTrackWidth( aItem );
1003
1004 if( itemTrackWidth > 0 )
1005 {
1006 *aInheritedWidth = itemTrackWidth;
1007 return true;
1008 }
1009
1010 switch( aItem->Kind() )
1011 {
1012 case PNS::ITEM::VIA_T: p = static_cast<PNS::VIA*>( aItem )->Pos(); break;
1013 case PNS::ITEM::SOLID_T: p = static_cast<PNS::SOLID*>( aItem )->Pos(); break;
1014 default: return false;
1015 }
1016
1017 const PNS::JOINT* jt = static_cast<const PNS::NODE*>( aItem->Owner() )->FindJoint( p, aItem );
1018
1019 assert( jt != nullptr );
1020
1021 PNS::ITEM_SET linkedSegs( jt->CLinks() );
1023
1024 if( linkedSegs.Empty() )
1025 return false;
1026
1027 // When a start position is provided, find the connected track whose far end is closest to
1028 // the cursor. Since all tracks share the pad/via endpoint, the far-end direction is a proxy
1029 // for which exit stub the user is pointing at.
1030 if( aStartPosition != VECTOR2I() )
1031 {
1032 PNS::ITEM* closestItem = nullptr;
1034
1035 for( PNS::ITEM* item : linkedSegs.Items() )
1036 {
1037 if( item->Layer() != m_startLayer )
1038 continue;
1039
1040 PNS::LINKED_ITEM* li = static_cast<PNS::LINKED_ITEM*>( item );
1041
1042 VECTOR2I anchor0 = li->Anchor( 0 );
1043 VECTOR2I anchor1 = li->Anchor( 1 );
1044
1045 // The "other end" is the anchor farther from the pad/via center
1046 VECTOR2I otherEnd = ( anchor0 - p ).SquaredEuclideanNorm() > ( anchor1 - p ).SquaredEuclideanNorm()
1047 ? anchor0
1048 : anchor1;
1049
1050 SEG::ecoord dist = ( otherEnd - aStartPosition ).SquaredEuclideanNorm();
1051
1052 if( dist < minDist )
1053 {
1054 minDist = dist;
1055 closestItem = item;
1056 }
1057 }
1058
1059 if( closestItem )
1060 {
1061 int w = tryGetTrackWidth( closestItem );
1062
1063 if( w > 0 )
1064 {
1065 *aInheritedWidth = w;
1066 return true;
1067 }
1068 }
1069 }
1070
1071 // Fallback to minimum width when no start position provided or no valid exit stub found
1072 int min_current_layer = INT_MAX;
1073 int min_all_layers = INT_MAX;
1074
1075 for( PNS::ITEM* item : linkedSegs.Items() )
1076 {
1077 int w = tryGetTrackWidth( item );
1078
1079 if( w > 0 )
1080 {
1081 min_all_layers = std::min( w, min_all_layers );
1082
1083 if( item->Layer() == m_startLayer )
1084 min_current_layer = std::min( w, min_current_layer );
1085 }
1086 }
1087
1088 if( min_all_layers == INT_MAX )
1089 return false;
1090
1091 if( min_current_layer < INT_MAX )
1092 *aInheritedWidth = min_current_layer;
1093 else
1094 *aInheritedWidth = min_all_layers;
1095
1096 return true;
1097}
1098
1099
1101 PNS::NET_HANDLE aNet, VECTOR2D aStartPosition )
1102{
1103 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
1104 PNS::CONSTRAINT constraint;
1105
1106 if( aStartItem && m_startLayer < 0 )
1107 m_startLayer = aStartItem->Layer();
1108
1109 aSizes.SetClearance( bds.m_MinClearance );
1110 aSizes.SetMinClearance( bds.m_MinClearance );
1111 aSizes.SetClearanceSource( _( "board minimum clearance" ) );
1112
1113 int startAnchor = 0;
1114 VECTOR2I startPosInt( aStartPosition.x, aStartPosition.y );
1115
1116 if( aStartItem && aStartItem->Kind() == PNS::ITEM::SEGMENT_T )
1117 {
1118 // Find the start anchor which is closest to the start mouse location
1119 double anchor0Distance = startPosInt.Distance( aStartItem->Anchor( 0 ) );
1120 double anchor1Distance = startPosInt.Distance( aStartItem->Anchor( 1 ) );
1121
1122 if( anchor1Distance < anchor0Distance )
1123 startAnchor = 1;
1124 }
1125
1126 if( aStartItem )
1127 {
1128 PNS::SEGMENT dummyTrack;
1129 dummyTrack.SetEnds( aStartItem->Anchor( startAnchor ), aStartItem->Anchor( startAnchor ) );
1130 dummyTrack.SetLayer( m_startLayer );
1131 dummyTrack.SetNet( static_cast<NETINFO_ITEM*>( aStartItem->Net() ) );
1132
1133 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_CLEARANCE, &dummyTrack,
1134 nullptr, m_startLayer, &constraint ) )
1135 {
1136 if( constraint.m_Value.Min() >= bds.m_MinClearance )
1137 {
1138 aSizes.SetClearance( constraint.m_Value.Min() );
1139 aSizes.SetClearanceSource( constraint.m_RuleName );
1140 }
1141 }
1142 }
1143
1144 int trackWidth = bds.m_TrackMinWidth;
1145 bool found = false;
1146 aSizes.SetWidthSource( _( "board minimum track width" ) );
1147
1148 if( bds.m_UseConnectedTrackWidth && !bds.m_TempOverrideTrackWidth && aStartItem != nullptr )
1149 {
1150 found = inheritTrackWidth( aStartItem, &trackWidth, startPosInt );
1151
1152 if( found )
1153 aSizes.SetWidthSource( _( "existing track" ) );
1154 }
1155
1156 if( !found && bds.UseNetClassTrack() && aStartItem )
1157 {
1158 PNS::SEGMENT dummyTrack;
1159 dummyTrack.SetEnds( aStartItem->Anchor( startAnchor ), aStartItem->Anchor( startAnchor ) );
1160 dummyTrack.SetLayer( m_startLayer );
1161 dummyTrack.SetNet( static_cast<NETINFO_ITEM*>( aStartItem->Net() ) );
1162
1163 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_WIDTH, &dummyTrack, nullptr,
1164 m_startLayer, &constraint ) )
1165 {
1166 trackWidth = std::max( trackWidth, constraint.m_Value.Opt() );
1167 found = true;
1168
1169 if( trackWidth == constraint.m_Value.Opt() )
1170 aSizes.SetWidthSource( constraint.m_RuleName );
1171 }
1172 }
1173
1174 if( !found )
1175 {
1176 trackWidth = std::max( trackWidth, bds.GetCurrentTrackWidth() );
1177
1178 if( bds.UseNetClassTrack() )
1179 aSizes.SetWidthSource( _( "netclass 'Default'" ) );
1180 else if( trackWidth == bds.GetCurrentTrackWidth() )
1181 aSizes.SetWidthSource( _( "user choice" ) );
1182 }
1183
1184 aSizes.SetTrackWidth( trackWidth );
1187
1188 int viaDiameter = bds.m_ViasMinSize;
1189 int viaDrill = bds.m_MinThroughDrill;
1190
1191 PNS::VIA dummyVia, coupledVia;
1192
1193 if( aStartItem )
1194 {
1195 dummyVia.SetNet( aStartItem->Net() );
1196 coupledVia.SetNet( m_ruleResolver->DpCoupledNet( aStartItem->Net() ) );
1197 }
1198
1199 if( bds.UseNetClassVia() && aStartItem ) // netclass value
1200 {
1201 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_VIA_DIAMETER, &dummyVia,
1202 nullptr, m_startLayer, &constraint ) )
1203 {
1204 viaDiameter = std::max( viaDiameter, constraint.m_Value.Opt() );
1205 }
1206
1207 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_VIA_HOLE, &dummyVia,
1208 nullptr, m_startLayer, &constraint ) )
1209 {
1210 viaDrill = std::max( viaDrill, constraint.m_Value.Opt() );
1211 }
1212 }
1213 else
1214 {
1215 viaDiameter = bds.GetCurrentViaSize();
1216 viaDrill = bds.GetCurrentViaDrill();
1217 }
1218
1219 aSizes.SetViaDiameter( viaDiameter );
1220 aSizes.SetViaDrill( viaDrill );
1221
1222 int diffPairWidth = bds.m_TrackMinWidth;
1223 int diffPairGap = bds.m_MinClearance;
1224 int diffPairViaGap = bds.m_MinClearance;
1225
1226 aSizes.SetDiffPairWidthSource( _( "board minimum track width" ) );
1227 aSizes.SetDiffPairGapSource( _( "board minimum clearance" ) );
1228
1229 found = false;
1230
1231 // First try to pick up diff pair width from starting track, if enabled
1232 if( bds.m_UseConnectedTrackWidth && aStartItem )
1233 found = inheritTrackWidth( aStartItem, &diffPairWidth, startPosInt );
1234
1235 // Next, pick up gap from netclass, and width also if we didn't get a starting width above
1236 if( bds.UseNetClassDiffPair() && aStartItem )
1237 {
1238 PNS::NET_HANDLE coupledNet = m_ruleResolver->DpCoupledNet( aStartItem->Net() );
1239
1240 PNS::SEGMENT dummyTrack;
1241 dummyTrack.SetEnds( aStartItem->Anchor( 0 ), aStartItem->Anchor( 0 ) );
1242 dummyTrack.SetLayer( m_startLayer );
1243 dummyTrack.SetNet( static_cast<NETINFO_ITEM*>( aStartItem->Net() ) );
1244
1245 PNS::SEGMENT coupledTrack;
1246 coupledTrack.SetEnds( aStartItem->Anchor( 0 ), aStartItem->Anchor( 0 ) );
1247 coupledTrack.SetLayer( m_startLayer );
1248 coupledTrack.SetNet( static_cast<NETINFO_ITEM*>( coupledNet ) );
1249
1250 if( !found
1251 && m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_WIDTH, &dummyTrack,
1252 &coupledTrack, m_startLayer, &constraint ) )
1253 {
1254 diffPairWidth = std::max( diffPairWidth, constraint.m_Value.Opt() );
1255
1256 if( diffPairWidth == constraint.m_Value.Opt() )
1257 aSizes.SetDiffPairWidthSource( constraint.m_RuleName );
1258 }
1259
1260 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_DIFF_PAIR_GAP, &dummyTrack,
1261 &coupledTrack, m_startLayer, &constraint ) )
1262 {
1263 diffPairGap = std::max( diffPairGap, constraint.m_Value.Opt() );
1264 diffPairViaGap = std::max( diffPairViaGap, constraint.m_Value.Opt() );
1265
1266 if( diffPairGap == constraint.m_Value.Opt() )
1267 aSizes.SetDiffPairGapSource( constraint.m_RuleName );
1268 }
1269 }
1270 else
1271 {
1272 diffPairWidth = bds.GetCurrentDiffPairWidth();
1273 diffPairGap = bds.GetCurrentDiffPairGap();
1274 diffPairViaGap = bds.GetCurrentDiffPairViaGap();
1275
1276 aSizes.SetDiffPairWidthSource( _( "user choice" ) );
1277 aSizes.SetDiffPairGapSource( _( "user choice" ) );
1278 }
1279
1280 aSizes.SetDiffPairWidth( diffPairWidth );
1281 aSizes.SetDiffPairGap( diffPairGap );
1282 aSizes.SetDiffPairViaGap( diffPairViaGap );
1283 aSizes.SetDiffPairViaGapSameAsTraceGap( false );
1284
1285 int holeToHoleMin = bds.m_HoleToHoleMin;
1286
1287 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_HOLE_TO_HOLE, &dummyVia,
1288 &dummyVia, UNDEFINED_LAYER, &constraint ) )
1289 {
1290 holeToHoleMin = constraint.m_Value.Min();
1291 }
1292
1293 aSizes.SetHoleToHole( holeToHoleMin );
1294
1295 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_HOLE_TO_HOLE, &dummyVia,
1296 &coupledVia, UNDEFINED_LAYER, &constraint ) )
1297 {
1298 holeToHoleMin = constraint.m_Value.Min();
1299 }
1300
1301 aSizes.SetDiffPairHoleToHole( std::max( holeToHoleMin, aSizes.GetHoleToHole() ) );
1302
1303 return true;
1304}
1305
1306
1307int PNS_KICAD_IFACE_BASE::StackupHeight( int aFirstLayer, int aSecondLayer ) const
1308{
1309 if( !m_board || !m_board->GetDesignSettings().m_UseHeightForLengthCalcs )
1310 return 0;
1311
1312 BOARD_STACKUP& stackup = m_board->GetDesignSettings().GetStackupDescriptor();
1313
1314 return stackup.GetLayerDistance( GetBoardLayerFromPNSLayer( aFirstLayer ),
1315 GetBoardLayerFromPNSLayer( aSecondLayer ) );
1316}
1317
1318
1320{
1321 return m_board->DpCoupledNet( static_cast<NETINFO_ITEM*>( aNet ) );
1322}
1323
1324
1326{
1327 return m_routerIface->GetNetCode( aNet );
1328}
1329
1330
1332{
1333 return m_routerIface->GetNetName( aNet );
1334}
1335
1336
1338{
1339 wxString refName;
1340
1341 if( NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aNet ) )
1342 refName = net->GetNetname();
1343
1344 wxString dummy1;
1345
1346 return m_board->MatchDpSuffix( refName, dummy1 );
1347}
1348
1349
1351 PNS::NET_HANDLE& aNetN )
1352{
1353 if( !aItem || !aItem->Net() )
1354 return false;
1355
1356 wxString netNameP = static_cast<NETINFO_ITEM*>( aItem->Net() )->GetNetname();
1357 wxString netNameN, netNameCoupled;
1358
1359 int r = m_board->MatchDpSuffix( netNameP, netNameCoupled );
1360
1361 if( r == 0 )
1362 {
1363 return false;
1364 }
1365 else if( r == 1 )
1366 {
1367 netNameN = netNameCoupled;
1368 }
1369 else
1370 {
1371 netNameN = netNameP;
1372 netNameP = netNameCoupled;
1373 }
1374
1375 PNS::NET_HANDLE netInfoP = m_board->FindNet( netNameP );
1376 PNS::NET_HANDLE netInfoN = m_board->FindNet( netNameN );
1377
1378 if( !netInfoP || !netInfoN )
1379 return false;
1380
1381 aNetP = netInfoP;
1382 aNetN = netInfoN;
1383
1384 return true;
1385}
1386
1387
1389{
1390public:
1393 m_iface( aIface ),
1394 m_view( nullptr ),
1395 m_items( nullptr ),
1396 m_depth( 0 )
1397 {}
1398
1400 {
1402
1403 for ( PNS::ITEM* item : m_clonedItems )
1404 {
1405 delete item;
1406 }
1407
1408 delete m_items;
1409 }
1410
1411 void SetView( KIGFX::VIEW* aView )
1412 {
1413 Clear();
1414 delete m_items;
1415 m_items = nullptr;
1416 m_view = aView;
1417
1418 if( m_view == nullptr )
1419 return;
1420
1421 if( m_view->GetGAL() )
1422 m_depth = m_view->GetGAL()->GetMinDepth();
1423
1425 m_items->SetLayer( LAYER_SELECT_OVERLAY ) ;
1426 m_view->Add( m_items );
1427 }
1428
1429 void AddPoint( const VECTOR2I& aP, const KIGFX::COLOR4D& aColor, int aSize, const wxString& aName = wxT( "" ),
1430 const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override
1431
1432 {
1434
1435 sh.SetWidth( 10000 );
1436
1437 sh.Append( aP.x - aSize, aP.y - aSize );
1438 sh.Append( aP.x + aSize, aP.y + aSize );
1439 sh.Append( aP.x, aP.y );
1440 sh.Append( aP.x - aSize, aP.y + aSize );
1441 sh.Append( aP.x + aSize, aP.y - aSize );
1442
1443 AddShape( &sh, aColor, sh.Width(), aName, aSrcLoc );
1444 }
1445
1446 void AddItem( const PNS::ITEM* aItem, const KIGFX::COLOR4D& aColor, int aOverrideWidth = 0,
1447 const wxString& aName = wxT( "" ),
1448 const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override
1449 {
1450 if( !m_view || !aItem )
1451 return;
1452
1453 PNS::ITEM* cloned = aItem->Clone();
1454
1455 if( auto line = dyn_cast<PNS::LINE*>( cloned ))
1456 {
1457 line->ClearLinks();
1458 }
1459
1460 m_clonedItems.push_back( cloned );
1461
1462 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( cloned, m_iface, m_view );
1463
1464 pitem->SetColor( aColor.WithAlpha( 0.5 ) );
1465 pitem->SetWidth( aOverrideWidth );
1466 pitem->SetDepth( nextDepth() );
1467
1468 m_items->Add( pitem );
1469 m_view->Update( m_items );
1470 }
1471
1472 void AddShape( const BOX2I& aBox, const KIGFX::COLOR4D& aColor, int aOverrideWidth = 0,
1473 const wxString& aName = wxT( "" ),
1474 const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override
1475 {
1477 l.SetWidth( aOverrideWidth );
1478
1479 VECTOR2I o = aBox.GetOrigin();
1480 VECTOR2I s = aBox.GetSize();
1481
1482 l.Append( o );
1483 l.Append( o.x + s.x, o.y );
1484 l.Append( o.x + s.x, o.y + s.y );
1485 l.Append( o.x, o.y + s.y );
1486 l.Append( o );
1487
1488 AddShape( &l, aColor, aOverrideWidth, aName, aSrcLoc );
1489 }
1490
1491 void AddShape( const SHAPE* aShape, const KIGFX::COLOR4D& aColor, int aOverrideWidth = 0,
1492 const wxString& aName = wxT( "" ),
1493 const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override
1494 {
1495 if( !m_view || !aShape )
1496 return;
1497
1498 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( *aShape, m_iface, m_view );
1499
1500 pitem->SetColor( aColor.WithAlpha( 0.5 ) );
1501 pitem->SetWidth( aOverrideWidth );
1502 pitem->SetDepth( nextDepth() );
1503
1504 m_items->Add( pitem );
1505 m_view->Update( m_items );
1506 }
1507
1508 void Clear() override
1509 {
1510 if( m_view && m_items )
1511 {
1512 m_items->FreeItems();
1513 m_view->Update( m_items );
1514
1515 if( m_view->GetGAL() )
1516 m_depth = m_view->GetGAL()->GetMinDepth();
1517 }
1518
1519 for( PNS::ITEM* item : m_clonedItems )
1520 delete item;
1521
1522 m_clonedItems.clear();
1523 }
1524
1525 virtual void Message( const wxString& msg, const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override
1526 {
1527 }
1528
1529private:
1530 double nextDepth()
1531 {
1532 // Use different depths so that the transculent shapes won't overwrite each other.
1533
1534 m_depth++;
1535
1536 if( m_depth >= 0 && m_view->GetGAL() )
1537 m_depth = m_view->GetGAL()->GetMinDepth();
1538
1539 return m_depth;
1540 }
1541
1545 std::vector<PNS::ITEM*> m_clonedItems;
1546
1547 double m_depth;
1548};
1549
1550
1555
1556
1558{
1559 m_ruleResolver = nullptr;
1560 m_board = nullptr;
1561 m_world = nullptr;
1562 m_debugDecorator = nullptr;
1563 m_startLayer = -1;
1564}
1565
1566
1568{
1569 m_tool = nullptr;
1570 m_view = nullptr;
1571 m_previewItems = nullptr;
1572 m_commitFlags = 0;
1573}
1574
1575
1581
1582
1584{
1585 if( m_previewItems )
1586 {
1587 m_previewItems->FreeItems();
1588 delete m_previewItems;
1589 }
1590}
1591
1592
1593std::vector<std::unique_ptr<PNS::SOLID>> PNS_KICAD_IFACE_BASE::syncPad( PAD* aPad )
1594{
1595 std::vector<std::unique_ptr<PNS::SOLID>> solids;
1596 PNS_LAYER_RANGE layers( 0, aPad->BoardCopperLayerCount() - 1 );
1597 LSEQ lmsk = aPad->GetLayerSet().CuStack();
1598
1599 // ignore non-copper pads except for those with holes
1600 if( lmsk.empty() && aPad->GetDrillSize().x == 0 )
1601 return solids;
1602
1603 switch( aPad->GetAttribute() )
1604 {
1605 case PAD_ATTRIB::PTH:
1606 case PAD_ATTRIB::NPTH:
1607 break;
1608
1609 case PAD_ATTRIB::CONN:
1610 case PAD_ATTRIB::SMD:
1611 {
1612 bool is_copper = false;
1613
1614 if( !lmsk.empty() && aPad->GetAttribute() != PAD_ATTRIB::NPTH )
1615 {
1616 layers = SetLayersFromPCBNew( lmsk.front(), lmsk.front() );
1617 is_copper = true;
1618 }
1619
1620 if( !is_copper )
1621 return solids;
1622
1623 break;
1624 }
1625
1626 default:
1627 wxLogTrace( wxT( "PNS" ), wxT( "unsupported pad type 0x%x" ), aPad->GetAttribute() );
1628 return solids;
1629 }
1630
1631 auto makeSolidFromPadLayer =
1632 [&]( PCB_LAYER_ID aLayer )
1633 {
1634 // For FRONT_INNER_BACK mode, skip creating a SOLID for inner layers when there are
1635 // no inner layers (2-layer board). Otherwise PNS_LAYER_RANGE(1, 0) would be swapped
1636 // to (0, 1) and indexed on both F_Cu and B_Cu, causing incorrect collision checks.
1638 && aLayer != F_Cu && aLayer != B_Cu
1639 && aPad->BoardCopperLayerCount() <= 2 )
1640 {
1641 return;
1642 }
1643
1644 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
1645
1646 if( aPad->GetAttribute() == PAD_ATTRIB::NPTH )
1647 solid->SetRoutable( false );
1648
1649 if( aPad->Padstack().Mode() == PADSTACK::MODE::CUSTOM )
1650 {
1651 solid->SetLayer( GetPNSLayerFromBoardLayer( aLayer ) );
1652 }
1653 else if( aPad->Padstack().Mode() == PADSTACK::MODE::FRONT_INNER_BACK )
1654 {
1655 if( aLayer == F_Cu || aLayer == B_Cu )
1656 solid->SetLayer( GetPNSLayerFromBoardLayer( aLayer ) );
1657 else
1658 solid->SetLayers( PNS_LAYER_RANGE( 1, aPad->BoardCopperLayerCount() - 2 ) );
1659 }
1660 else
1661 {
1662 solid->SetLayers( layers );
1663 }
1664
1665 solid->SetNet( aPad->GetNet() );
1666 solid->SetParent( aPad );
1667 solid->SetPadToDie( aPad->GetPadToDieLength() );
1668 solid->SetPadToDieDelay( aPad->GetPadToDieDelay() );
1669 solid->SetOrientation( aPad->GetOrientation() );
1670
1671 if( aPad->IsFreePad() )
1672 solid->SetIsFreePad();
1673
1674 VECTOR2I wx_c = aPad->ShapePos( aLayer );
1675 VECTOR2I offset = aPad->GetOffset( aLayer );
1676
1677 VECTOR2I c( wx_c.x, wx_c.y );
1678
1679 RotatePoint( offset, aPad->GetOrientation() );
1680
1681 solid->SetPos( VECTOR2I( c.x - offset.x, c.y - offset.y ) );
1682 solid->SetOffset( VECTOR2I( offset.x, offset.y ) );
1683
1684 if( aPad->GetDrillSize().x > 0 )
1685 {
1686 solid->SetHole( new PNS::HOLE( aPad->GetEffectiveHoleShape()->Clone() ) );
1687 solid->Hole()->SetLayers( PNS_LAYER_RANGE( 0, aPad->BoardCopperLayerCount() - 1 ) );
1688 }
1689
1690 // We generate a single SOLID for a pad, so we have to treat it as ALWAYS_FLASHED and
1691 // then perform layer-specific flashing tests internally.
1692 const std::shared_ptr<SHAPE>& shape = aPad->GetEffectiveShape( aLayer, FLASHING::ALWAYS_FLASHED );
1693
1694 if( shape->HasIndexableSubshapes() && shape->GetIndexableSubshapeCount() == 1 )
1695 {
1696 std::vector<const SHAPE*> subshapes;
1697 shape->GetIndexableSubshapes( subshapes );
1698
1699 solid->SetShape( subshapes[0]->Clone() );
1700 }
1701 // For anything that's not a single shape we use a polygon. Multiple shapes have a tendency
1702 // to confuse the hull generator. https://gitlab.com/kicad/code/kicad/-/issues/15553
1703 else
1704 {
1705 const std::shared_ptr<SHAPE_POLY_SET>& poly = aPad->GetEffectivePolygon( aLayer, ERROR_OUTSIDE );
1706
1707 if( poly->OutlineCount() )
1708 solid->SetShape( new SHAPE_SIMPLE( poly->Outline( 0 ) ) );
1709 }
1710
1711 if( !solid->Shape( 0 ) )
1712 return;
1713
1714 solids.emplace_back( std::move( solid ) );
1715 };
1716
1717 aPad->Padstack().ForEachUniqueLayer( makeSolidFromPadLayer );
1718
1719 return solids;
1720}
1721
1722
1723std::unique_ptr<PNS::SEGMENT> PNS_KICAD_IFACE_BASE::syncTrack( PCB_TRACK* aTrack )
1724{
1725 auto segment = std::make_unique<PNS::SEGMENT>( SEG( aTrack->GetStart(), aTrack->GetEnd() ), aTrack->GetNet() );
1726
1727 segment->SetWidth( aTrack->GetWidth() );
1728 segment->SetLayer( GetPNSLayerFromBoardLayer( aTrack->GetLayer() ) );
1729 segment->SetParent( aTrack );
1730
1731 if( aTrack->IsLocked() )
1732 segment->Mark( PNS::MK_LOCKED );
1733
1734 if( PCB_GENERATOR* generator = dynamic_cast<PCB_GENERATOR*>( aTrack->GetParentGroup() ) )
1735 {
1736 if( !generator->HasFlag( IN_EDIT ) )
1737 segment->Mark( PNS::MK_LOCKED );
1738 }
1739
1740 return segment;
1741}
1742
1743
1744std::unique_ptr<PNS::ARC> PNS_KICAD_IFACE_BASE::syncArc( PCB_ARC* aArc )
1745{
1746 auto arc = std::make_unique<PNS::ARC>( SHAPE_ARC( aArc->GetStart(), aArc->GetMid(),
1747 aArc->GetEnd(), aArc->GetWidth() ),
1748 aArc->GetNet() );
1749
1750 arc->SetLayer( GetPNSLayerFromBoardLayer( aArc->GetLayer() ) );
1751 arc->SetParent( aArc );
1752
1753 if( aArc->IsLocked() )
1754 arc->Mark( PNS::MK_LOCKED );
1755
1756 if( PCB_GENERATOR* generator = dynamic_cast<PCB_GENERATOR*>( aArc->GetParentGroup() ) )
1757 {
1758 if( !generator->HasFlag( IN_EDIT ) )
1759 arc->Mark( PNS::MK_LOCKED );
1760 }
1761
1762 return arc;
1763}
1764
1765
1766std::unique_ptr<PNS::VIA> PNS_KICAD_IFACE_BASE::syncVia( PCB_VIA* aVia )
1767{
1768 PCB_LAYER_ID top, bottom;
1769 aVia->LayerPair( &top, &bottom );
1770
1771 /*
1772 * NOTE about PNS via padstacks:
1773 *
1774 * PNS::VIA has no knowledge about how many layers are in the board, and there is no fixed
1775 * reference to the "back layer" in the PNS. That means that there is no way for a VIA to know
1776 * the difference between its bottom layer and the bottom layer of the overall board (i.e. if
1777 * the via is a blind/buried via). For this reason, PNS::VIA::STACK_MODE::FRONT_INNER_BACK
1778 * cannot be used for blind/buried vias. This mode will always assume that the via's top layer
1779 * is the "front" layer and the via's bottom layer is the "back" layer, but from KiCad's point
1780 * of view, at least at the moment, front/inner/back padstack mode is board-scoped, not
1781 * via-scoped, so a buried via would only use the inner layer size even if its padstack mode is
1782 * set to PADSTACK::MODE::FRONT_INNER_BACK and different sizes are defined for front or back.
1783 * For this kind of via, the PNS VIA stack mode will be set to NORMAL because effectively it has
1784 * the same size on every layer it exists on.
1785 */
1786
1787 auto via = std::make_unique<PNS::VIA>( aVia->GetPosition(),
1788 SetLayersFromPCBNew( aVia->TopLayer(), aVia->BottomLayer() ),
1789 0,
1790 aVia->GetDrillValue(),
1791 aVia->GetNet(),
1792 aVia->GetViaType() );
1793 via->SetUnconnectedLayerMode( aVia->Padstack().UnconnectedLayerMode() );
1794
1795 auto syncDiameter =
1796 [&]( PCB_LAYER_ID aLayer )
1797 {
1798 via->SetDiameter( GetPNSLayerFromBoardLayer( aLayer ), aVia->GetWidth( aLayer ) );
1799 };
1800
1801 switch( aVia->Padstack().Mode() )
1802 {
1804 via->SetDiameter( 0, aVia->GetWidth( PADSTACK::ALL_LAYERS ) );
1805 break;
1806
1808 if( aVia->GetViaType() == VIATYPE::BLIND || aVia->GetViaType() == VIATYPE::BURIED )
1809 {
1810 via->SetDiameter( 0, aVia->GetWidth( PADSTACK::INNER_LAYERS ) );
1811 }
1812 else
1813 {
1815 aVia->Padstack().ForEachUniqueLayer( syncDiameter );
1816 }
1817
1818 break;
1819
1821 via->SetStackMode( PNS::VIA::STACK_MODE::CUSTOM );
1822 aVia->Padstack().ForEachUniqueLayer( syncDiameter );
1823 }
1824
1825 via->SetParent( aVia );
1826
1827 if( aVia->IsLocked() )
1828 via->Mark( PNS::MK_LOCKED );
1829
1830 if( PCB_GENERATOR* generator = dynamic_cast<PCB_GENERATOR*>( aVia->GetParentGroup() ) )
1831 {
1832 if( !generator->HasFlag( IN_EDIT ) )
1833 via->Mark( PNS::MK_LOCKED );
1834 }
1835
1836 via->SetIsFree( aVia->GetIsFree() );
1837 via->SetHole( PNS::HOLE::MakeCircularHole( aVia->GetPosition(),
1838 aVia->GetDrillValue() / 2,
1839 SetLayersFromPCBNew( aVia->TopLayer(), aVia->BottomLayer() ) ) );
1840
1841 PCB_LAYER_ID primaryStart = aVia->GetPrimaryDrillStartLayer();
1842 PCB_LAYER_ID primaryEnd = aVia->GetPrimaryDrillEndLayer();
1843
1844 if( primaryStart != UNDEFINED_LAYER && primaryEnd != UNDEFINED_LAYER )
1845 via->SetHoleLayers( SetLayersFromPCBNew( primaryStart, primaryEnd ) );
1846 else
1847 via->SetHoleLayers( SetLayersFromPCBNew( aVia->TopLayer(), aVia->BottomLayer() ) );
1848
1849 via->SetHolePostMachining( aVia->GetFrontPostMachining() );
1850 via->SetSecondaryDrill( aVia->GetSecondaryDrillSize() );
1851
1852 std::optional<PNS_LAYER_RANGE> secondaryLayers;
1853
1856 {
1857 secondaryLayers = SetLayersFromPCBNew( aVia->GetSecondaryDrillStartLayer(),
1858 aVia->GetSecondaryDrillEndLayer() );
1859 }
1860
1861 via->SetSecondaryHoleLayers( secondaryLayers );
1862 via->SetSecondaryHolePostMachining( std::nullopt );
1863
1864 return via;
1865}
1866
1867
1868bool PNS_KICAD_IFACE_BASE::syncZone( PNS::NODE* aWorld, ZONE* aZone, SHAPE_POLY_SET* aBoardOutline )
1869{
1870 static wxString msg;
1871 SHAPE_POLY_SET* poly;
1872
1873 if( !aZone->GetIsRuleArea() || !aZone->HasKeepoutParametersSet() )
1874 return false;
1875
1876 LSET layers = aZone->GetLayerSet();
1877
1878 poly = aZone->Outline();
1879 poly->CacheTriangulation();
1880
1881 if( !poly->IsTriangulationUpToDate() )
1882 {
1883 UNITS_PROVIDER unitsProvider( pcbIUScale, GetUnits() );
1884 msg.Printf( _( "%s is malformed." ), aZone->GetItemDescription( &unitsProvider, true ) );
1885
1886 KIDIALOG dlg( nullptr, msg, KIDIALOG::KD_WARNING );
1887 dlg.ShowDetailedText( _( "This zone cannot be handled by the router.\n"
1888 "Please verify it is not a self-intersecting polygon." ) );
1889 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
1890 dlg.ShowModal();
1891
1892 return false;
1893 }
1894
1895 for( PCB_LAYER_ID layer : LAYER_RANGE( F_Cu, B_Cu, m_board->GetCopperLayerCount() ) )
1896 {
1897 if( !layers[ layer ] )
1898 continue;
1899
1900 for( unsigned int polyId = 0; polyId < poly->TriangulatedPolyCount(); polyId++ )
1901 {
1902 const SHAPE_POLY_SET::TRIANGULATED_POLYGON* tri = poly->TriangulatedPolygon( polyId );
1903
1904 for( size_t i = 0; i < tri->GetTriangleCount(); i++)
1905 {
1906 VECTOR2I a, b, c;
1907 tri->GetTriangle( i, a, b, c );
1908 SHAPE_SIMPLE* triShape = new SHAPE_SIMPLE;
1909
1910 triShape->Append( a );
1911 triShape->Append( b );
1912 triShape->Append( c );
1913
1914 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
1915
1916 solid->SetLayer( GetPNSLayerFromBoardLayer( layer ) );
1917 solid->SetNet( nullptr );
1918 solid->SetParent( aZone );
1919 solid->SetShape( triShape );
1920 solid->SetIsCompoundShapePrimitive();
1921 solid->SetRoutable( false );
1922
1923 aWorld->Add( std::move( solid ) );
1924 }
1925 }
1926 }
1927
1928 return true;
1929}
1930
1931
1933{
1934 if( !IsKicadCopperLayer( aLayer ) )
1935 return false;
1936
1937 if( aItem->Type() == PCB_FIELD_T && !static_cast<PCB_FIELD*>( aItem )->IsVisible() )
1938 return false;
1939
1940 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
1941 SHAPE_SIMPLE* shape = new SHAPE_SIMPLE;
1942
1943 solid->SetLayer( GetPNSLayerFromBoardLayer( aLayer ) );
1944 solid->SetNet( nullptr );
1945 solid->SetParent( aItem );
1946 solid->SetShape( shape ); // takes ownership
1947 solid->SetRoutable( false );
1948
1949 SHAPE_POLY_SET cornerBuffer;
1950
1951 aItem->TransformShapeToPolygon( cornerBuffer, aItem->GetLayer(), 0, aItem->GetMaxError(), ERROR_OUTSIDE );
1952
1953 cornerBuffer.Simplify();
1954
1955 if( !cornerBuffer.OutlineCount() )
1956 return false;
1957
1958 for( const VECTOR2I& pt : cornerBuffer.Outline( 0 ).CPoints() )
1959 shape->Append( pt );
1960
1961 aWorld->Add( std::move( solid ) );
1962
1963 return true;
1964}
1965
1966
1968{
1969 if( !IsKicadCopperLayer( aDimension->GetLayer() ) )
1970 return false;
1971
1972 auto addPolysToWorld =
1973 [&]( const SHAPE_POLY_SET& aPolys )
1974 {
1975 for( int ii = 0; ii < aPolys.OutlineCount(); ++ii )
1976 {
1977 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
1978 SHAPE_SIMPLE* shape = new SHAPE_SIMPLE;
1979
1980 solid->SetLayer( GetPNSLayerFromBoardLayer( aDimension->GetLayer() ) );
1981 solid->SetNet( nullptr );
1982 solid->SetParent( aDimension );
1983 solid->SetShape( shape ); // takes ownership
1984 solid->SetRoutable( false );
1985
1986 for( const VECTOR2I& pt : aPolys.Outline( ii ).CPoints() )
1987 shape->Append( pt );
1988
1989 aWorld->Add( std::move( solid ) );
1990 }
1991 };
1992
1993 SHAPE_POLY_SET cornerBuffer;
1994
1995 aDimension->TransformShapeToPolygon( cornerBuffer, aDimension->GetLayer(), 0,
1996 aDimension->GetMaxError(), ERROR_OUTSIDE );
1997
1998 cornerBuffer.Simplify();
1999
2000 if( cornerBuffer.OutlineCount() )
2001 addPolysToWorld( cornerBuffer );
2002
2003 // Footprints can have hidden dimensions
2004 if( aDimension->IsVisible() && !aDimension->GetText().IsEmpty() )
2005 {
2006 SHAPE_POLY_SET textBuffer;
2007
2008 aDimension->PCB_TEXT::TransformShapeToPolygon( textBuffer, aDimension->GetLayer(), 0,
2009 aDimension->GetMaxError(), ERROR_OUTSIDE );
2010
2011 textBuffer.Simplify();
2012
2013 if( textBuffer.OutlineCount() )
2014 addPolysToWorld( textBuffer );
2015 }
2016
2017 return cornerBuffer.OutlineCount() || !aDimension->GetText().IsEmpty();
2018}
2019
2020
2022{
2023 if( aItem->GetLayer() == Edge_Cuts
2024 || aItem->GetLayer() == Margin
2025 || IsKicadCopperLayer( aItem->GetLayer() ) )
2026 {
2027 std::vector<SHAPE*> shapes = aItem->MakeEffectiveShapes();
2028
2029 for( SHAPE* shape : shapes )
2030 {
2031 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
2032
2033 if( aItem->GetLayer() == Edge_Cuts || aItem->GetLayer() == Margin )
2034 {
2035 solid->SetLayers( PNS_LAYER_RANGE( 0, m_board->GetCopperLayerCount() - 1 ) );
2036 solid->SetRoutable( false );
2037 }
2038 else
2039 {
2040 solid->SetLayer( GetPNSLayerFromBoardLayer( aItem->GetLayer() ) );
2041 solid->SetRoutable( aItem->Type() != PCB_TABLECELL_T );
2042 }
2043
2044 if( aItem->GetLayer() == Edge_Cuts )
2045 {
2046 switch( shape->Type() )
2047 {
2048 case SH_SEGMENT: static_cast<SHAPE_SEGMENT*>( shape )->SetWidth( 0 ); break;
2049 case SH_ARC: static_cast<SHAPE_ARC*>( shape )->SetWidth( 0 ); break;
2050 case SH_LINE_CHAIN: static_cast<SHAPE_LINE_CHAIN*>( shape )->SetWidth( 0 ); break;
2051 default: /* remaining shapes don't have width */ break;
2052 }
2053 }
2054
2055 solid->SetAnchorPoints( aItem->GetConnectionPoints() );
2056 solid->SetNet( aItem->GetNet() );
2057 solid->SetParent( aItem );
2058 solid->SetShape( shape ); // takes ownership
2059
2060 if( shapes.size() > 1 )
2061 solid->SetIsCompoundShapePrimitive();
2062
2063 aWorld->Add( std::move( solid ) );
2064 }
2065
2066 return true;
2067 }
2068
2069 return false;
2070}
2071
2072
2074{
2075 if( IsKicadCopperLayer( aBarcode->GetLayer() ) )
2076 {
2077 SHAPE_POLY_SET cornerBuffer;
2078
2079 aBarcode->GetBoundingHull( cornerBuffer, aBarcode->GetLayer(), 0, aBarcode->GetMaxError(), ERROR_OUTSIDE );
2080
2081 if( !cornerBuffer.OutlineCount() )
2082 return false;
2083
2084 for( int ii = 0; ii < cornerBuffer.OutlineCount(); ++ii )
2085 {
2086 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
2087 SHAPE_SIMPLE* shape = new SHAPE_SIMPLE;
2088
2089 solid->SetLayer( GetPNSLayerFromBoardLayer( aBarcode->GetLayer() ) );
2090 solid->SetNet( nullptr );
2091 solid->SetParent( aBarcode );
2092 solid->SetShape( shape ); // takes ownership
2093 solid->SetRoutable( false );
2094
2095 for( const VECTOR2I& pt : cornerBuffer.Outline( ii ).CPoints() )
2096 shape->Append( pt );
2097
2098 aWorld->Add( std::move( solid ) );
2099 }
2100
2101 return true;
2102 }
2103
2104 return false;
2105}
2106
2107
2109{
2110 m_board = aBoard;
2111 wxLogTrace( wxT( "PNS" ), wxT( "m_board = %p" ), m_board );
2112}
2113
2114
2116{
2117 return ::IsCopperLayer( GetBoardLayerFromPNSLayer( aPNSLayer ) );
2118}
2119
2120
2121
2123{
2124 return ::IsCopperLayer( aKicadLayer );
2125}
2126
2127
2129{
2130 if( !m_view )
2131 return false;
2132
2133 for( int i = aLayer.Start(); i <= aLayer.End(); i++ )
2134 {
2135 if( m_view->IsLayerVisible( GetBoardLayerFromPNSLayer( i ) ) )
2136 return true;
2137 }
2138
2139 return false;
2140}
2141
2142
2143bool PNS_KICAD_IFACE_BASE::IsFlashedOnLayer( const PNS::ITEM* aItem, int aLayer ) const
2144{
2146 if( aLayer < 0 )
2147 return true;
2148
2149 if( aItem->Parent() )
2150 {
2151 switch( aItem->Parent()->Type() )
2152 {
2153 case PCB_VIA_T:
2154 {
2155 const PCB_VIA* via = static_cast<const PCB_VIA*>( aItem->Parent() );
2156
2157 return via->FlashLayer( GetBoardLayerFromPNSLayer( aLayer ) );
2158 }
2159
2160 case PCB_PAD_T:
2161 {
2162 const PAD* pad = static_cast<const PAD*>( aItem->Parent() );
2163
2164 return pad->FlashLayer( GetBoardLayerFromPNSLayer( aLayer ) );
2165 }
2166
2167 default:
2168 break;
2169 }
2170 }
2171
2172 if( aItem->OfKind( PNS::ITEM::VIA_T ) )
2173 return static_cast<const PNS::VIA*>( aItem )->ConnectsLayer( aLayer );
2174
2175 return aItem->Layers().Overlaps( aLayer );
2176}
2177
2178
2180{
2181 PNS_LAYER_RANGE test = aItem->Layers().Intersection( aLayer );
2182
2183 if( aItem->Parent() )
2184 {
2185 switch( aItem->Parent()->Type() )
2186 {
2187 case PCB_VIA_T:
2188 {
2189 const PCB_VIA* via = static_cast<const PCB_VIA*>( aItem->Parent() );
2190
2191 for( int layer = test.Start(); layer <= test.End(); ++layer )
2192 {
2193 if( via->FlashLayer( GetBoardLayerFromPNSLayer( layer ) ) )
2194 return true;
2195 }
2196
2197 return false;
2198 }
2199
2200 case PCB_PAD_T:
2201 {
2202 const PAD* pad = static_cast<const PAD*>( aItem->Parent() );
2203
2204 for( int layer = test.Start(); layer <= test.End(); ++layer )
2205 {
2206 if( pad->FlashLayer( GetBoardLayerFromPNSLayer( layer ) ) )
2207 return true;
2208 }
2209
2210 return false;
2211 }
2212
2213 default:
2214 break;
2215 }
2216 }
2217
2218 if( aItem->OfKind( PNS::ITEM::VIA_T ) )
2219 {
2220 const PNS::VIA* via = static_cast<const PNS::VIA*>( aItem );
2221
2222 for( int layer = test.Start(); layer <= test.End(); ++layer )
2223 {
2224 if( via->ConnectsLayer( layer ) )
2225 return true;
2226 }
2227
2228 return false;
2229 }
2230
2231 return test.Start() <= test.End();
2232}
2233
2234
2236{
2237 // by default, all items are visible (new ones created by the router have parent == NULL
2238 // as they have not been committed yet to the BOARD)
2239 if( !m_view || !aItem->Parent() )
2240 return true;
2241
2242 BOARD_ITEM* item = aItem->Parent();
2243 bool isOnVisibleLayer = true;
2244 RENDER_SETTINGS* settings = m_view->GetPainter()->GetSettings();
2245
2246 if( settings->GetHighContrast() )
2247 isOnVisibleLayer = item->IsOnLayer( settings->GetPrimaryHighContrastLayer() );
2248
2249 if( m_view->IsVisible( item ) && isOnVisibleLayer )
2250 {
2251 for( PCB_LAYER_ID layer : item->GetLayerSet() )
2252 {
2253 if( item->ViewGetLOD( layer, m_view ) < m_view->GetScale() )
2254 return true;
2255 }
2256 }
2257
2258 // Items hidden in the router are not hidden on the board
2259 if( m_hiddenItems.find( item ) != m_hiddenItems.end() )
2260 return true;
2261
2262 return false;
2263}
2264
2265
2267{
2268 if( !m_board )
2269 {
2270 wxLogTrace( wxT( "PNS" ), wxT( "No board attached, aborting sync." ) );
2271 return;
2272 }
2273
2274 int worstClearance = m_board->GetMaxClearanceValue();
2275
2276 m_world = aWorld;
2277
2278 for( BOARD_ITEM* gitem : m_board->Drawings() )
2279 {
2280 switch( gitem->Type() )
2281 {
2282 case PCB_SHAPE_T:
2283 case PCB_TEXTBOX_T:
2284 syncGraphicalItem( aWorld, static_cast<PCB_SHAPE*>( gitem ) );
2285 break;
2286
2287 case PCB_TEXT_T:
2288 syncTextItem( aWorld, static_cast<PCB_TEXT*>( gitem ), gitem->GetLayer() );
2289 break;
2290
2291 case PCB_TABLE_T:
2292 syncTextItem( aWorld, static_cast<PCB_TABLE*>( gitem ), gitem->GetLayer() );
2293 break;
2294
2295 case PCB_BARCODE_T:
2296 syncBarcode( aWorld, static_cast<PCB_BARCODE*>( gitem ) );
2297 break;
2298
2299 case PCB_DIM_ALIGNED_T:
2300 case PCB_DIM_CENTER_T:
2301 case PCB_DIM_RADIAL_T:
2303 case PCB_DIM_LEADER_T:
2304 syncDimension( aWorld, static_cast<PCB_DIMENSION_BASE*>( gitem ) );
2305 break;
2306
2307 case PCB_REFERENCE_IMAGE_T: // ignore
2308 case PCB_TARGET_T:
2309 break;
2310
2311 default:
2312 UNIMPLEMENTED_FOR( gitem->GetClass() );
2313 break;
2314 }
2315 }
2316
2317 SHAPE_POLY_SET buffer;
2318 SHAPE_POLY_SET* boardOutline = nullptr;
2319
2320 if( m_board->GetBoardPolygonOutlines( buffer, true ) )
2321 boardOutline = &buffer;
2322
2323 for( ZONE* zone : m_board->Zones() )
2324 {
2325 syncZone( aWorld, zone, boardOutline );
2326 }
2327
2328 for( FOOTPRINT* footprint : m_board->Footprints() )
2329 {
2330 for( PAD* pad : footprint->Pads() )
2331 {
2332 std::vector<std::unique_ptr<PNS::SOLID>> solids = syncPad( pad );
2333
2334 for( std::unique_ptr<PNS::SOLID>& solid : solids )
2335 aWorld->Add( std::move( solid ) );
2336
2337 std::optional<int> clearanceOverride = pad->GetClearanceOverrides( nullptr );
2338
2339 if( clearanceOverride.has_value() )
2340 worstClearance = std::max( worstClearance, clearanceOverride.value() );
2341
2342 if( pad->GetProperty() == PAD_PROP::CASTELLATED )
2343 {
2344 std::unique_ptr<SHAPE> hole;
2345 hole.reset( pad->GetEffectiveHoleShape()->Clone() );
2346 aWorld->AddEdgeExclusion( std::move( hole ) );
2347 }
2348 }
2349
2350 syncTextItem( aWorld, &footprint->Reference(), footprint->Reference().GetLayer() );
2351 syncTextItem( aWorld, &footprint->Value(), footprint->Value().GetLayer() );
2352
2353 for( ZONE* zone : footprint->Zones() )
2354 syncZone( aWorld, zone, boardOutline );
2355
2356 for( PCB_FIELD* field : footprint->GetFields() )
2357 syncTextItem( aWorld, static_cast<PCB_TEXT*>( field ), field->GetLayer() );
2358
2359 for( BOARD_ITEM* item : footprint->GraphicalItems() )
2360 {
2361 switch( item->Type() )
2362 {
2363 case PCB_SHAPE_T:
2364 case PCB_TEXTBOX_T:
2365 syncGraphicalItem( aWorld, static_cast<PCB_SHAPE*>( item ) );
2366 break;
2367
2368 case PCB_TEXT_T:
2369 syncTextItem( aWorld, static_cast<PCB_TEXT*>( item ), item->GetLayer() );
2370 break;
2371
2372 case PCB_TABLE_T:
2373 syncTextItem( aWorld, static_cast<PCB_TABLE*>( item ), item->GetLayer() );
2374 break;
2375
2376 case PCB_BARCODE_T:
2377 syncBarcode( aWorld, static_cast<PCB_BARCODE*>( item ) );
2378 break;
2379
2380 case PCB_DIM_ALIGNED_T:
2381 case PCB_DIM_CENTER_T:
2382 case PCB_DIM_RADIAL_T:
2384 case PCB_DIM_LEADER_T:
2385 syncDimension( aWorld, static_cast<PCB_DIMENSION_BASE*>( item ) );
2386 break;
2387
2388 case PCB_REFERENCE_IMAGE_T: // ignore
2389 break;
2390
2391 default:
2392 UNIMPLEMENTED_FOR( item->GetClass() );
2393 break;
2394 }
2395 }
2396 }
2397
2398 for( PCB_TRACK* t : m_board->Tracks() )
2399 {
2400 KICAD_T type = t->Type();
2401
2402 if( type == PCB_TRACE_T )
2403 {
2404 if( std::unique_ptr<PNS::SEGMENT> segment = syncTrack( t ) )
2405 aWorld->Add( std::move( segment ), true );
2406 }
2407 else if( type == PCB_ARC_T )
2408 {
2409 if( std::unique_ptr<PNS::ARC> arc = syncArc( static_cast<PCB_ARC*>( t ) ) )
2410 aWorld->Add( std::move( arc ), true );
2411 }
2412 else if( type == PCB_VIA_T )
2413 {
2414 if( std::unique_ptr<PNS::VIA> via = syncVia( static_cast<PCB_VIA*>( t ) ) )
2415 aWorld->Add( std::move( via ) );
2416 }
2417 }
2418
2419 // NB: if this were ever to become a long-lived object we would need to dirty its
2420 // clearance cache here....
2421 delete m_ruleResolver;
2423
2425 aWorld->SetMaxClearance( worstClearance + m_ruleResolver->ClearanceEpsilon() );
2426}
2427
2428
2430{
2431 for( BOARD_ITEM* item : m_hiddenItems )
2432 m_view->SetVisible( item, true );
2433
2434 m_hiddenItems.clear();
2435
2436 if( m_previewItems )
2437 {
2438 m_previewItems->FreeItems();
2439 m_view->Update( m_previewItems );
2440 }
2441
2442 if( m_debugDecorator )
2443 m_debugDecorator->Clear();
2444}
2445
2446
2451
2452
2453void PNS_KICAD_IFACE::DisplayItem( const PNS::ITEM* aItem, int aClearance, bool aEdit, int aFlags )
2454{
2455 if( aItem->IsVirtual() )
2456 return;
2457
2458 if( ZONE* zone = dynamic_cast<ZONE*>( aItem->Parent() ) )
2459 {
2460 if( zone->GetIsRuleArea() )
2461 aFlags |= PNS_SEMI_SOLID;
2462 }
2463
2464 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aItem, this, m_view, aFlags );
2465
2466 // Note: SEGMENT_T is used for placed tracks; LINE_T is used for the routing head
2468 static int tracksOrVias = tracks | PNS::ITEM::VIA_T;
2469
2470 if( aClearance >= 0 )
2471 {
2472 pitem->SetClearance( aClearance );
2473
2474 PCBNEW_SETTINGS* settings = static_cast<PCBNEW_SETTINGS*>( m_tool->GetManager()->GetSettings() );
2475
2476 switch( settings->m_Display.m_TrackClearance )
2477 {
2480 pitem->ShowClearance( aItem->OfKind( tracksOrVias ) );
2481 break;
2482
2484 pitem->ShowClearance( aItem->OfKind( tracksOrVias ) && !aEdit );
2485 break;
2486
2487 case SHOW_WHILE_ROUTING:
2488 pitem->ShowClearance( aItem->OfKind( tracks ) && !aEdit );
2489 break;
2490
2491 default:
2492 pitem->ShowClearance( false );
2493 break;
2494 }
2495 }
2496
2497 m_previewItems->Add( pitem );
2498 m_view->Update( m_previewItems );
2499}
2500
2501
2502void PNS_KICAD_IFACE::DisplayPathLine( const SHAPE_LINE_CHAIN& aLine, int aImportance )
2503{
2504 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aLine, this, m_view );
2506
2507 COLOR4D color;
2508
2509 if( aImportance >= 1 )
2510 color = COLOR4D( 1.0, 1.0, 0.0, 0.6 );
2511 else if( aImportance == 0 )
2512 color = COLOR4D( 0.7, 0.7, 0.7, 0.6 );
2513
2514 pitem->SetColor( color );
2515
2516 m_previewItems->Add( pitem );
2517 m_view->Update( m_previewItems );
2518}
2519
2520
2522{
2523 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aRatline, this, m_view );
2524
2525 KIGFX::RENDER_SETTINGS* renderSettings = m_view->GetPainter()->GetSettings();
2526 KIGFX::PCB_RENDER_SETTINGS* rs = static_cast<KIGFX::PCB_RENDER_SETTINGS*>( renderSettings );
2527 bool colorByNet = rs->GetNetColorMode() != NET_COLOR_MODE::OFF;
2528 COLOR4D defaultColor = rs->GetColor( nullptr, LAYER_RATSNEST );
2529 COLOR4D color = defaultColor;
2530
2531 std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_board->GetConnectivity();
2532 std::set<int> highlightedNets = rs->GetHighlightNetCodes();
2533 std::map<int, KIGFX::COLOR4D>& netColors = rs->GetNetColorMap();
2534 int netCode = -1;
2535
2536 if( NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aNet ) )
2537 netCode = net->GetNetCode();
2538
2539 const NETCLASS* nc = nullptr;
2540 const NET_SETTINGS* netSettings = connectivity->GetNetSettings();
2541
2542 if( connectivity->HasNetNameForNetCode( netCode ) )
2543 {
2544 const wxString& netName = connectivity->GetNetNameForNetCode( netCode );
2545
2546 if( netSettings && netSettings->HasEffectiveNetClass( netName ) )
2547 nc = netSettings->GetCachedEffectiveNetClass( netName ).get();
2548 }
2549
2550 if( colorByNet && netColors.count( netCode ) )
2551 color = netColors.at( netCode );
2552 else if( colorByNet && nc && nc->HasPcbColor() )
2553 color = nc->GetPcbColor();
2554 else
2555 color = defaultColor;
2556
2557 if( color == COLOR4D::UNSPECIFIED )
2558 color = defaultColor;
2559
2560 pitem->SetColor( color.Brightened( 0.5 ).WithAlpha( std::min( 1.0, color.a + 0.4 ) ) );
2561
2562 m_previewItems->Add( pitem );
2563 m_view->Update( m_previewItems );
2564}
2565
2566
2568{
2569 BOARD_ITEM* parent = aItem->Parent();
2570
2571 if( parent )
2572 {
2573 if( m_view->IsVisible( parent ) )
2574 m_hiddenItems.insert( parent );
2575
2576 m_view->SetVisible( parent, false );
2577 m_view->Update( parent, KIGFX::APPEARANCE );
2578
2579 for( ZONE* td : m_board->Zones() )
2580 {
2581 if( td->IsTeardropArea()
2582 && td->GetBoundingBox().Intersects( aItem->Parent()->GetBoundingBox() )
2583 && td->Outline()->Collide( aItem->Shape( td->GetLayer() ) ) )
2584 {
2585 m_view->SetVisible( td, false );
2586 m_view->Update( td, KIGFX::APPEARANCE );
2587 }
2588 }
2589 }
2590}
2591
2592
2596
2597
2599{
2600 BOARD_ITEM* parent = aItem->Parent();
2601
2602 if( aItem->OfKind( PNS::ITEM::SOLID_T ) && parent->Type() == PCB_PAD_T )
2603 {
2604 PAD* pad = static_cast<PAD*>( parent );
2605 VECTOR2I pos = static_cast<PNS::SOLID*>( aItem )->Pos();
2606
2607 m_fpOffsets[ pad ].p_old = pos;
2608 return;
2609 }
2610
2611 if( parent )
2612 {
2613 if( EDA_GROUP* group = parent->GetParentGroup() )
2614 m_itemGroups[parent] = group;
2615
2616 m_commit->Remove( parent );
2617 }
2618}
2619
2620
2624
2625
2627{
2628 BOARD_ITEM* board_item = aItem->Parent();
2629
2630 switch( aItem->Kind() )
2631 {
2632 case PNS::ITEM::ARC_T:
2633 {
2634 PNS::ARC* arc = static_cast<PNS::ARC*>( aItem );
2635 PCB_ARC* arc_board = static_cast<PCB_ARC*>( board_item );
2636 const SHAPE_ARC* arc_shape = static_cast<const SHAPE_ARC*>( arc->Shape( -1 ) );
2637
2638 m_commit->Modify( arc_board );
2639
2640 arc_board->SetStart( VECTOR2I( arc_shape->GetP0() ) );
2641 arc_board->SetEnd( VECTOR2I( arc_shape->GetP1() ) );
2642 arc_board->SetMid( VECTOR2I( arc_shape->GetArcMid() ) );
2643 arc_board->SetWidth( arc->Width() );
2644 break;
2645 }
2646
2648 {
2649 PNS::SEGMENT* seg = static_cast<PNS::SEGMENT*>( aItem );
2650 PCB_TRACK* track = static_cast<PCB_TRACK*>( board_item );
2651 const SEG& s = seg->Seg();
2652
2653 m_commit->Modify( track );
2654
2655 track->SetStart( VECTOR2I( s.A.x, s.A.y ) );
2656 track->SetEnd( VECTOR2I( s.B.x, s.B.y ) );
2657 track->SetWidth( seg->Width() );
2658 break;
2659 }
2660
2661 case PNS::ITEM::VIA_T:
2662 {
2663 PCB_VIA* via_board = static_cast<PCB_VIA*>( board_item );
2664 PNS::VIA* via = static_cast<PNS::VIA*>( aItem );
2665
2666 m_commit->Modify( via_board );
2667
2668 via_board->SetPosition( VECTOR2I( via->Pos().x, via->Pos().y ) );
2669 via_board->SetWidth( PADSTACK::ALL_LAYERS, via->Diameter( 0 ) );
2670 via_board->SetDrill( via->Drill() );
2671 via_board->SetNet( static_cast<NETINFO_ITEM*>( via->Net() ) );
2672 via_board->SetViaType( via->ViaType() ); // MUST be before SetLayerPair()
2673 via_board->Padstack().SetUnconnectedLayerMode( via->UnconnectedLayerMode() );
2674 via_board->SetIsFree( via->IsFree() );
2675 via_board->SetLayerPair( GetBoardLayerFromPNSLayer( via->Layers().Start() ),
2676 GetBoardLayerFromPNSLayer( via->Layers().End() ) );
2677
2678 PNS_LAYER_RANGE holeLayers = via->HoleLayers();
2679
2680 if( holeLayers.Start() >= 0 && holeLayers.End() >= 0 )
2681 {
2682 via_board->SetPrimaryDrillStartLayer( GetBoardLayerFromPNSLayer( holeLayers.Start() ) );
2683 via_board->SetPrimaryDrillEndLayer( GetBoardLayerFromPNSLayer( holeLayers.End() ) );
2684 }
2685
2686 via_board->SetFrontPostMachining( via->HolePostMachining() );
2687 via_board->SetSecondaryDrillSize( via->SecondaryDrill() );
2688
2689 if( std::optional<PNS_LAYER_RANGE> secondaryLayers = via->SecondaryHoleLayers() )
2690 {
2691 via_board->SetSecondaryDrillStartLayer( GetBoardLayerFromPNSLayer( secondaryLayers->Start() ) );
2692 via_board->SetSecondaryDrillEndLayer( GetBoardLayerFromPNSLayer( secondaryLayers->End() ) );
2693 }
2694 else
2695 {
2698 }
2699
2700 break;
2701 }
2702
2703 case PNS::ITEM::SOLID_T:
2704 {
2705 if( aItem->Parent()->Type() == PCB_PAD_T )
2706 {
2707 PAD* pad = static_cast<PAD*>( aItem->Parent() );
2708 VECTOR2I pos = static_cast<PNS::SOLID*>( aItem )->Pos();
2709
2710 // Don't add to commit; we'll add the parent footprints when processing the m_fpOffsets
2711
2712 m_fpOffsets[pad].p_old = pad->GetPosition();
2713 m_fpOffsets[pad].p_new = pos;
2714 }
2715 break;
2716 }
2717
2718 default:
2719 m_commit->Modify( aItem->Parent() );
2720 break;
2721 }
2722}
2723
2724
2726{
2727 modifyBoardItem( aItem );
2728}
2729
2730
2732{
2733}
2734
2735
2737{
2738 BOARD_CONNECTED_ITEM* newBoardItem = nullptr;
2739 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aItem->Net() );
2740
2741 if( !net )
2743
2744 switch( aItem->Kind() )
2745 {
2746 case PNS::ITEM::ARC_T:
2747 {
2748 PNS::ARC* arc = static_cast<PNS::ARC*>( aItem );
2749 PCB_ARC* new_arc = new PCB_ARC( m_board, static_cast<const SHAPE_ARC*>( arc->Shape( -1 ) ) );
2750 new_arc->SetWidth( arc->Width() );
2751 new_arc->SetLayer( GetBoardLayerFromPNSLayer( arc->Layers().Start() ) );
2752 new_arc->SetNet( net );
2753
2754 if( aItem->GetSourceItem() && aItem->GetSourceItem()->IsType( { PCB_TRACE_T, PCB_ARC_T } ) )
2755 {
2756 PCB_TRACK* sourceTrack = static_cast<PCB_TRACK*>( aItem->GetSourceItem() );
2757 new_arc->SetHasSolderMask( sourceTrack->HasSolderMask() );
2758 new_arc->SetLocalSolderMaskMargin( sourceTrack->GetLocalSolderMaskMargin() );
2759 }
2760
2761 newBoardItem = new_arc;
2762 break;
2763 }
2764
2766 {
2767 PNS::SEGMENT* seg = static_cast<PNS::SEGMENT*>( aItem );
2768 PCB_TRACK* track = new PCB_TRACK( m_board );
2769 const SEG& s = seg->Seg();
2770 track->SetStart( VECTOR2I( s.A.x, s.A.y ) );
2771 track->SetEnd( VECTOR2I( s.B.x, s.B.y ) );
2772 track->SetWidth( seg->Width() );
2773 track->SetLayer( GetBoardLayerFromPNSLayer( seg->Layers().Start() ) );
2774 track->SetNet( net );
2775
2776 if( aItem->GetSourceItem() && aItem->GetSourceItem()->IsType( { PCB_TRACE_T, PCB_ARC_T } ) )
2777 {
2778 PCB_TRACK* sourceTrack = static_cast<PCB_TRACK*>( aItem->GetSourceItem() );
2779 track->SetHasSolderMask( sourceTrack->HasSolderMask() );
2780 track->SetLocalSolderMaskMargin( sourceTrack->GetLocalSolderMaskMargin() );
2781 }
2782
2783 newBoardItem = track;
2784 break;
2785 }
2786
2787 case PNS::ITEM::VIA_T:
2788 {
2789 PCB_VIA* via_board = new PCB_VIA( m_board );
2790 PNS::VIA* via = static_cast<PNS::VIA*>( aItem );
2791 via_board->SetPosition( VECTOR2I( via->Pos().x, via->Pos().y ) );
2792 via_board->SetWidth( PADSTACK::ALL_LAYERS, via->Diameter( 0 ) );
2793 via_board->SetDrill( via->Drill() );
2794 via_board->SetNet( net );
2795 via_board->SetViaType( via->ViaType() ); // MUST be before SetLayerPair()
2796 via_board->Padstack().SetUnconnectedLayerMode( via->UnconnectedLayerMode() );
2797 via_board->SetIsFree( via->IsFree() );
2798 via_board->SetLayerPair( GetBoardLayerFromPNSLayer( via->Layers().Start() ),
2799 GetBoardLayerFromPNSLayer( via->Layers().End() ) );
2800
2801 PNS_LAYER_RANGE holeLayers = via->HoleLayers();
2802
2803 if( holeLayers.Start() >= 0 && holeLayers.End() >= 0 )
2804 {
2805 via_board->SetPrimaryDrillStartLayer( GetBoardLayerFromPNSLayer( holeLayers.Start() ) );
2806 via_board->SetPrimaryDrillEndLayer( GetBoardLayerFromPNSLayer( holeLayers.End() ) );
2807 }
2808
2809 via_board->SetFrontPostMachining( via->HolePostMachining() );
2810 via_board->SetSecondaryDrillSize( via->SecondaryDrill() );
2811
2812 if( std::optional<PNS_LAYER_RANGE> secondaryLayers = via->SecondaryHoleLayers() )
2813 {
2814 via_board->SetSecondaryDrillStartLayer( GetBoardLayerFromPNSLayer( secondaryLayers->Start() ) );
2815 via_board->SetSecondaryDrillEndLayer( GetBoardLayerFromPNSLayer( secondaryLayers->End() ) );
2816 }
2817 else
2818 {
2821 }
2822
2823 if( aItem->GetSourceItem() && aItem->GetSourceItem()->Type() == PCB_VIA_T )
2824 {
2825 PCB_VIA* sourceVia = static_cast<PCB_VIA*>( aItem->GetSourceItem() );
2826 via_board->SetFrontTentingMode( sourceVia->GetFrontTentingMode() );
2827 via_board->SetBackTentingMode( sourceVia->GetBackTentingMode() );
2828 }
2829
2830 newBoardItem = via_board;
2831 break;
2832 }
2833
2834 case PNS::ITEM::SOLID_T:
2835 {
2836 PAD* pad = static_cast<PAD*>( aItem->Parent() );
2837 VECTOR2I pos = static_cast<PNS::SOLID*>( aItem )->Pos();
2838
2839 m_fpOffsets[pad].p_new = pos;
2840 return nullptr;
2841 }
2842
2843 default:
2844 return nullptr;
2845 }
2846
2847 if( net->GetNetCode() <= 0 )
2848 {
2849 NETINFO_ITEM* newNetInfo = newBoardItem->GetNet();
2850
2851 newNetInfo->SetParent( m_board );
2852 newNetInfo->SetNetClass( m_board->GetDesignSettings().m_NetSettings->GetDefaultNetclass() );
2853 }
2854
2855 if( newBoardItem )
2856 {
2857 if( aItem->IsLocked() )
2858 newBoardItem->SetLocked( true );
2859
2860 if( BOARD_ITEM* src = aItem->GetSourceItem() )
2861 {
2862 if( m_itemGroups.contains( src ) )
2863 m_replacementMap[src].push_back( newBoardItem );
2864 }
2865 else
2866 {
2867 // This is a new item, which goes in the entered group (if any)
2868 m_replacementMap[ENTERED_GROUP_MAGIC_NUMBER].push_back( newBoardItem );
2869 }
2870 }
2871
2872 return newBoardItem;
2873}
2874
2875
2877{
2878 BOARD_CONNECTED_ITEM* boardItem = createBoardItem( aItem );
2879
2880 if( boardItem )
2881 {
2882 aItem->SetParent( boardItem );
2883 boardItem->ClearFlags();
2884
2885 m_commit->Add( boardItem );
2886 }
2887}
2888
2889
2891{
2892 PCB_SELECTION_TOOL* selTool = m_tool->GetManager()->GetTool<PCB_SELECTION_TOOL>();
2893 std::set<FOOTPRINT*> processedFootprints;
2894
2895 EraseView();
2896
2897 for( const auto& [ pad, fpOffset ] : m_fpOffsets )
2898 {
2899 VECTOR2I offset = fpOffset.p_new - fpOffset.p_old;
2900 FOOTPRINT* footprint = pad->GetParentFootprint();
2901 VECTOR2I p_orig = footprint->GetPosition();
2902 VECTOR2I p_new = p_orig + offset;
2903
2904 if( processedFootprints.find( footprint ) != processedFootprints.end() )
2905 continue;
2906
2907 processedFootprints.insert( footprint );
2908 m_commit->Modify( footprint );
2909 footprint->SetPosition( p_new );
2910 }
2911
2912 m_fpOffsets.clear();
2913
2914 for( const auto& [ src, items ] : m_replacementMap )
2915 {
2916 EDA_GROUP* group = nullptr;
2917
2918 if( src == ENTERED_GROUP_MAGIC_NUMBER )
2919 group = selTool ? selTool->GetEnteredGroup() : nullptr;
2920 else if( auto it = m_itemGroups.find( src ); it != m_itemGroups.end() )
2921 group = it->second;
2922
2923 if( group )
2924 {
2925 m_commit->Modify( group->AsEdaItem(), nullptr, RECURSE_MODE::NO_RECURSE );
2926
2927 for( BOARD_ITEM* bi : items )
2928 group->AddItem( bi );
2929 }
2930 }
2931
2932 m_itemGroups.clear();
2933 m_replacementMap.clear();
2934
2935 m_commit->Push( _( "Routing" ), m_commitFlags | SKIP_ENTERED_GROUP );
2936 m_commit = std::make_unique<BOARD_COMMIT>( m_tool );
2937}
2938
2939
2941{
2942 return static_cast<EDA_UNITS>( m_tool->GetManager()->GetSettings()->m_System.units );
2943}
2944
2945
2947{
2948 wxLogTrace( wxT( "PNS" ), wxT( "SetView %p" ), aView );
2949
2950 if( m_previewItems )
2951 {
2952 m_previewItems->FreeItems();
2953 delete m_previewItems;
2954 }
2955
2956 m_view = aView;
2959
2960 if(m_view)
2961 m_view->Add( m_previewItems );
2962
2963 delete m_debugDecorator;
2964
2965 auto dec = new PNS_PCBNEW_DEBUG_DECORATOR( this );
2966 m_debugDecorator = dec;
2967
2968 dec->SetDebugEnabled( ADVANCED_CFG::GetCfg().m_ShowRouterDebugGraphics );
2969
2970 if( ADVANCED_CFG::GetCfg().m_ShowRouterDebugGraphics )
2971 dec->SetView( m_view );
2972}
2973
2974
2976{
2977 if( aNet )
2978 return static_cast<NETINFO_ITEM*>( aNet )->GetNetCode();
2979 else
2980 return -1;
2981}
2982
2983
2985{
2986 if( aNet )
2987 return static_cast<NETINFO_ITEM*>( aNet )->GetNetname();
2988 else
2989 return wxEmptyString;
2990}
2991
2992
2994{
2995 wxLogTrace( wxT( "PNS" ), wxT( "Update-net %s" ), GetNetName( aNet ) );
2996}
2997
2998
3003
3004
3009
3010
3012{
3013 m_tool = aTool;
3014 m_commit = std::make_unique<BOARD_COMMIT>( m_tool );
3015}
3016
3017
3019{
3020 if( aLayer < 0 || aLayer >= m_board->GetCopperLayerCount() )
3022
3023 if( aLayer == 0 )
3024 return F_Cu;
3025
3026 if( aLayer == m_board->GetCopperLayerCount() - 1 )
3027 return B_Cu;
3028
3029 return static_cast<PCB_LAYER_ID>( ( aLayer + 1 ) * 2 );
3030}
3031
3032
3034{
3035 if( aLayer < 0 )
3036 return -1;
3037
3038 if( aLayer == F_Cu )
3039 return 0;
3040
3041 if( aLayer == B_Cu )
3042 return m_board->GetCopperLayerCount() - 1;
3043
3044 return ( aLayer / 2 ) - 1;
3045}
3046
3048 long long& aExtraLength, long long& aExtraDelay ) const
3049{
3050 aExtraLength = 0;
3051 aExtraDelay = 0;
3052 if( !m_board || !aNetP || !aNetN )
3053 return false;
3054
3055 auto* netP = static_cast<NETINFO_ITEM*>( aNetP );
3056 auto* netN = static_cast<NETINFO_ITEM*>( aNetN );
3057 wxString sig = netP->GetNetChain();
3058 if( sig.IsEmpty() || sig != netN->GetNetChain() )
3059 return false;
3060
3061 // Build the set of net codes to exclude (the nets the caller is already accounting for).
3062 std::set<int> exclude;
3063 exclude.insert( netP->GetNetCode() );
3064 if( netP != netN )
3065 exclude.insert( netN->GetNetCode() );
3066
3067 // Sum routed length/delay of every other net in the chain.
3068 for( NETINFO_ITEM* net : m_board->GetNetInfo() )
3069 {
3070 if( net->GetNetChain() != sig )
3071 continue;
3072 if( exclude.count( net->GetNetCode() ) )
3073 continue;
3074
3075 PCB_TRACK* rep = nullptr;
3076
3077 for( BOARD_ITEM* bi : m_board->Tracks() )
3078 {
3079 if( auto tr = dynamic_cast<PCB_TRACK*>( bi ) )
3080 {
3081 if( tr->GetNetCode() == net->GetNetCode() )
3082 {
3083 rep = tr;
3084 break;
3085 }
3086 }
3087 }
3088
3089 if( rep )
3090 {
3091 int count = 0; double trk = 0, pad = 0, tDelay = 0, padDelay = 0;
3092 std::tie( count, trk, pad, tDelay, padDelay ) = m_board->GetTrackLength( *rep );
3093 aExtraLength += KiROUND<double, long long>( trk + pad );
3094
3095 if( tDelay > 0.0 || padDelay > 0.0 )
3096 aExtraDelay += KiROUND<double, long long>( tDelay + padDelay );
3097 }
3098 }
3099
3100 // Chain is valid; return true even if no sibling nets carry routed length yet so the
3101 // placer applies the full chain budget to the net being routed first.
3102 return true;
3103}
3104
3106 long long& aExtraLength, long long& aExtraDelay ) const
3107{
3108 return PNS_KICAD_IFACE_BASE::GetSignalAggregate( aNetP, aNetN, aExtraLength, aExtraDelay );
3109}
3110
3111
3113{
3114 if( !m_board || !aNet )
3115 return 0;
3116
3117 auto* ni = static_cast<NETINFO_ITEM*>( aNet );
3118
3119 for( BOARD_ITEM* bi : m_board->Tracks() )
3120 {
3121 if( auto tr = dynamic_cast<PCB_TRACK*>( bi ) )
3122 {
3123 if( tr->GetNetCode() == ni->GetNetCode() )
3124 {
3125 int count = 0; double trk = 0, pad = 0, tDelay = 0, padDelay = 0;
3126 std::tie( count, trk, pad, tDelay, padDelay ) = m_board->GetTrackLength( *tr );
3127 return KiROUND<double, long long>( trk + pad );
3128 }
3129 }
3130 }
3131
3132 return 0;
3133}
3134
3135
3140
3141
3146
3147
3149 const PNS::SOLID* aEndPad, const NETCLASS* aNetClass )
3150{
3151 std::vector<LENGTH_DELAY_CALCULATION_ITEM> lengthItems = GetLengthDelayCalculationItems( aLine, aNetClass );
3152
3153 const PAD* startPad = nullptr;
3154 const PAD* endPad = nullptr;
3155
3156 if( aStartPad )
3157 startPad = static_cast<PAD*>( aStartPad->Parent() );
3158
3159 if( aEndPad )
3160 endPad = static_cast<PAD*>( aEndPad->Parent() );
3161
3162 constexpr PATH_OPTIMISATIONS opts = {
3163 .OptimiseVias = false,
3164 .MergeTracks = false,
3165 .OptimiseTracesInPads = false,
3166 .InferViaInPad = true
3167 };
3168 const BOARD* board = GetBoard();
3169 return board->GetLengthCalculation()->CalculateLength( lengthItems, opts, startPad, endPad );
3170}
3171
3172
3174 const PNS::SOLID* aEndPad, const NETCLASS* aNetClass )
3175{
3176 std::vector<LENGTH_DELAY_CALCULATION_ITEM> lengthItems = GetLengthDelayCalculationItems( aLine, aNetClass );
3177
3178 const PAD* startPad = nullptr;
3179 const PAD* endPad = nullptr;
3180
3181 if( aStartPad )
3182 startPad = static_cast<PAD*>( aStartPad->Parent() );
3183
3184 if( aEndPad )
3185 endPad = static_cast<PAD*>( aEndPad->Parent() );
3186
3187 constexpr PATH_OPTIMISATIONS opts = {
3188 .OptimiseVias = false,
3189 .MergeTracks = false,
3190 .OptimiseTracesInPads = false,
3191 .InferViaInPad = true
3192 };
3193 const BOARD* board = GetBoard();
3194 return board->GetLengthCalculation()->CalculateDelay( lengthItems, opts, startPad, endPad );
3195}
3196
3197
3198int64_t PNS_KICAD_IFACE_BASE::CalculateLengthForDelay( int64_t aDesiredDelay, const int aWidth,
3199 const bool aIsDiffPairCoupled, const int aDiffPairCouplingGap,
3200 const int aPNSLayer, const NETCLASS* aNetClass )
3201{
3203 ctx.NetClass = aNetClass;
3204 ctx.Width = aWidth;
3205 ctx.IsDiffPairCoupled = aIsDiffPairCoupled;
3206 ctx.DiffPairCouplingGap = aDiffPairCouplingGap;
3207 ctx.Layer = GetBoardLayerFromPNSLayer( aPNSLayer );
3208
3209 const BOARD* board = GetBoard();
3210 return board->GetLengthCalculation()->CalculateLengthForDelay( aDesiredDelay, ctx );
3211}
3212
3213
3215 bool aIsDiffPairCoupled, int aDiffPairCouplingGap,
3216 int aPNSLayer, const NETCLASS* aNetClass )
3217{
3219 ctx.NetClass = aNetClass;
3220 ctx.Width = aWidth;
3221 ctx.IsDiffPairCoupled = aIsDiffPairCoupled;
3222 ctx.DiffPairCouplingGap = aDiffPairCouplingGap;
3223 ctx.Layer = GetBoardLayerFromPNSLayer( aPNSLayer );
3224
3225 const BOARD* board = GetBoard();
3227}
3228
3229
3230std::vector<LENGTH_DELAY_CALCULATION_ITEM>
3232{
3233 std::vector<LENGTH_DELAY_CALCULATION_ITEM> lengthItems;
3234
3235 for( int idx = 0; idx < aLine.Size(); idx++ )
3236 {
3237 const PNS::ITEM* lineItem = aLine[idx];
3238
3239 if( const PNS::LINE* l = dyn_cast<const PNS::LINE*>( lineItem ) )
3240 {
3242 item.SetLine( l->CLine() );
3243
3244 const PCB_LAYER_ID layer = GetBoardLayerFromPNSLayer( lineItem->Layer() );
3245 item.SetLayers( layer );
3246 item.SetEffectiveNetClass( aNetClass );
3247 item.SetWidth( l->Width() );
3248
3249 lengthItems.emplace_back( std::move( item ) );
3250 }
3251 else if( lineItem->OfKind( PNS::ITEM::VIA_T ) && idx > 0 && idx < aLine.Size() - 1 )
3252 {
3253 const int layerPrev = aLine[idx - 1]->Layer();
3254 const int layerNext = aLine[idx + 1]->Layer();
3255 const PCB_LAYER_ID pcbLayerPrev = GetBoardLayerFromPNSLayer( layerPrev );
3256 const PCB_LAYER_ID pcbLayerNext = GetBoardLayerFromPNSLayer( layerNext );
3257
3258 if( layerPrev != layerNext )
3259 {
3261 item.SetVia( static_cast<PCB_VIA*>( lineItem->GetSourceItem() ) );
3262 item.SetLayers( pcbLayerPrev, pcbLayerNext ); // TODO: BUG IS HERE!!!
3263 item.SetEffectiveNetClass( aNetClass );
3264 lengthItems.emplace_back( std::move( item ) );
3265 }
3266 }
3267 }
3268
3269 return lengthItems;
3270}
@ ERROR_OUTSIDE
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:125
#define SKIP_ENTERED_GROUP
@ OFF
Net (and netclass) colors are not shown.
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
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:84
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition board_item.h:268
void SetLocked(bool aLocked) override
Definition board_item.h:359
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:350
FOOTPRINT * GetParentFootprint() const
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition board_item.h:288
virtual bool HasDrilledHole() const
Definition board_item.h:185
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:175
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:323
LENGTH_DELAY_CALCULATION * GetLengthCalculation() const
Returns the track length calculator.
Definition board.h:1434
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:558
constexpr void SetOrigin(const Vec &pos)
Definition box2.h:237
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:146
constexpr const Vec & GetOrigin() const
Definition box2.h:210
constexpr const SizeVec & GetSize() const
Definition box2.h:206
constexpr void SetEnd(coord_type x, coord_type y)
Definition box2.h:297
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:311
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition color4d.h:402
wxString GetName() const
Definition drc_rule.h:208
SEVERITY GetSeverity() const
Definition drc_rule.h:221
const MINOPTMAX< int > & GetValue() const
Definition drc_rule.h:200
MINOPTMAX< int > m_Value
Definition drc_rule.h:244
bool GetOption(OPTIONS option) const
Definition drc_rule.h:233
DRC_RULE * GetParentRule() const
Definition drc_rule.h:204
bool IsNull() const
Definition drc_rule.h:195
bool IsImplicit() const
Definition drc_rule.h:147
DRC_IMPLICIT_SOURCE GetImplicitSource() const
Definition drc_rule.h:151
A set of EDA_ITEMs (i.e., without duplicates).
Definition eda_group.h:46
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:139
virtual EDA_GROUP * GetParentGroup() const
Definition eda_item.h:118
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:112
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:158
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition eda_item.h:206
virtual std::vector< SHAPE * > MakeEffectiveShapes(bool aEdgeOnly=false) const
Make a set of SHAPE objects representing the EDA_SHAPE.
Definition eda_shape.h:457
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:114
virtual bool IsVisible() const
Definition eda_text.h:212
void SetPosition(const VECTOR2I &aPos) override
bool IsNetTie() const
Definition footprint.h:508
VECTOR2I GetPosition() const override
Definition footprint.h:405
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition kidialog.h:42
@ KD_WARNING
Definition kidialog.h:47
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
Definition kidialog.cpp:55
int ShowModal() override
Definition kidialog.cpp:93
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:105
COLOR4D WithAlpha(double aAlpha) const
Return a color with the same color, but the given alpha.
Definition color4d.h:312
double a
Alpha component.
Definition color4d.h:396
COLOR4D Brightened(double aFactor) const
Return a color that is brighter by a given factor, without modifying object.
Definition color4d.h:269
PCB specific render settings.
Definition pcb_painter.h:82
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:43
virtual double ViewGetLOD(int aLayer, const VIEW *aView) const
Return the level of detail (LOD) of the item.
Definition view_item.h:155
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:67
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:263
T Min() const
Definition minoptmax.h:33
void SetMin(T v)
Definition minoptmax.h:41
bool HasMin() const
Definition minoptmax.h:37
T Opt() const
Definition minoptmax.h:35
A collection of nets and the parameters used to route or test these nets.
Definition netclass.h:42
COLOR4D GetPcbColor(bool aIsForSave=false) const
Definition netclass.h:186
bool HasPcbColor() const
Definition netclass.h:185
Handle the data for a net.
Definition netinfo.h:50
const wxString & GetNetChain() const
Definition netinfo.h:116
const wxString & GetNetname() const
Definition netinfo.h:104
int GetNetCode() const
Definition netinfo.h:98
void SetParent(BOARD *aParent)
Definition netinfo.h:169
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:268
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:65
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition pad.h:580
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:966
const VECTOR2I & GetDrillSize() const
Definition pad.h:337
PAD_ATTRIB GetAttribute() const
Definition pad.h:583
int GetPadToDieDelay() const
Definition pad.h:604
const PADSTACK & Padstack() const
Definition pad.h:353
const VECTOR2I & GetOffset(PCB_LAYER_ID aLayer) const
Definition pad.h:349
bool IsFreePad() const
Definition pad.cpp:366
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition pad.h:440
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(PCB_LAYER_ID aLayer, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition pad.cpp:952
VECTOR2I ShapePos(PCB_LAYER_ID aLayer) const
Definition pad.cpp:1562
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
Return a SHAPE_SEGMENT object representing the pad's hole.
Definition pad.cpp:1070
int GetPadToDieLength() const
Definition pad.h:601
DISPLAY_OPTIONS m_Display
void SetMid(const VECTOR2I &aMid)
Definition pcb_track.h:289
const VECTOR2I & GetMid() const
Definition pcb_track.h:290
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:71
void SetHasSolderMask(bool aVal)
Definition pcb_track.h:120
void SetEnd(const VECTOR2I &aEnd)
Definition pcb_track.h:93
bool HasSolderMask() const
Definition pcb_track.h:121
void SetStart(const VECTOR2I &aStart)
Definition pcb_track.h:96
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
Definition pcb_track.h:123
std::optional< int > GetLocalSolderMaskMargin() const
Definition pcb_track.h:124
const VECTOR2I & GetStart() const
Definition pcb_track.h:97
const VECTOR2I & GetEnd() const
Definition pcb_track.h:94
virtual void SetWidth(int aWidth)
Definition pcb_track.h:90
virtual int GetWidth() const
Definition pcb_track.h:91
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:810
PCB_LAYER_ID BottomLayer() const
VECTOR2I GetPosition() const override
Definition pcb_track.h:557
const PADSTACK & Padstack() const
Definition pcb_track.h:406
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:680
void SetDrill(int aDrill)
Definition pcb_track.h:748
PCB_LAYER_ID GetSecondaryDrillEndLayer() const
Definition pcb_track.h:784
void SetBackTentingMode(TENTING_MODE aMode)
void SetIsFree(bool aFree=true)
Definition pcb_track.h:811
PCB_LAYER_ID GetPrimaryDrillStartLayer() const
Definition pcb_track.h:674
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:677
void SetPosition(const VECTOR2I &aPoint) override
Definition pcb_track.h:558
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:399
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:398
PCB_LAYER_ID GetSecondaryDrillStartLayer() const
Definition pcb_track.h:781
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 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:42
VECTOR2I A
Definition seg.h:49
VECTOR2I::extended_type ecoord
Definition seg.h:44
VECTOR2I B
Definition seg.h:50
const VECTOR2I & GetArcMid() const
Definition shape_arc.h:120
const VECTOR2I & GetP1() const
Definition shape_arc.h:119
const VECTOR2I & GetP0() const
Definition shape_arc.h:118
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:128
double Distance(const VECTOR2< extended_type > &aVector) const
Compute the distance between two vectors.
Definition vector2d.h:553
static constexpr extended_type ECOORD_MAX
Definition vector2d.h:76
VECTOR2_TRAITS< int32_t >::extended_type extended_type
Definition vector2d.h:73
Handle a list of polygons defining a copper zone.
Definition zone.h:74
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
Definition zone.cpp:1300
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition zone.h:802
bool GetDoNotAllowVias() const
Definition zone.h:813
bool GetDoNotAllowPads() const
Definition zone.h:815
bool GetDoNotAllowTracks() const
Definition zone.h:814
SHAPE_POLY_SET * Outline()
Definition zone.h:422
bool GetDoNotAllowFootprints() const
Definition zone.h:816
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition zone.h:137
bool HasKeepoutParametersSet() const
Accessor to determine if any keepout parameters are set.
Definition zone.h:793
DRC_CONSTRAINT_T
Definition drc_rule.h:53
@ VIA_DIAMETER_CONSTRAINT
Definition drc_rule.h:76
@ DIFF_PAIR_GAP_CONSTRAINT
Definition drc_rule.h:82
@ TRACK_WIDTH_CONSTRAINT
Definition drc_rule.h:65
@ EDGE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:59
@ LENGTH_CONSTRAINT
Definition drc_rule.h:77
@ PHYSICAL_HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:87
@ CLEARANCE_CONSTRAINT
Definition drc_rule.h:55
@ MAX_UNCOUPLED_CONSTRAINT
Definition drc_rule.h:83
@ SKEW_CONSTRAINT
Definition drc_rule.h:81
@ HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:57
@ HOLE_SIZE_CONSTRAINT
Definition drc_rule.h:60
@ PHYSICAL_CLEARANCE_CONSTRAINT
Definition drc_rule.h:86
@ HOLE_TO_HOLE_CONSTRAINT
Definition drc_rule.h:58
#define _(s)
@ NO_RECURSE
Definition eda_item.h:54
#define ROUTER_TRANSIENT
transient items that should NOT be cached
#define IN_EDIT
Item currently edited.
EDA_UNITS
Definition eda_units.h:48
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:32
constexpr PCB_LAYER_ID PCBNEW_LAYER_ID_START
Definition layer_ids.h:174
@ ALWAYS_FLASHED
Always flashed for connectivity.
Definition layer_ids.h:186
@ LAYER_RATSNEST
Definition layer_ids.h:253
@ LAYER_SELECT_OVERLAY
Selected items overlay.
Definition layer_ids.h:280
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ Edge_Cuts
Definition layer_ids.h:112
@ B_Cu
Definition layer_ids.h:65
@ Margin
Definition layer_ids.h:113
@ UNDEFINED_LAYER
Definition layer_ids.h:61
@ PCB_LAYER_ID_COUNT
Definition layer_ids.h:171
@ F_Cu
Definition layer_ids.h:64
This file contains miscellaneous commonly used macros and functions.
#define UNIMPLEMENTED_FOR(type)
Definition macros.h:96
@ APPEARANCE
Visibility flag has changed.
Definition view_item.h:53
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:48
@ SH_ARC
circular arc
Definition shape.h:54
@ SH_LINE_CHAIN
line chain (polyline)
Definition shape.h:49
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:229
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:75
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:85
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition typeinfo.h:103
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition typeinfo.h:100
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:94
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition typeinfo.h:101
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:90
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition typeinfo.h:105
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:89
@ PCB_REFERENCE_IMAGE_T
class PCB_REFERENCE_IMAGE, bitmap on a layer
Definition typeinfo.h:86
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition typeinfo.h:87
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
Definition typeinfo.h:98
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
Definition typeinfo.h:104
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:92
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition typeinfo.h:99
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:84
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:95
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition typeinfo.h:91
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:93
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition typeinfo.h:102
Casted dyn_cast(From aObject)
A lightweight dynamic downcast.
Definition typeinfo.h:60
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687
VECTOR2< double > VECTOR2D
Definition vector2d.h:686