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