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 solids.emplace_back( std::move( solid ) );
1578 };
1579
1580 aPad->Padstack().ForEachUniqueLayer( makeSolidFromPadLayer );
1581
1582 return solids;
1583}
1584
1585
1586std::unique_ptr<PNS::SEGMENT> PNS_KICAD_IFACE_BASE::syncTrack( PCB_TRACK* aTrack )
1587{
1588 auto segment = std::make_unique<PNS::SEGMENT>( SEG( aTrack->GetStart(), aTrack->GetEnd() ), aTrack->GetNet() );
1589
1590 segment->SetWidth( aTrack->GetWidth() );
1591 segment->SetLayer( GetPNSLayerFromBoardLayer( aTrack->GetLayer() ) );
1592 segment->SetParent( aTrack );
1593
1594 if( aTrack->IsLocked() )
1595 segment->Mark( PNS::MK_LOCKED );
1596
1597 if( PCB_GENERATOR* generator = dynamic_cast<PCB_GENERATOR*>( aTrack->GetParentGroup() ) )
1598 {
1599 if( !generator->HasFlag( IN_EDIT ) )
1600 segment->Mark( PNS::MK_LOCKED );
1601 }
1602
1603 return segment;
1604}
1605
1606
1607std::unique_ptr<PNS::ARC> PNS_KICAD_IFACE_BASE::syncArc( PCB_ARC* aArc )
1608{
1609 auto arc = std::make_unique<PNS::ARC>( SHAPE_ARC( aArc->GetStart(), aArc->GetMid(),
1610 aArc->GetEnd(), aArc->GetWidth() ),
1611 aArc->GetNet() );
1612
1613 arc->SetLayer( GetPNSLayerFromBoardLayer( aArc->GetLayer() ) );
1614 arc->SetParent( aArc );
1615
1616 if( aArc->IsLocked() )
1617 arc->Mark( PNS::MK_LOCKED );
1618
1619 if( PCB_GENERATOR* generator = dynamic_cast<PCB_GENERATOR*>( aArc->GetParentGroup() ) )
1620 {
1621 if( !generator->HasFlag( IN_EDIT ) )
1622 arc->Mark( PNS::MK_LOCKED );
1623 }
1624
1625 return arc;
1626}
1627
1628
1629std::unique_ptr<PNS::VIA> PNS_KICAD_IFACE_BASE::syncVia( PCB_VIA* aVia )
1630{
1631 PCB_LAYER_ID top, bottom;
1632 aVia->LayerPair( &top, &bottom );
1633
1634 /*
1635 * NOTE about PNS via padstacks:
1636 *
1637 * PNS::VIA has no knowledge about how many layers are in the board, and there is no fixed
1638 * reference to the "back layer" in the PNS. That means that there is no way for a VIA to know
1639 * the difference between its bottom layer and the bottom layer of the overall board (i.e. if
1640 * the via is a blind/buried via). For this reason, PNS::VIA::STACK_MODE::FRONT_INNER_BACK
1641 * cannot be used for blind/buried vias. This mode will always assume that the via's top layer
1642 * is the "front" layer and the via's bottom layer is the "back" layer, but from KiCad's point
1643 * of view, at least at the moment, front/inner/back padstack mode is board-scoped, not
1644 * via-scoped, so a buried via would only use the inner layer size even if its padstack mode is
1645 * set to PADSTACK::MODE::FRONT_INNER_BACK and different sizes are defined for front or back.
1646 * For this kind of via, the PNS VIA stack mode will be set to NORMAL because effectively it has
1647 * the same size on every layer it exists on.
1648 */
1649
1650 auto via = std::make_unique<PNS::VIA>( aVia->GetPosition(),
1651 SetLayersFromPCBNew( aVia->TopLayer(), aVia->BottomLayer() ),
1652 0,
1653 aVia->GetDrillValue(),
1654 aVia->GetNet(),
1655 aVia->GetViaType() );
1656 via->SetUnconnectedLayerMode( aVia->Padstack().UnconnectedLayerMode() );
1657
1658 auto syncDiameter =
1659 [&]( PCB_LAYER_ID aLayer )
1660 {
1661 via->SetDiameter( GetPNSLayerFromBoardLayer( aLayer ), aVia->GetWidth( aLayer ) );
1662 };
1663
1664 switch( aVia->Padstack().Mode() )
1665 {
1667 via->SetDiameter( 0, aVia->GetWidth( PADSTACK::ALL_LAYERS ) );
1668 break;
1669
1671 if( aVia->GetViaType() == VIATYPE::BLIND || aVia->GetViaType() == VIATYPE::BURIED )
1672 {
1673 via->SetDiameter( 0, aVia->GetWidth( PADSTACK::INNER_LAYERS ) );
1674 }
1675 else
1676 {
1678 aVia->Padstack().ForEachUniqueLayer( syncDiameter );
1679 }
1680
1681 break;
1682
1684 via->SetStackMode( PNS::VIA::STACK_MODE::CUSTOM );
1685 aVia->Padstack().ForEachUniqueLayer( syncDiameter );
1686 }
1687
1688 via->SetParent( aVia );
1689
1690 if( aVia->IsLocked() )
1691 via->Mark( PNS::MK_LOCKED );
1692
1693 if( PCB_GENERATOR* generator = dynamic_cast<PCB_GENERATOR*>( aVia->GetParentGroup() ) )
1694 {
1695 if( !generator->HasFlag( IN_EDIT ) )
1696 via->Mark( PNS::MK_LOCKED );
1697 }
1698
1699 via->SetIsFree( aVia->GetIsFree() );
1700 via->SetHole( PNS::HOLE::MakeCircularHole( aVia->GetPosition(),
1701 aVia->GetDrillValue() / 2,
1702 SetLayersFromPCBNew( aVia->TopLayer(), aVia->BottomLayer() ) ) );
1703
1704 PCB_LAYER_ID primaryStart = aVia->GetPrimaryDrillStartLayer();
1705 PCB_LAYER_ID primaryEnd = aVia->GetPrimaryDrillEndLayer();
1706
1707 if( primaryStart != UNDEFINED_LAYER && primaryEnd != UNDEFINED_LAYER )
1708 via->SetHoleLayers( SetLayersFromPCBNew( primaryStart, primaryEnd ) );
1709 else
1710 via->SetHoleLayers( SetLayersFromPCBNew( aVia->TopLayer(), aVia->BottomLayer() ) );
1711
1712 via->SetHolePostMachining( aVia->GetFrontPostMachining() );
1713 via->SetSecondaryDrill( aVia->GetSecondaryDrillSize() );
1714
1715 std::optional<PNS_LAYER_RANGE> secondaryLayers;
1716
1719 {
1720 secondaryLayers = SetLayersFromPCBNew( aVia->GetSecondaryDrillStartLayer(),
1721 aVia->GetSecondaryDrillEndLayer() );
1722 }
1723
1724 via->SetSecondaryHoleLayers( secondaryLayers );
1725 via->SetSecondaryHolePostMachining( std::nullopt );
1726
1727 return via;
1728}
1729
1730
1731bool PNS_KICAD_IFACE_BASE::syncZone( PNS::NODE* aWorld, ZONE* aZone, SHAPE_POLY_SET* aBoardOutline )
1732{
1733 static wxString msg;
1734 SHAPE_POLY_SET* poly;
1735
1736 if( !aZone->GetIsRuleArea() || !aZone->HasKeepoutParametersSet() )
1737 return false;
1738
1739 LSET layers = aZone->GetLayerSet();
1740
1741 poly = aZone->Outline();
1742 poly->CacheTriangulation( false );
1743
1744 if( !poly->IsTriangulationUpToDate() )
1745 {
1746 UNITS_PROVIDER unitsProvider( pcbIUScale, GetUnits() );
1747 msg.Printf( _( "%s is malformed." ), aZone->GetItemDescription( &unitsProvider, true ) );
1748
1749 KIDIALOG dlg( nullptr, msg, KIDIALOG::KD_WARNING );
1750 dlg.ShowDetailedText( _( "This zone cannot be handled by the router.\n"
1751 "Please verify it is not a self-intersecting polygon." ) );
1752 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
1753 dlg.ShowModal();
1754
1755 return false;
1756 }
1757
1758 for( PCB_LAYER_ID layer : LAYER_RANGE( F_Cu, B_Cu, m_board->GetCopperLayerCount() ) )
1759 {
1760 if( !layers[ layer ] )
1761 continue;
1762
1763 for( unsigned int polyId = 0; polyId < poly->TriangulatedPolyCount(); polyId++ )
1764 {
1765 const SHAPE_POLY_SET::TRIANGULATED_POLYGON* tri = poly->TriangulatedPolygon( polyId );
1766
1767 for( size_t i = 0; i < tri->GetTriangleCount(); i++)
1768 {
1769 VECTOR2I a, b, c;
1770 tri->GetTriangle( i, a, b, c );
1771 SHAPE_SIMPLE* triShape = new SHAPE_SIMPLE;
1772
1773 triShape->Append( a );
1774 triShape->Append( b );
1775 triShape->Append( c );
1776
1777 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
1778
1779 solid->SetLayer( GetPNSLayerFromBoardLayer( layer ) );
1780 solid->SetNet( nullptr );
1781 solid->SetParent( aZone );
1782 solid->SetShape( triShape );
1783 solid->SetIsCompoundShapePrimitive();
1784 solid->SetRoutable( false );
1785
1786 aWorld->Add( std::move( solid ) );
1787 }
1788 }
1789 }
1790
1791 return true;
1792}
1793
1794
1796{
1797 if( !IsKicadCopperLayer( aLayer ) )
1798 return false;
1799
1800 if( aItem->Type() == PCB_FIELD_T && !static_cast<PCB_FIELD*>( aItem )->IsVisible() )
1801 return false;
1802
1803 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
1804 SHAPE_SIMPLE* shape = new SHAPE_SIMPLE;
1805
1806 solid->SetLayer( GetPNSLayerFromBoardLayer( aLayer ) );
1807 solid->SetNet( nullptr );
1808 solid->SetParent( aItem );
1809 solid->SetShape( shape ); // takes ownership
1810 solid->SetRoutable( false );
1811
1812 SHAPE_POLY_SET cornerBuffer;
1813
1814 aItem->TransformShapeToPolygon( cornerBuffer, aItem->GetLayer(), 0, aItem->GetMaxError(), ERROR_OUTSIDE );
1815
1816 cornerBuffer.Simplify();
1817
1818 if( !cornerBuffer.OutlineCount() )
1819 return false;
1820
1821 for( const VECTOR2I& pt : cornerBuffer.Outline( 0 ).CPoints() )
1822 shape->Append( pt );
1823
1824 aWorld->Add( std::move( solid ) );
1825
1826 return true;
1827}
1828
1829
1831{
1832 if( !IsKicadCopperLayer( aDimension->GetLayer() ) )
1833 return false;
1834
1835 auto addPolysToWorld =
1836 [&]( const SHAPE_POLY_SET& aPolys )
1837 {
1838 for( int ii = 0; ii < aPolys.OutlineCount(); ++ii )
1839 {
1840 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
1841 SHAPE_SIMPLE* shape = new SHAPE_SIMPLE;
1842
1843 solid->SetLayer( GetPNSLayerFromBoardLayer( aDimension->GetLayer() ) );
1844 solid->SetNet( nullptr );
1845 solid->SetParent( aDimension );
1846 solid->SetShape( shape ); // takes ownership
1847 solid->SetRoutable( false );
1848
1849 for( const VECTOR2I& pt : aPolys.Outline( ii ).CPoints() )
1850 shape->Append( pt );
1851
1852 aWorld->Add( std::move( solid ) );
1853 }
1854 };
1855
1856 SHAPE_POLY_SET cornerBuffer;
1857
1858 aDimension->TransformShapeToPolygon( cornerBuffer, aDimension->GetLayer(), 0,
1859 aDimension->GetMaxError(), ERROR_OUTSIDE );
1860
1861 cornerBuffer.Simplify();
1862
1863 if( cornerBuffer.OutlineCount() )
1864 addPolysToWorld( cornerBuffer );
1865
1866 // Footprints can have hidden dimensions
1867 if( aDimension->IsVisible() && !aDimension->GetText().IsEmpty() )
1868 {
1869 SHAPE_POLY_SET textBuffer;
1870
1871 aDimension->PCB_TEXT::TransformShapeToPolygon( textBuffer, aDimension->GetLayer(), 0,
1872 aDimension->GetMaxError(), ERROR_OUTSIDE );
1873
1874 textBuffer.Simplify();
1875
1876 if( textBuffer.OutlineCount() )
1877 addPolysToWorld( textBuffer );
1878 }
1879
1880 return cornerBuffer.OutlineCount() || !aDimension->GetText().IsEmpty();
1881}
1882
1883
1885{
1886 if( aItem->GetLayer() == Edge_Cuts
1887 || aItem->GetLayer() == Margin
1888 || IsKicadCopperLayer( aItem->GetLayer() ) )
1889 {
1890 std::vector<SHAPE*> shapes = aItem->MakeEffectiveShapes();
1891
1892 for( SHAPE* shape : shapes )
1893 {
1894 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
1895
1896 if( aItem->GetLayer() == Edge_Cuts || aItem->GetLayer() == Margin )
1897 {
1898 solid->SetLayers( PNS_LAYER_RANGE( 0, m_board->GetCopperLayerCount() - 1 ) );
1899 solid->SetRoutable( false );
1900 }
1901 else
1902 {
1903 solid->SetLayer( GetPNSLayerFromBoardLayer( aItem->GetLayer() ) );
1904 solid->SetRoutable( aItem->Type() != PCB_TABLECELL_T );
1905 }
1906
1907 if( aItem->GetLayer() == Edge_Cuts )
1908 {
1909 switch( shape->Type() )
1910 {
1911 case SH_SEGMENT: static_cast<SHAPE_SEGMENT*>( shape )->SetWidth( 0 ); break;
1912 case SH_ARC: static_cast<SHAPE_ARC*>( shape )->SetWidth( 0 ); break;
1913 case SH_LINE_CHAIN: static_cast<SHAPE_LINE_CHAIN*>( shape )->SetWidth( 0 ); break;
1914 default: /* remaining shapes don't have width */ break;
1915 }
1916 }
1917
1918 solid->SetAnchorPoints( aItem->GetConnectionPoints() );
1919 solid->SetNet( aItem->GetNet() );
1920 solid->SetParent( aItem );
1921 solid->SetShape( shape ); // takes ownership
1922
1923 if( shapes.size() > 1 )
1924 solid->SetIsCompoundShapePrimitive();
1925
1926 aWorld->Add( std::move( solid ) );
1927 }
1928
1929 return true;
1930 }
1931
1932 return false;
1933}
1934
1935
1937{
1938 if( IsKicadCopperLayer( aBarcode->GetLayer() ) )
1939 {
1940 SHAPE_POLY_SET cornerBuffer;
1941
1942 aBarcode->GetBoundingHull( cornerBuffer, aBarcode->GetLayer(), 0, aBarcode->GetMaxError(), ERROR_OUTSIDE );
1943
1944 if( !cornerBuffer.OutlineCount() )
1945 return false;
1946
1947 for( int ii = 0; ii < cornerBuffer.OutlineCount(); ++ii )
1948 {
1949 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
1950 SHAPE_SIMPLE* shape = new SHAPE_SIMPLE;
1951
1952 solid->SetLayer( GetPNSLayerFromBoardLayer( aBarcode->GetLayer() ) );
1953 solid->SetNet( nullptr );
1954 solid->SetParent( aBarcode );
1955 solid->SetShape( shape ); // takes ownership
1956 solid->SetRoutable( false );
1957
1958 for( const VECTOR2I& pt : cornerBuffer.Outline( ii ).CPoints() )
1959 shape->Append( pt );
1960
1961 aWorld->Add( std::move( solid ) );
1962 }
1963
1964 return true;
1965 }
1966
1967 return false;
1968}
1969
1970
1972{
1973 m_board = aBoard;
1974 wxLogTrace( wxT( "PNS" ), wxT( "m_board = %p" ), m_board );
1975}
1976
1977
1979{
1980 return ::IsCopperLayer( GetBoardLayerFromPNSLayer( aPNSLayer ) );
1981}
1982
1983
1984
1986{
1987 return ::IsCopperLayer( aKicadLayer );
1988}
1989
1990
1992{
1993 if( !m_view )
1994 return false;
1995
1996 for( int i = aLayer.Start(); i <= aLayer.End(); i++ )
1997 {
1998 if( m_view->IsLayerVisible( GetBoardLayerFromPNSLayer( i ) ) )
1999 return true;
2000 }
2001
2002 return false;
2003}
2004
2005
2006bool PNS_KICAD_IFACE_BASE::IsFlashedOnLayer( const PNS::ITEM* aItem, int aLayer ) const
2007{
2009 if( aLayer < 0 )
2010 return true;
2011
2012 if( aItem->Parent() )
2013 {
2014 switch( aItem->Parent()->Type() )
2015 {
2016 case PCB_VIA_T:
2017 {
2018 const PCB_VIA* via = static_cast<const PCB_VIA*>( aItem->Parent() );
2019
2020 return via->FlashLayer( GetBoardLayerFromPNSLayer( aLayer ) );
2021 }
2022
2023 case PCB_PAD_T:
2024 {
2025 const PAD* pad = static_cast<const PAD*>( aItem->Parent() );
2026
2027 return pad->FlashLayer( GetBoardLayerFromPNSLayer( aLayer ) );
2028 }
2029
2030 default:
2031 break;
2032 }
2033 }
2034
2035 if( aItem->OfKind( PNS::ITEM::VIA_T ) )
2036 return static_cast<const PNS::VIA*>( aItem )->ConnectsLayer( aLayer );
2037
2038 return aItem->Layers().Overlaps( aLayer );
2039}
2040
2041
2043{
2044 PNS_LAYER_RANGE test = aItem->Layers().Intersection( aLayer );
2045
2046 if( aItem->Parent() )
2047 {
2048 switch( aItem->Parent()->Type() )
2049 {
2050 case PCB_VIA_T:
2051 {
2052 const PCB_VIA* via = static_cast<const PCB_VIA*>( aItem->Parent() );
2053
2054 for( int layer = test.Start(); layer <= test.End(); ++layer )
2055 {
2056 if( via->FlashLayer( GetBoardLayerFromPNSLayer( layer ) ) )
2057 return true;
2058 }
2059
2060 return false;
2061 }
2062
2063 case PCB_PAD_T:
2064 {
2065 const PAD* pad = static_cast<const PAD*>( aItem->Parent() );
2066
2067 for( int layer = test.Start(); layer <= test.End(); ++layer )
2068 {
2069 if( pad->FlashLayer( GetBoardLayerFromPNSLayer( layer ) ) )
2070 return true;
2071 }
2072
2073 return false;
2074 }
2075
2076 default:
2077 break;
2078 }
2079 }
2080
2081 if( aItem->OfKind( PNS::ITEM::VIA_T ) )
2082 {
2083 const PNS::VIA* via = static_cast<const PNS::VIA*>( aItem );
2084
2085 for( int layer = test.Start(); layer <= test.End(); ++layer )
2086 {
2087 if( via->ConnectsLayer( layer ) )
2088 return true;
2089 }
2090
2091 return false;
2092 }
2093
2094 return test.Start() <= test.End();
2095}
2096
2097
2099{
2100 // by default, all items are visible (new ones created by the router have parent == NULL
2101 // as they have not been committed yet to the BOARD)
2102 if( !m_view || !aItem->Parent() )
2103 return true;
2104
2105 BOARD_ITEM* item = aItem->Parent();
2106 bool isOnVisibleLayer = true;
2107 RENDER_SETTINGS* settings = m_view->GetPainter()->GetSettings();
2108
2109 if( settings->GetHighContrast() )
2110 isOnVisibleLayer = item->IsOnLayer( settings->GetPrimaryHighContrastLayer() );
2111
2112 if( m_view->IsVisible( item ) && isOnVisibleLayer )
2113 {
2114 for( PCB_LAYER_ID layer : item->GetLayerSet() )
2115 {
2116 if( item->ViewGetLOD( layer, m_view ) < m_view->GetScale() )
2117 return true;
2118 }
2119 }
2120
2121 // Items hidden in the router are not hidden on the board
2122 if( m_hiddenItems.find( item ) != m_hiddenItems.end() )
2123 return true;
2124
2125 return false;
2126}
2127
2128
2130{
2131 if( !m_board )
2132 {
2133 wxLogTrace( wxT( "PNS" ), wxT( "No board attached, aborting sync." ) );
2134 return;
2135 }
2136
2137 int worstClearance = m_board->GetMaxClearanceValue();
2138
2139 m_world = aWorld;
2140
2141 for( BOARD_ITEM* gitem : m_board->Drawings() )
2142 {
2143 switch( gitem->Type() )
2144 {
2145 case PCB_SHAPE_T:
2146 case PCB_TEXTBOX_T:
2147 syncGraphicalItem( aWorld, static_cast<PCB_SHAPE*>( gitem ) );
2148 break;
2149
2150 case PCB_TEXT_T:
2151 syncTextItem( aWorld, static_cast<PCB_TEXT*>( gitem ), gitem->GetLayer() );
2152 break;
2153
2154 case PCB_TABLE_T:
2155 syncTextItem( aWorld, static_cast<PCB_TABLE*>( gitem ), gitem->GetLayer() );
2156 break;
2157
2158 case PCB_BARCODE_T:
2159 syncBarcode( aWorld, static_cast<PCB_BARCODE*>( gitem ) );
2160 break;
2161
2162 case PCB_DIM_ALIGNED_T:
2163 case PCB_DIM_CENTER_T:
2164 case PCB_DIM_RADIAL_T:
2166 case PCB_DIM_LEADER_T:
2167 syncDimension( aWorld, static_cast<PCB_DIMENSION_BASE*>( gitem ) );
2168 break;
2169
2170 case PCB_REFERENCE_IMAGE_T: // ignore
2171 case PCB_TARGET_T:
2172 break;
2173
2174 default:
2175 UNIMPLEMENTED_FOR( gitem->GetClass() );
2176 break;
2177 }
2178 }
2179
2180 SHAPE_POLY_SET buffer;
2181 SHAPE_POLY_SET* boardOutline = nullptr;
2182
2183 if( m_board->GetBoardPolygonOutlines( buffer, true ) )
2184 boardOutline = &buffer;
2185
2186 for( ZONE* zone : m_board->Zones() )
2187 {
2188 syncZone( aWorld, zone, boardOutline );
2189 }
2190
2191 for( FOOTPRINT* footprint : m_board->Footprints() )
2192 {
2193 for( PAD* pad : footprint->Pads() )
2194 {
2195 std::vector<std::unique_ptr<PNS::SOLID>> solids = syncPad( pad );
2196
2197 for( std::unique_ptr<PNS::SOLID>& solid : solids )
2198 aWorld->Add( std::move( solid ) );
2199
2200 std::optional<int> clearanceOverride = pad->GetClearanceOverrides( nullptr );
2201
2202 if( clearanceOverride.has_value() )
2203 worstClearance = std::max( worstClearance, clearanceOverride.value() );
2204
2205 if( pad->GetProperty() == PAD_PROP::CASTELLATED )
2206 {
2207 std::unique_ptr<SHAPE> hole;
2208 hole.reset( pad->GetEffectiveHoleShape()->Clone() );
2209 aWorld->AddEdgeExclusion( std::move( hole ) );
2210 }
2211 }
2212
2213 syncTextItem( aWorld, &footprint->Reference(), footprint->Reference().GetLayer() );
2214 syncTextItem( aWorld, &footprint->Value(), footprint->Value().GetLayer() );
2215
2216 for( ZONE* zone : footprint->Zones() )
2217 syncZone( aWorld, zone, boardOutline );
2218
2219 for( PCB_FIELD* field : footprint->GetFields() )
2220 syncTextItem( aWorld, static_cast<PCB_TEXT*>( field ), field->GetLayer() );
2221
2222 for( BOARD_ITEM* item : footprint->GraphicalItems() )
2223 {
2224 switch( item->Type() )
2225 {
2226 case PCB_SHAPE_T:
2227 case PCB_TEXTBOX_T:
2228 syncGraphicalItem( aWorld, static_cast<PCB_SHAPE*>( item ) );
2229 break;
2230
2231 case PCB_TEXT_T:
2232 syncTextItem( aWorld, static_cast<PCB_TEXT*>( item ), item->GetLayer() );
2233 break;
2234
2235 case PCB_TABLE_T:
2236 syncTextItem( aWorld, static_cast<PCB_TABLE*>( item ), item->GetLayer() );
2237 break;
2238
2239 case PCB_BARCODE_T:
2240 syncBarcode( aWorld, static_cast<PCB_BARCODE*>( item ) );
2241 break;
2242
2243 case PCB_DIM_ALIGNED_T:
2244 case PCB_DIM_CENTER_T:
2245 case PCB_DIM_RADIAL_T:
2247 case PCB_DIM_LEADER_T:
2248 syncDimension( aWorld, static_cast<PCB_DIMENSION_BASE*>( item ) );
2249 break;
2250
2251 case PCB_REFERENCE_IMAGE_T: // ignore
2252 break;
2253
2254 default:
2255 UNIMPLEMENTED_FOR( item->GetClass() );
2256 break;
2257 }
2258 }
2259 }
2260
2261 for( PCB_TRACK* t : m_board->Tracks() )
2262 {
2263 KICAD_T type = t->Type();
2264
2265 if( type == PCB_TRACE_T )
2266 {
2267 if( std::unique_ptr<PNS::SEGMENT> segment = syncTrack( t ) )
2268 aWorld->Add( std::move( segment ), true );
2269 }
2270 else if( type == PCB_ARC_T )
2271 {
2272 if( std::unique_ptr<PNS::ARC> arc = syncArc( static_cast<PCB_ARC*>( t ) ) )
2273 aWorld->Add( std::move( arc ), true );
2274 }
2275 else if( type == PCB_VIA_T )
2276 {
2277 if( std::unique_ptr<PNS::VIA> via = syncVia( static_cast<PCB_VIA*>( t ) ) )
2278 aWorld->Add( std::move( via ) );
2279 }
2280 }
2281
2282 // NB: if this were ever to become a long-lived object we would need to dirty its
2283 // clearance cache here....
2284 delete m_ruleResolver;
2286
2288 aWorld->SetMaxClearance( worstClearance + m_ruleResolver->ClearanceEpsilon() );
2289}
2290
2291
2293{
2294 for( BOARD_ITEM* item : m_hiddenItems )
2295 m_view->SetVisible( item, true );
2296
2297 m_hiddenItems.clear();
2298
2299 if( m_previewItems )
2300 {
2301 m_previewItems->FreeItems();
2302 m_view->Update( m_previewItems );
2303 }
2304
2305 if( m_debugDecorator )
2306 m_debugDecorator->Clear();
2307}
2308
2309
2314
2315
2316void PNS_KICAD_IFACE::DisplayItem( const PNS::ITEM* aItem, int aClearance, bool aEdit, int aFlags )
2317{
2318 if( aItem->IsVirtual() )
2319 return;
2320
2321 if( ZONE* zone = dynamic_cast<ZONE*>( aItem->Parent() ) )
2322 {
2323 if( zone->GetIsRuleArea() )
2324 aFlags |= PNS_SEMI_SOLID;
2325 }
2326
2327 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aItem, this, m_view, aFlags );
2328
2329 // Note: SEGMENT_T is used for placed tracks; LINE_T is used for the routing head
2331 static int tracksOrVias = tracks | PNS::ITEM::VIA_T;
2332
2333 if( aClearance >= 0 )
2334 {
2335 pitem->SetClearance( aClearance );
2336
2337 PCBNEW_SETTINGS* settings = static_cast<PCBNEW_SETTINGS*>( m_tool->GetManager()->GetSettings() );
2338
2339 switch( settings->m_Display.m_TrackClearance )
2340 {
2343 pitem->ShowClearance( aItem->OfKind( tracksOrVias ) );
2344 break;
2345
2347 pitem->ShowClearance( aItem->OfKind( tracksOrVias ) && !aEdit );
2348 break;
2349
2350 case SHOW_WHILE_ROUTING:
2351 pitem->ShowClearance( aItem->OfKind( tracks ) && !aEdit );
2352 break;
2353
2354 default:
2355 pitem->ShowClearance( false );
2356 break;
2357 }
2358 }
2359
2360 m_previewItems->Add( pitem );
2361 m_view->Update( m_previewItems );
2362}
2363
2364
2365void PNS_KICAD_IFACE::DisplayPathLine( const SHAPE_LINE_CHAIN& aLine, int aImportance )
2366{
2367 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aLine, this, m_view );
2369
2370 COLOR4D color;
2371
2372 if( aImportance >= 1 )
2373 color = COLOR4D( 1.0, 1.0, 0.0, 0.6 );
2374 else if( aImportance == 0 )
2375 color = COLOR4D( 0.7, 0.7, 0.7, 0.6 );
2376
2377 pitem->SetColor( color );
2378
2379 m_previewItems->Add( pitem );
2380 m_view->Update( m_previewItems );
2381}
2382
2383
2385{
2386 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aRatline, this, m_view );
2387
2388 KIGFX::RENDER_SETTINGS* renderSettings = m_view->GetPainter()->GetSettings();
2389 KIGFX::PCB_RENDER_SETTINGS* rs = static_cast<KIGFX::PCB_RENDER_SETTINGS*>( renderSettings );
2390 bool colorByNet = rs->GetNetColorMode() != NET_COLOR_MODE::OFF;
2391 COLOR4D defaultColor = rs->GetColor( nullptr, LAYER_RATSNEST );
2392 COLOR4D color = defaultColor;
2393
2394 std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_board->GetConnectivity();
2395 std::set<int> highlightedNets = rs->GetHighlightNetCodes();
2396 std::map<int, KIGFX::COLOR4D>& netColors = rs->GetNetColorMap();
2397 int netCode = -1;
2398
2399 if( NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aNet ) )
2400 netCode = net->GetNetCode();
2401
2402 const NETCLASS* nc = nullptr;
2403 const NET_SETTINGS* netSettings = connectivity->GetNetSettings();
2404
2405 if( connectivity->HasNetNameForNetCode( netCode ) )
2406 {
2407 const wxString& netName = connectivity->GetNetNameForNetCode( netCode );
2408
2409 if( netSettings && netSettings->HasEffectiveNetClass( netName ) )
2410 nc = netSettings->GetCachedEffectiveNetClass( netName ).get();
2411 }
2412
2413 if( colorByNet && netColors.count( netCode ) )
2414 color = netColors.at( netCode );
2415 else if( colorByNet && nc && nc->HasPcbColor() )
2416 color = nc->GetPcbColor();
2417 else
2418 color = defaultColor;
2419
2420 if( color == COLOR4D::UNSPECIFIED )
2421 color = defaultColor;
2422
2423 pitem->SetColor( color.Brightened( 0.5 ).WithAlpha( std::min( 1.0, color.a + 0.4 ) ) );
2424
2425 m_previewItems->Add( pitem );
2426 m_view->Update( m_previewItems );
2427}
2428
2429
2431{
2432 BOARD_ITEM* parent = aItem->Parent();
2433
2434 if( parent )
2435 {
2436 if( m_view->IsVisible( parent ) )
2437 m_hiddenItems.insert( parent );
2438
2439 m_view->SetVisible( parent, false );
2440 m_view->Update( parent, KIGFX::APPEARANCE );
2441
2442 for( ZONE* td : m_board->Zones() )
2443 {
2444 if( td->IsTeardropArea()
2445 && td->GetBoundingBox().Intersects( aItem->Parent()->GetBoundingBox() )
2446 && td->Outline()->Collide( aItem->Shape( td->GetLayer() ) ) )
2447 {
2448 m_view->SetVisible( td, false );
2449 m_view->Update( td, KIGFX::APPEARANCE );
2450 }
2451 }
2452 }
2453}
2454
2455
2459
2460
2462{
2463 BOARD_ITEM* parent = aItem->Parent();
2464
2465 if( aItem->OfKind( PNS::ITEM::SOLID_T ) && parent->Type() == PCB_PAD_T )
2466 {
2467 PAD* pad = static_cast<PAD*>( parent );
2468 VECTOR2I pos = static_cast<PNS::SOLID*>( aItem )->Pos();
2469
2470 m_fpOffsets[ pad ].p_old = pos;
2471 return;
2472 }
2473
2474 if( parent )
2475 {
2476 if( EDA_GROUP* group = parent->GetParentGroup() )
2477 m_itemGroups[parent] = group;
2478
2479 m_commit->Remove( parent );
2480 }
2481}
2482
2483
2487
2488
2490{
2491 BOARD_ITEM* board_item = aItem->Parent();
2492
2493 switch( aItem->Kind() )
2494 {
2495 case PNS::ITEM::ARC_T:
2496 {
2497 PNS::ARC* arc = static_cast<PNS::ARC*>( aItem );
2498 PCB_ARC* arc_board = static_cast<PCB_ARC*>( board_item );
2499 const SHAPE_ARC* arc_shape = static_cast<const SHAPE_ARC*>( arc->Shape( -1 ) );
2500
2501 m_commit->Modify( arc_board );
2502
2503 arc_board->SetStart( VECTOR2I( arc_shape->GetP0() ) );
2504 arc_board->SetEnd( VECTOR2I( arc_shape->GetP1() ) );
2505 arc_board->SetMid( VECTOR2I( arc_shape->GetArcMid() ) );
2506 arc_board->SetWidth( arc->Width() );
2507 break;
2508 }
2509
2511 {
2512 PNS::SEGMENT* seg = static_cast<PNS::SEGMENT*>( aItem );
2513 PCB_TRACK* track = static_cast<PCB_TRACK*>( board_item );
2514 const SEG& s = seg->Seg();
2515
2516 m_commit->Modify( track );
2517
2518 track->SetStart( VECTOR2I( s.A.x, s.A.y ) );
2519 track->SetEnd( VECTOR2I( s.B.x, s.B.y ) );
2520 track->SetWidth( seg->Width() );
2521 break;
2522 }
2523
2524 case PNS::ITEM::VIA_T:
2525 {
2526 PCB_VIA* via_board = static_cast<PCB_VIA*>( board_item );
2527 PNS::VIA* via = static_cast<PNS::VIA*>( aItem );
2528
2529 m_commit->Modify( via_board );
2530
2531 via_board->SetPosition( VECTOR2I( via->Pos().x, via->Pos().y ) );
2532 via_board->SetWidth( PADSTACK::ALL_LAYERS, via->Diameter( 0 ) );
2533 via_board->SetDrill( via->Drill() );
2534 via_board->SetNet( static_cast<NETINFO_ITEM*>( via->Net() ) );
2535 via_board->SetViaType( via->ViaType() ); // MUST be before SetLayerPair()
2536 via_board->Padstack().SetUnconnectedLayerMode( via->UnconnectedLayerMode() );
2537 via_board->SetIsFree( via->IsFree() );
2538 via_board->SetLayerPair( GetBoardLayerFromPNSLayer( via->Layers().Start() ),
2539 GetBoardLayerFromPNSLayer( via->Layers().End() ) );
2540
2541 PNS_LAYER_RANGE holeLayers = via->HoleLayers();
2542
2543 if( holeLayers.Start() >= 0 && holeLayers.End() >= 0 )
2544 {
2545 via_board->SetPrimaryDrillStartLayer( GetBoardLayerFromPNSLayer( holeLayers.Start() ) );
2546 via_board->SetPrimaryDrillEndLayer( GetBoardLayerFromPNSLayer( holeLayers.End() ) );
2547 }
2548
2549 via_board->SetFrontPostMachining( via->HolePostMachining() );
2550 via_board->SetSecondaryDrillSize( via->SecondaryDrill() );
2551
2552 if( std::optional<PNS_LAYER_RANGE> secondaryLayers = via->SecondaryHoleLayers() )
2553 {
2554 via_board->SetSecondaryDrillStartLayer( GetBoardLayerFromPNSLayer( secondaryLayers->Start() ) );
2555 via_board->SetSecondaryDrillEndLayer( GetBoardLayerFromPNSLayer( secondaryLayers->End() ) );
2556 }
2557 else
2558 {
2561 }
2562
2563 break;
2564 }
2565
2566 case PNS::ITEM::SOLID_T:
2567 {
2568 if( aItem->Parent()->Type() == PCB_PAD_T )
2569 {
2570 PAD* pad = static_cast<PAD*>( aItem->Parent() );
2571 VECTOR2I pos = static_cast<PNS::SOLID*>( aItem )->Pos();
2572
2573 // Don't add to commit; we'll add the parent footprints when processing the m_fpOffsets
2574
2575 m_fpOffsets[pad].p_old = pad->GetPosition();
2576 m_fpOffsets[pad].p_new = pos;
2577 }
2578 break;
2579 }
2580
2581 default:
2582 m_commit->Modify( aItem->Parent() );
2583 break;
2584 }
2585}
2586
2587
2589{
2590 modifyBoardItem( aItem );
2591}
2592
2593
2595{
2596}
2597
2598
2600{
2601 BOARD_CONNECTED_ITEM* newBoardItem = nullptr;
2602 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aItem->Net() );
2603
2604 if( !net )
2606
2607 switch( aItem->Kind() )
2608 {
2609 case PNS::ITEM::ARC_T:
2610 {
2611 PNS::ARC* arc = static_cast<PNS::ARC*>( aItem );
2612 PCB_ARC* new_arc = new PCB_ARC( m_board, static_cast<const SHAPE_ARC*>( arc->Shape( -1 ) ) );
2613 new_arc->SetWidth( arc->Width() );
2614 new_arc->SetLayer( GetBoardLayerFromPNSLayer( arc->Layers().Start() ) );
2615 new_arc->SetNet( net );
2616
2617 if( aItem->GetSourceItem() && aItem->GetSourceItem()->IsType( { PCB_TRACE_T, PCB_ARC_T } ) )
2618 {
2619 PCB_TRACK* sourceTrack = static_cast<PCB_TRACK*>( aItem->GetSourceItem() );
2620 new_arc->SetHasSolderMask( sourceTrack->HasSolderMask() );
2621 new_arc->SetLocalSolderMaskMargin( sourceTrack->GetLocalSolderMaskMargin() );
2622 }
2623
2624 newBoardItem = new_arc;
2625 break;
2626 }
2627
2629 {
2630 PNS::SEGMENT* seg = static_cast<PNS::SEGMENT*>( aItem );
2631 PCB_TRACK* track = new PCB_TRACK( m_board );
2632 const SEG& s = seg->Seg();
2633 track->SetStart( VECTOR2I( s.A.x, s.A.y ) );
2634 track->SetEnd( VECTOR2I( s.B.x, s.B.y ) );
2635 track->SetWidth( seg->Width() );
2636 track->SetLayer( GetBoardLayerFromPNSLayer( seg->Layers().Start() ) );
2637 track->SetNet( net );
2638
2639 if( aItem->GetSourceItem() && aItem->GetSourceItem()->IsType( { PCB_TRACE_T, PCB_ARC_T } ) )
2640 {
2641 PCB_TRACK* sourceTrack = static_cast<PCB_TRACK*>( aItem->GetSourceItem() );
2642 track->SetHasSolderMask( sourceTrack->HasSolderMask() );
2643 track->SetLocalSolderMaskMargin( sourceTrack->GetLocalSolderMaskMargin() );
2644 }
2645
2646 newBoardItem = track;
2647 break;
2648 }
2649
2650 case PNS::ITEM::VIA_T:
2651 {
2652 PCB_VIA* via_board = new PCB_VIA( m_board );
2653 PNS::VIA* via = static_cast<PNS::VIA*>( aItem );
2654 via_board->SetPosition( VECTOR2I( via->Pos().x, via->Pos().y ) );
2655 via_board->SetWidth( PADSTACK::ALL_LAYERS, via->Diameter( 0 ) );
2656 via_board->SetDrill( via->Drill() );
2657 via_board->SetNet( net );
2658 via_board->SetViaType( via->ViaType() ); // MUST be before SetLayerPair()
2659 via_board->Padstack().SetUnconnectedLayerMode( via->UnconnectedLayerMode() );
2660 via_board->SetIsFree( via->IsFree() );
2661 via_board->SetLayerPair( GetBoardLayerFromPNSLayer( via->Layers().Start() ),
2662 GetBoardLayerFromPNSLayer( via->Layers().End() ) );
2663
2664 PNS_LAYER_RANGE holeLayers = via->HoleLayers();
2665
2666 if( holeLayers.Start() >= 0 && holeLayers.End() >= 0 )
2667 {
2668 via_board->SetPrimaryDrillStartLayer( GetBoardLayerFromPNSLayer( holeLayers.Start() ) );
2669 via_board->SetPrimaryDrillEndLayer( GetBoardLayerFromPNSLayer( holeLayers.End() ) );
2670 }
2671
2672 via_board->SetFrontPostMachining( via->HolePostMachining() );
2673 via_board->SetSecondaryDrillSize( via->SecondaryDrill() );
2674
2675 if( std::optional<PNS_LAYER_RANGE> secondaryLayers = via->SecondaryHoleLayers() )
2676 {
2677 via_board->SetSecondaryDrillStartLayer( GetBoardLayerFromPNSLayer( secondaryLayers->Start() ) );
2678 via_board->SetSecondaryDrillEndLayer( GetBoardLayerFromPNSLayer( secondaryLayers->End() ) );
2679 }
2680 else
2681 {
2684 }
2685
2686 if( aItem->GetSourceItem() && aItem->GetSourceItem()->Type() == PCB_VIA_T )
2687 {
2688 PCB_VIA* sourceVia = static_cast<PCB_VIA*>( aItem->GetSourceItem() );
2689 via_board->SetFrontTentingMode( sourceVia->GetFrontTentingMode() );
2690 via_board->SetBackTentingMode( sourceVia->GetBackTentingMode() );
2691 }
2692
2693 newBoardItem = via_board;
2694 break;
2695 }
2696
2697 case PNS::ITEM::SOLID_T:
2698 {
2699 PAD* pad = static_cast<PAD*>( aItem->Parent() );
2700 VECTOR2I pos = static_cast<PNS::SOLID*>( aItem )->Pos();
2701
2702 m_fpOffsets[pad].p_new = pos;
2703 return nullptr;
2704 }
2705
2706 default:
2707 return nullptr;
2708 }
2709
2710 if( net->GetNetCode() <= 0 )
2711 {
2712 NETINFO_ITEM* newNetInfo = newBoardItem->GetNet();
2713
2714 newNetInfo->SetParent( m_board );
2715 newNetInfo->SetNetClass( m_board->GetDesignSettings().m_NetSettings->GetDefaultNetclass() );
2716 }
2717
2718 if( newBoardItem )
2719 {
2720 if( aItem->IsLocked() )
2721 newBoardItem->SetLocked( true );
2722
2723 if( BOARD_ITEM* src = aItem->GetSourceItem() )
2724 {
2725 if( m_itemGroups.contains( src ) )
2726 m_replacementMap[src].push_back( newBoardItem );
2727 }
2728 else
2729 {
2730 // This is a new item, which goes in the entered group (if any)
2731 m_replacementMap[ENTERED_GROUP_MAGIC_NUMBER].push_back( newBoardItem );
2732 }
2733 }
2734
2735 return newBoardItem;
2736}
2737
2738
2740{
2741 BOARD_CONNECTED_ITEM* boardItem = createBoardItem( aItem );
2742
2743 if( boardItem )
2744 {
2745 aItem->SetParent( boardItem );
2746 boardItem->ClearFlags();
2747
2748 m_commit->Add( boardItem );
2749 }
2750}
2751
2752
2754{
2755 PCB_SELECTION_TOOL* selTool = m_tool->GetManager()->GetTool<PCB_SELECTION_TOOL>();
2756 std::set<FOOTPRINT*> processedFootprints;
2757
2758 EraseView();
2759
2760 for( const auto& [ pad, fpOffset ] : m_fpOffsets )
2761 {
2762 VECTOR2I offset = fpOffset.p_new - fpOffset.p_old;
2763 FOOTPRINT* footprint = pad->GetParentFootprint();
2764 VECTOR2I p_orig = footprint->GetPosition();
2765 VECTOR2I p_new = p_orig + offset;
2766
2767 if( processedFootprints.find( footprint ) != processedFootprints.end() )
2768 continue;
2769
2770 processedFootprints.insert( footprint );
2771 m_commit->Modify( footprint );
2772 footprint->SetPosition( p_new );
2773 }
2774
2775 m_fpOffsets.clear();
2776
2777 for( const auto& [ src, items ] : m_replacementMap )
2778 {
2779 EDA_GROUP* group = nullptr;
2780
2781 if( src == ENTERED_GROUP_MAGIC_NUMBER )
2782 group = selTool ? selTool->GetEnteredGroup() : nullptr;
2783 else if( auto it = m_itemGroups.find( src ); it != m_itemGroups.end() )
2784 group = it->second;
2785
2786 if( group )
2787 {
2788 m_commit->Modify( group->AsEdaItem(), nullptr, RECURSE_MODE::NO_RECURSE );
2789
2790 for( BOARD_ITEM* bi : items )
2791 group->AddItem( bi );
2792 }
2793 }
2794
2795 m_itemGroups.clear();
2796 m_replacementMap.clear();
2797
2798 m_commit->Push( _( "Routing" ), m_commitFlags | SKIP_ENTERED_GROUP );
2799 m_commit = std::make_unique<BOARD_COMMIT>( m_tool );
2800}
2801
2802
2804{
2805 return static_cast<EDA_UNITS>( m_tool->GetManager()->GetSettings()->m_System.units );
2806}
2807
2808
2810{
2811 wxLogTrace( wxT( "PNS" ), wxT( "SetView %p" ), aView );
2812
2813 if( m_previewItems )
2814 {
2815 m_previewItems->FreeItems();
2816 delete m_previewItems;
2817 }
2818
2819 m_view = aView;
2822
2823 if(m_view)
2824 m_view->Add( m_previewItems );
2825
2826 delete m_debugDecorator;
2827
2828 auto dec = new PNS_PCBNEW_DEBUG_DECORATOR( this );
2829 m_debugDecorator = dec;
2830
2831 dec->SetDebugEnabled( ADVANCED_CFG::GetCfg().m_ShowRouterDebugGraphics );
2832
2833 if( ADVANCED_CFG::GetCfg().m_ShowRouterDebugGraphics )
2834 dec->SetView( m_view );
2835}
2836
2837
2839{
2840 if( aNet )
2841 return static_cast<NETINFO_ITEM*>( aNet )->GetNetCode();
2842 else
2843 return -1;
2844}
2845
2846
2848{
2849 if( aNet )
2850 return static_cast<NETINFO_ITEM*>( aNet )->GetNetname();
2851 else
2852 return wxEmptyString;
2853}
2854
2855
2857{
2858 wxLogTrace( wxT( "PNS" ), wxT( "Update-net %s" ), GetNetName( aNet ) );
2859}
2860
2861
2866
2867
2872
2873
2875{
2876 m_tool = aTool;
2877 m_commit = std::make_unique<BOARD_COMMIT>( m_tool );
2878}
2879
2880
2882{
2883 if( aLayer < 0 )
2885
2886 if( aLayer == 0 )
2887 return F_Cu;
2888
2889 if( aLayer == m_board->GetCopperLayerCount() - 1 )
2890 return B_Cu;
2891
2892 return static_cast<PCB_LAYER_ID>( ( aLayer + 1 ) * 2 );
2893}
2894
2895
2897{
2898 if( aLayer < 0 )
2899 return -1;
2900
2901 if( aLayer == F_Cu )
2902 return 0;
2903
2904 if( aLayer == B_Cu )
2905 return m_board->GetCopperLayerCount() - 1;
2906
2907 return ( aLayer / 2 ) - 1;
2908}
2909
2910
2915
2916
2921
2922
2924 const PNS::SOLID* aEndPad, const NETCLASS* aNetClass )
2925{
2926 std::vector<LENGTH_DELAY_CALCULATION_ITEM> lengthItems = getLengthDelayCalculationItems( aLine, aNetClass );
2927
2928 const PAD* startPad = nullptr;
2929 const PAD* endPad = nullptr;
2930
2931 if( aStartPad )
2932 startPad = static_cast<PAD*>( aStartPad->Parent() );
2933
2934 if( aEndPad )
2935 endPad = static_cast<PAD*>( aEndPad->Parent() );
2936
2937 constexpr PATH_OPTIMISATIONS opts = {
2938 .OptimiseViaLayers = false,
2939 .MergeTracks = false,
2940 .OptimiseTracesInPads = false,
2941 .InferViaInPad = true
2942 };
2943 const BOARD* board = GetBoard();
2944 return board->GetLengthCalculation()->CalculateLength( lengthItems, opts, startPad, endPad );
2945}
2946
2947
2949 const PNS::SOLID* aEndPad, const NETCLASS* aNetClass )
2950{
2951 std::vector<LENGTH_DELAY_CALCULATION_ITEM> lengthItems = getLengthDelayCalculationItems( aLine, aNetClass );
2952
2953 const PAD* startPad = nullptr;
2954 const PAD* endPad = nullptr;
2955
2956 if( aStartPad )
2957 startPad = static_cast<PAD*>( aStartPad->Parent() );
2958
2959 if( aEndPad )
2960 endPad = static_cast<PAD*>( aEndPad->Parent() );
2961
2962 constexpr PATH_OPTIMISATIONS opts = {
2963 .OptimiseViaLayers = false,
2964 .MergeTracks = false,
2965 .OptimiseTracesInPads = false,
2966 .InferViaInPad = true
2967 };
2968 const BOARD* board = GetBoard();
2969 return board->GetLengthCalculation()->CalculateDelay( lengthItems, opts, startPad, endPad );
2970}
2971
2972
2973int64_t PNS_KICAD_IFACE_BASE::CalculateLengthForDelay( int64_t aDesiredDelay, const int aWidth,
2974 const bool aIsDiffPairCoupled, const int aDiffPairCouplingGap,
2975 const int aPNSLayer, const NETCLASS* aNetClass )
2976{
2978 ctx.NetClass = aNetClass;
2979 ctx.Width = aWidth;
2980 ctx.IsDiffPairCoupled = aIsDiffPairCoupled;
2981 ctx.DiffPairCouplingGap = aDiffPairCouplingGap;
2982 ctx.Layer = GetBoardLayerFromPNSLayer( aPNSLayer );
2983
2984 const BOARD* board = GetBoard();
2985 return board->GetLengthCalculation()->CalculateLengthForDelay( aDesiredDelay, ctx );
2986}
2987
2988
2990 bool aIsDiffPairCoupled, int aDiffPairCouplingGap,
2991 int aPNSLayer, const NETCLASS* aNetClass )
2992{
2994 ctx.NetClass = aNetClass;
2995 ctx.Width = aWidth;
2996 ctx.IsDiffPairCoupled = aIsDiffPairCoupled;
2997 ctx.DiffPairCouplingGap = aDiffPairCouplingGap;
2998 ctx.Layer = GetBoardLayerFromPNSLayer( aPNSLayer );
2999
3000 const BOARD* board = GetBoard();
3002}
3003
3004
3005std::vector<LENGTH_DELAY_CALCULATION_ITEM>
3007{
3008 std::vector<LENGTH_DELAY_CALCULATION_ITEM> lengthItems;
3009
3010 for( int idx = 0; idx < aLine.Size(); idx++ )
3011 {
3012 const PNS::ITEM* lineItem = aLine[idx];
3013
3014 if( const PNS::LINE* l = dyn_cast<const PNS::LINE*>( lineItem ) )
3015 {
3017 item.SetLine( l->CLine() );
3018
3019 const PCB_LAYER_ID layer = GetBoardLayerFromPNSLayer( lineItem->Layer() );
3020 item.SetLayers( layer );
3021 item.SetEffectiveNetClass( aNetClass );
3022
3023 lengthItems.emplace_back( std::move( item ) );
3024 }
3025 else if( lineItem->OfKind( PNS::ITEM::VIA_T ) && idx > 0 && idx < aLine.Size() - 1 )
3026 {
3027 const int layerPrev = aLine[idx - 1]->Layer();
3028 const int layerNext = aLine[idx + 1]->Layer();
3029 const PCB_LAYER_ID pcbLayerPrev = GetBoardLayerFromPNSLayer( layerPrev );
3030 const PCB_LAYER_ID pcbLayerNext = GetBoardLayerFromPNSLayer( layerNext );
3031
3032 if( layerPrev != layerNext )
3033 {
3035 item.SetVia( static_cast<PCB_VIA*>( lineItem->GetSourceItem() ) );
3036 item.SetLayers( pcbLayerPrev, pcbLayerNext ); // TODO: BUG IS HERE!!!
3037 item.SetEffectiveNetClass( aNetClass );
3038 lengthItems.emplace_back( std::move( item ) );
3039 }
3040 }
3041 }
3042
3043 return lengthItems;
3044}
@ ERROR_OUTSIDE
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
#define SKIP_ENTERED_GROUP
@ OFF
Net (and netclass) colors are not shown.
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
NETINFO_ITEM * GetNet() const
Return #NET_INFO object for a given item.
void SetNet(NETINFO_ITEM *aNetInfo)
Set a NET_INFO object for the item.
Container for design settings for a BOARD object.
bool UseNetClassVia() const
Return true if netclass values should be used to obtain appropriate via size.
bool UseNetClassTrack() const
Return true if netclass values should be used to obtain appropriate track width.
bool UseNetClassDiffPair() const
Return true if netclass values should be used to obtain appropriate diff pair dimensions.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition board_item.h:237
void SetLocked(bool aLocked) override
Definition board_item.h:328
bool IsLocked() const override
virtual void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const
Convert the item shape to a closed polygon.
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
Definition board_item.h:319
FOOTPRINT * GetParentFootprint() const
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition board_item.h:257
virtual bool HasDrilledHole() const
Definition board_item.h:166
virtual int BoardCopperLayerCount() const
Return the total number of copper layers for the board that this item resides on.
virtual bool IsOnCopperLayer() const
Definition board_item.h:156
int GetMaxError() const
Manage layers needed to make a physical board.
int GetLayerDistance(PCB_LAYER_ID aFirstLayer, PCB_LAYER_ID aSecondLayer) const
Calculate the distance (height) between the two given copper layers.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:322
LENGTH_DELAY_CALCULATION * GetLengthCalculation() const
Returns the track length calculator.
Definition board.h:1402
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:558
constexpr void SetOrigin(const Vec &pos)
Definition box2.h:237
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:146
constexpr const Vec & GetOrigin() const
Definition box2.h:210
constexpr const SizeVec & GetSize() const
Definition box2.h:206
constexpr void SetEnd(coord_type x, coord_type y)
Definition box2.h:297
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:311
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition color4d.h:402
wxString GetName() const
Definition drc_rule.h:195
SEVERITY GetSeverity() const
Definition drc_rule.h:208
const MINOPTMAX< int > & GetValue() const
Definition drc_rule.h:187
MINOPTMAX< int > m_Value
Definition drc_rule.h:229
bool GetOption(OPTIONS option) const
Definition drc_rule.h:220
DRC_RULE * GetParentRule() const
Definition drc_rule.h:191
bool IsNull() const
Definition drc_rule.h:182
bool IsImplicit() const
Definition drc_rule.h:135
DRC_IMPLICIT_SOURCE GetImplicitSource() const
Definition drc_rule.h:139
A set of EDA_ITEMs (i.e., without duplicates).
Definition eda_group.h:46
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:120
virtual EDA_GROUP * GetParentGroup() const
Definition eda_item.h:117
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:111
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:150
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition eda_item.h:198
virtual std::vector< SHAPE * > MakeEffectiveShapes(bool aEdgeOnly=false) const
Make a set of SHAPE objects representing the EDA_SHAPE.
Definition eda_shape.h:379
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:98
virtual bool IsVisible() const
Definition eda_text.h:187
void SetPosition(const VECTOR2I &aPos) override
bool IsNetTie() const
Definition footprint.h:430
VECTOR2I GetPosition() const override
Definition footprint.h:327
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition kidialog.h:42
@ KD_WARNING
Definition kidialog.h:47
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
Definition kidialog.cpp:55
int ShowModal() override
Definition kidialog.cpp:93
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:105
COLOR4D WithAlpha(double aAlpha) const
Return a color with the same color, but the given alpha.
Definition color4d.h:312
double a
Alpha component.
Definition color4d.h:396
COLOR4D Brightened(double aFactor) const
Return a color that is brighter by a given factor, without modifying object.
Definition color4d.h:269
PCB specific render settings.
Definition pcb_painter.h:82
NET_COLOR_MODE GetNetColorMode() const
COLOR4D GetColor(const VIEW_ITEM *aItem, int aLayer) const override
Returns the color that should be used to draw the specific VIEW_ITEM on the specific layer using curr...
std::map< int, KIGFX::COLOR4D > & GetNetColorMap()
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
const std::set< int > & GetHighlightNetCodes() const
Return the netcode of currently highlighted net.
PCB_LAYER_ID GetPrimaryHighContrastLayer() const
Return the board layer which is in high-contrast mode.
Extend VIEW_ITEM by possibility of grouping items into a single object.
Definition view_group.h:43
virtual double ViewGetLOD(int aLayer, const VIEW *aView) const
Return the level of detail (LOD) of the item.
Definition view_item.h:155
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:67
Lightweight class which holds a pad, via, or a routed trace outline.
void SetLine(const SHAPE_LINE_CHAIN &aLine)
Sets the source SHAPE_LINE_CHAIN of this item.
void SetVia(const PCB_VIA *aVia)
Sets the VIA associated with this item.
void SetEffectiveNetClass(const NETCLASS *aNetClass)
Sets the effective net class for the item.
void SetLayers(const PCB_LAYER_ID aStart, const PCB_LAYER_ID aEnd=PCB_LAYER_ID::UNDEFINED_LAYER)
Sets the first and last layers associated with this item.
int64_t CalculateLengthForDelay(int64_t aDesiredDelay, const TUNING_PROFILE_GEOMETRY_CONTEXT &aCtx) const
Calculates the length of track required for the given delay in a specific geometry context.
int64_t CalculatePropagationDelayForShapeLineChain(const SHAPE_LINE_CHAIN &aShape, const TUNING_PROFILE_GEOMETRY_CONTEXT &aCtx) const
Gets the propagation delay for the given shape line chain.
int64_t CalculateDelay(std::vector< LENGTH_DELAY_CALCULATION_ITEM > &aItems, PATH_OPTIMISATIONS aOptimisations, const PAD *aStartPad=nullptr, const PAD *aEndPad=nullptr) const
Calculates the electrical propagation delay of the given items.
int64_t CalculateLength(std::vector< LENGTH_DELAY_CALCULATION_ITEM > &aItems, PATH_OPTIMISATIONS aOptimisations, const PAD *aStartPad=nullptr, const PAD *aEndPad=nullptr) const
Calculates the electrical length of the given items.
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition lseq.h:47
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
LSEQ CuStack() const
Return a sequence of copper layers in starting from the front/top and extending to the back/bottom.
Definition lset.cpp:263
T Min() const
Definition minoptmax.h:33
void SetMin(T v)
Definition minoptmax.h:41
bool HasMin() const
Definition minoptmax.h:37
T Opt() const
Definition minoptmax.h:35
A collection of nets and the parameters used to route or test these nets.
Definition netclass.h:45
COLOR4D GetPcbColor(bool aIsForSave=false) const
Definition netclass.h:189
bool HasPcbColor() const
Definition netclass.h:188
Handle the data for a net.
Definition netinfo.h:54
const wxString & GetNetname() const
Definition netinfo.h:112
int GetNetCode() const
Definition netinfo.h:106
void SetParent(BOARD *aParent)
Definition netinfo.h:151
void SetNetClass(const std::shared_ptr< NETCLASS > &aNetClass)
static NETINFO_ITEM * OrphanedItem()
NETINFO_ITEM meaning that there was no net assigned for an item, as there was no board storing net li...
Definition netinfo.h:255
NET_SETTINGS stores various net-related settings in a project context.
bool HasEffectiveNetClass(const wxString &aNetName) const
Determines if an effective netclass for the given net name has been cached.
std::shared_ptr< NETCLASS > GetCachedEffectiveNetClass(const wxString &aNetName) const
Returns an already cached effective netclass for the given net name.
void ForEachUniqueLayer(const std::function< void(PCB_LAYER_ID)> &aMethod) const
Runs the given callable for each active unique copper layer in this padstack, meaning F_Cu for MODE::...
void SetUnconnectedLayerMode(UNCONNECTED_LAYER_MODE aMode)
Definition padstack.h:364
UNCONNECTED_LAYER_MODE UnconnectedLayerMode() const
Definition padstack.h:363
@ NORMAL
Shape is the same on all layers.
Definition padstack.h:171
@ CUSTOM
Shapes can be defined on arbitrary layers.
Definition padstack.h:173
@ FRONT_INNER_BACK
Up to three shapes can be defined (F_Cu, inner copper layers, B_Cu)
Definition padstack.h:172
MODE Mode() const
Definition padstack.h:335
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition padstack.h:177
static constexpr PCB_LAYER_ID INNER_LAYERS
! The layer identifier to use for "inner layers" on top/inner/bottom padstacks
Definition padstack.h:180
Definition pad.h:55
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition pad.h:560
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer, FLASHING flashPTHPads=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition pad.cpp:961
const VECTOR2I & GetDrillSize() const
Definition pad.h:317
PAD_ATTRIB GetAttribute() const
Definition pad.h:563
int GetPadToDieDelay() const
Definition pad.h:581
const PADSTACK & Padstack() const
Definition pad.h:333
const VECTOR2I & GetOffset(PCB_LAYER_ID aLayer) const
Definition pad.h:329
bool IsFreePad() const
Definition pad.cpp:363
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition pad.h:420
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(PCB_LAYER_ID aLayer, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition pad.cpp:949
VECTOR2I ShapePos(PCB_LAYER_ID aLayer) const
Definition pad.cpp:1536
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
Return a SHAPE_SEGMENT object representing the pad's hole.
Definition pad.cpp:1063
int GetPadToDieLength() const
Definition pad.h:578
DISPLAY_OPTIONS m_Display
void SetMid(const VECTOR2I &aMid)
Definition pcb_track.h: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:267
const JOINT * FindJoint(const VECTOR2I &aPos, int aLayer, NET_HANDLE aNet) const
Search for a joint at a given position, layer and belonging to given net.
bool Add(std::unique_ptr< SEGMENT > aSegment, bool aAllowRedundant=false)
Add an item to the current node.
Definition pns_node.cpp:749
void SetRuleResolver(RULE_RESOLVER *aFunc)
Definition pns_node.h:273
void AddEdgeExclusion(std::unique_ptr< SHAPE > aShape)
Definition pns_node.cpp:793
const ITEM_OWNER * Owner() const
Return the owner of this item, or NULL if there's none.
Definition pns_item.h:72
const SEG & Seg() const
Definition pns_segment.h:93
void SetEnds(const VECTOR2I &a, const VECTOR2I &b)
int Width() const override
Definition pns_segment.h:88
void SetTrackWidth(int aWidth)
void SetBoardMinTrackWidth(int aWidth)
void SetDiffPairViaGapSameAsTraceGap(bool aEnable)
void SetDiffPairWidth(int aWidth)
void SetDiffPairWidthSource(const wxString &aSource)
void SetDiffPairGapSource(const wxString &aSource)
void SetDiffPairGap(int aGap)
void SetHoleToHole(int aHoleToHole)
void SetViaDrill(int aDrill)
void SetDiffPairViaGap(int aGap)
void SetDiffPairHoleToHole(int aHoleToHole)
void SetMinClearance(int aClearance)
void SetClearance(int aClearance)
void SetViaDiameter(int aDiameter)
void SetClearanceSource(const wxString &aSource)
void SetWidthSource(const wxString &aSource)
void SetTrackWidthIsExplicit(bool aIsExplicit)
bool syncGraphicalItem(PNS::NODE *aWorld, PCB_SHAPE *aItem)
void AddItem(PNS::ITEM *aItem) override
bool syncDimension(PNS::NODE *aWorld, PCB_DIMENSION_BASE *aDimension)
virtual EDA_UNITS GetUnits() const
PNS::DEBUG_DECORATOR * m_debugDecorator
void SetDebugDecorator(PNS::DEBUG_DECORATOR *aDec)
bool syncZone(PNS::NODE *aWorld, ZONE *aZone, SHAPE_POLY_SET *aBoardOutline)
void SetBoard(BOARD *aBoard)
long long int CalculateRoutedPathLength(const PNS::ITEM_SET &aLine, const PNS::SOLID *aStartPad, const PNS::SOLID *aEndPad, const NETCLASS *aNetClass) override
int64_t CalculateRoutedPathDelay(const PNS::ITEM_SET &aLine, const PNS::SOLID *aStartPad, const PNS::SOLID *aEndPad, const NETCLASS *aNetClass) override
std::unique_ptr< PNS::ARC > syncArc(PCB_ARC *aArc)
void RemoveItem(PNS::ITEM *aItem) override
bool IsPNSCopperLayer(int aPNSLayer) const override
int64_t CalculateLengthForDelay(int64_t aDesiredDelay, int aWidth, bool aIsDiffPairCoupled, int aDiffPairCouplingGap, int aPNSLayer, const NETCLASS *aNetClass) override
PNS::RULE_RESOLVER * GetRuleResolver() override
bool syncTextItem(PNS::NODE *aWorld, BOARD_ITEM *aItem, PCB_LAYER_ID aLayer)
std::vector< LENGTH_DELAY_CALCULATION_ITEM > getLengthDelayCalculationItems(const PNS::ITEM_SET &aLine, const NETCLASS *aNetClass) const
bool IsKicadCopperLayer(PCB_LAYER_ID aPcbnewLayer) const
std::vector< std::unique_ptr< PNS::SOLID > > syncPad(PAD *aPad)
void SetStartLayerFromPCBNew(PCB_LAYER_ID aLayer)
bool syncBarcode(PNS::NODE *aWorld, PCB_BARCODE *aBarcode)
bool IsFlashedOnLayer(const PNS::ITEM *aItem, int aLayer) const override
PCB_LAYER_ID GetBoardLayerFromPNSLayer(int aLayer) const override
BOARD * GetBoard() const
void SyncWorld(PNS::NODE *aWorld) override
int StackupHeight(int aFirstLayer, int aSecondLayer) const override
int64_t CalculateDelayForShapeLineChain(const SHAPE_LINE_CHAIN &aShape, int aWidth, bool aIsDiffPairCoupled, int aDiffPairCouplingGap, int aPNSLayer, const NETCLASS *aNetClass) override
PNS::DEBUG_DECORATOR * GetDebugDecorator() override
std::unique_ptr< PNS::SEGMENT > syncTrack(PCB_TRACK *aTrack)
PNS_PCBNEW_RULE_RESOLVER * m_ruleResolver
PNS::NET_HANDLE GetOrphanedNetHandle() override
std::unique_ptr< PNS::VIA > syncVia(PCB_VIA *aVia)
int GetPNSLayerFromBoardLayer(PCB_LAYER_ID aLayer) const override
PNS_LAYER_RANGE SetLayersFromPCBNew(PCB_LAYER_ID aStartLayer, PCB_LAYER_ID aEndLayer)
void UpdateItem(PNS::ITEM *aItem) override
bool ImportSizes(PNS::SIZES_SETTINGS &aSizes, PNS::ITEM *aStartItem, PNS::NET_HANDLE aNet, VECTOR2D aStartPosition) override
bool inheritTrackWidth(PNS::ITEM *aItem, int *aInheritedWidth, const VECTOR2I &aStartPosition)
void SetView(KIGFX::VIEW *aView)
void RemoveItem(PNS::ITEM *aItem) override
void AddItem(PNS::ITEM *aItem) override
void UpdateItem(PNS::ITEM *aItem) override
std::map< PAD *, OFFSET > m_fpOffsets
int GetNetCode(PNS::NET_HANDLE aNet) const override
virtual void SetHostTool(PCB_TOOL_BASE *aTool)
void DisplayItem(const PNS::ITEM *aItem, int aClearance, bool aEdit=false, int aFlags=0) override
std::unique_ptr< BOARD_COMMIT > m_commit
void EraseView() override
void HideItem(PNS::ITEM *aItem) override
void UpdateNet(PNS::NET_HANDLE aNet) override
BOARD_CONNECTED_ITEM * createBoardItem(PNS::ITEM *aItem)
KIGFX::VIEW * m_view
void DisplayPathLine(const SHAPE_LINE_CHAIN &aLine, int aImportance) override
std::unordered_map< BOARD_ITEM *, EDA_GROUP * > m_itemGroups
bool IsItemVisible(const PNS::ITEM *aItem) const override
std::unordered_set< BOARD_ITEM * > m_hiddenItems
EDA_UNITS GetUnits() const override
bool IsAnyLayerVisible(const PNS_LAYER_RANGE &aLayer) const override
PCB_TOOL_BASE * m_tool
void modifyBoardItem(PNS::ITEM *aItem)
void Commit() override
KIGFX::VIEW_GROUP * m_previewItems
void DisplayRatline(const SHAPE_LINE_CHAIN &aRatline, PNS::NET_HANDLE aNet) override
std::unordered_map< BOARD_ITEM *, std::vector< BOARD_ITEM * > > m_replacementMap
wxString GetNetName(PNS::NET_HANDLE aNet) const override
~PNS_KICAD_IFACE() override
Represent a contiguous set of PCB layers.
int Start() const
bool Overlaps(const PNS_LAYER_RANGE &aOther) const
int End() const
PNS_LAYER_RANGE Intersection(const PNS_LAYER_RANGE &aOther) const
Shortcut for comparisons/overlap tests.
PNS_PCBNEW_DEBUG_DECORATOR(PNS::ROUTER_IFACE *aIface)
void AddPoint(const VECTOR2I &aP, const KIGFX::COLOR4D &aColor, int aSize, const wxString &aName=wxT(""), const SRC_LOCATION_INFO &aSrcLoc=SRC_LOCATION_INFO()) override
void AddShape(const BOX2I &aBox, const KIGFX::COLOR4D &aColor, int aOverrideWidth=0, const wxString &aName=wxT(""), const SRC_LOCATION_INFO &aSrcLoc=SRC_LOCATION_INFO()) override
void AddItem(const PNS::ITEM *aItem, const KIGFX::COLOR4D &aColor, int aOverrideWidth=0, const wxString &aName=wxT(""), const SRC_LOCATION_INFO &aSrcLoc=SRC_LOCATION_INFO()) override
virtual void Message(const wxString &msg, const SRC_LOCATION_INFO &aSrcLoc=SRC_LOCATION_INFO()) override
void SetView(KIGFX::VIEW *aView)
void AddShape(const SHAPE *aShape, const KIGFX::COLOR4D &aColor, int aOverrideWidth=0, const wxString &aName=wxT(""), const SRC_LOCATION_INFO &aSrcLoc=SRC_LOCATION_INFO()) override
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 aPartition=true, bool aSimplify=false)
Build a polygon triangulation, needed to draw a polygon on OpenGL and in some other calculations.
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
const TRIANGULATED_POLYGON * TriangulatedPolygon(int aIndex) const
unsigned int TriangulatedPolyCount() const
Return the number of triangulated polygons.
int OutlineCount() const
Return the number of outlines in the set.
SHAPE * Clone() const override
Return a dynamically allocated copy of the shape.
Represent a simple polygon consisting of a zero-thickness closed chain of connected line segments.
void Append(int aX, int aY)
Append a new point at the end of the polygon.
An abstract shape on 2D plane.
Definition shape.h:126
double Distance(const VECTOR2< extended_type > &aVector) const
Compute the distance between two vectors.
Definition vector2d.h:561
static constexpr extended_type ECOORD_MAX
Definition vector2d.h:76
VECTOR2_TRAITS< int32_t >::extended_type extended_type
Definition vector2d.h:73
Handle a list of polygons defining a copper zone.
Definition zone.h:73
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
Definition zone.cpp:1203
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition zone.h:719
bool GetDoNotAllowVias() const
Definition zone.h:730
bool GetDoNotAllowPads() const
Definition zone.h:732
bool GetDoNotAllowTracks() const
Definition zone.h:731
SHAPE_POLY_SET * Outline()
Definition zone.h:340
bool GetDoNotAllowFootprints() const
Definition zone.h:733
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition zone.h:136
bool HasKeepoutParametersSet() const
Accessor to determine if any keepout parameters are set.
Definition zone.h:710
DRC_CONSTRAINT_T
Definition drc_rule.h:47
@ VIA_DIAMETER_CONSTRAINT
Definition drc_rule.h:70
@ DIFF_PAIR_GAP_CONSTRAINT
Definition drc_rule.h:73
@ TRACK_WIDTH_CONSTRAINT
Definition drc_rule.h:59
@ EDGE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:53
@ LENGTH_CONSTRAINT
Definition drc_rule.h:71
@ CLEARANCE_CONSTRAINT
Definition drc_rule.h:49
@ MAX_UNCOUPLED_CONSTRAINT
Definition drc_rule.h:74
@ SKEW_CONSTRAINT
Definition drc_rule.h:72
@ HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:51
@ HOLE_SIZE_CONSTRAINT
Definition drc_rule.h:54
@ PHYSICAL_CLEARANCE_CONSTRAINT
Definition drc_rule.h:77
@ HOLE_TO_HOLE_CONSTRAINT
Definition drc_rule.h:52
#define _(s)
@ NO_RECURSE
Definition eda_item.h:53
#define ROUTER_TRANSIENT
transient items that should NOT be cached
#define IN_EDIT
Item currently edited.
EDA_UNITS
Definition eda_units.h:48
static constexpr void hash_combine(std::size_t &seed)
This is a dummy function to take the final case of hash_combine below.
Definition hash.h:32
constexpr PCB_LAYER_ID PCBNEW_LAYER_ID_START
Definition layer_ids.h:174
@ ALWAYS_FLASHED
Always flashed for connectivity.
Definition layer_ids.h:186
@ LAYER_RATSNEST
Definition layer_ids.h:253
@ LAYER_SELECT_OVERLAY
Selected items overlay.
Definition layer_ids.h:280
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ Edge_Cuts
Definition layer_ids.h:112
@ B_Cu
Definition layer_ids.h:65
@ Margin
Definition layer_ids.h:113
@ UNDEFINED_LAYER
Definition layer_ids.h:61
@ PCB_LAYER_ID_COUNT
Definition layer_ids.h:171
@ F_Cu
Definition layer_ids.h:64
This file contains miscellaneous commonly used macros and functions.
#define UNIMPLEMENTED_FOR(type)
Definition macros.h:96
@ APPEARANCE
Visibility flag has changed.
Definition view_item.h:53
Push and Shove diff pair dimensions (gap) settings dialog.
CONSTRAINT_TYPE
Definition pns_node.h:52
void * NET_HANDLE
Definition pns_item.h:55
@ MK_LOCKED
Definition pns_item.h:45
STL namespace.
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:103
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:99
@ PTH
Plated through hole pad.
Definition padstack.h:98
@ CONN
Like smd, does not appear on the solder paste layer (default) Note: also has a special attribute in G...
Definition padstack.h:100
@ CASTELLATED
a pad with a castellated through hole
Definition padstack.h:121
BARCODE class definition.
@ SHOW_WITH_VIA_WHILE_ROUTING_OR_DRAGGING
@ SHOW_WHILE_ROUTING
@ SHOW_WITH_VIA_ALWAYS
@ SHOW_WITH_VIA_WHILE_ROUTING
static bool isEdge(const PNS::ITEM *aItem)
static bool isHole(const PNS::ITEM *aItem)
static bool isCopper(const PNS::ITEM *aItem)
#define ENTERED_GROUP_MAGIC_NUMBER
@ RPT_SEVERITY_IGNORE
#define PNS_SEMI_SOLID
@ SH_SEGMENT
line segment
Definition shape.h:48
@ SH_ARC
circular arc
Definition shape.h:54
@ SH_LINE_CHAIN
line chain (polyline)
Definition shape.h:49
VECTOR2I::extended_type ecoord
const PNS::ITEM * A
bool operator==(const CLEARANCE_CACHE_KEY &other) const
const PNS::ITEM * B
CLEARANCE_CACHE_KEY(const PNS::ITEM *aA, const PNS::ITEM *aB, bool aFlag)
const PNS::ITEM * item
bool operator==(const HULL_CACHE_KEY &other) const
Struct to control which optimisations the length calculation code runs on the given path objects.
TRACK_CLEARANCE_MODE m_TrackClearance
An abstract function object, returning a design rule (clearance, diff pair gap, etc) required between...
Definition pns_node.h:73
wxString m_RuleName
Definition pns_node.h:77
bool m_IsTimeDomain
Definition pns_node.h:80
MINOPTMAX< int > m_Value
Definition pns_node.h:75
CONSTRAINT_TYPE m_Type
Definition pns_node.h:74
A data structure to contain basic geometry data which can affect signal propagation calculations.
int64_t DiffPairCouplingGap
The gap between coupled tracks.
const NETCLASS * NetClass
The net class this track belongs to.
int64_t Width
The width (in internal units) of the track.
bool IsDiffPairCoupled
Whether this track or via is a member of a coupled differential pair.
PCB_LAYER_ID Layer
The layer this track is on.
std::size_t operator()(const CLEARANCE_CACHE_KEY &k) const
std::size_t operator()(const HULL_CACHE_KEY &k) const
KIBIS top(path, &reporter)
const SHAPE_LINE_CHAIN chain
arc1_slc SetWidth(0)
wxString result
Test unit parsing edge cases and error handling.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:229
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:78
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:88
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition typeinfo.h:106
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition typeinfo.h:103
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:97
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition typeinfo.h:104
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:93
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition typeinfo.h:108
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:92
@ PCB_REFERENCE_IMAGE_T
class PCB_REFERENCE_IMAGE, bitmap on a layer
Definition typeinfo.h:89
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition typeinfo.h:90
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
Definition typeinfo.h:101
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
Definition typeinfo.h:107
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:95
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition typeinfo.h:102
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:87
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:98
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition typeinfo.h:94
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:96
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition typeinfo.h:105
Casted dyn_cast(From aObject)
A lightweight dynamic downcast.
Definition typeinfo.h:61
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694