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