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