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