KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pns_kicad_iface.cpp
Go to the documentation of this file.
1/*
2 * KiRouter - a push-and-(sometimes-)shove PCB router
3 *
4 * Copyright (C) 2013-2016 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * Author: Tomasz Wlostowski <[email protected]>
7 *
8 * This program is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include <board.h>
25#include <netinfo.h>
26#include <footprint.h>
27#include <layer_range.h>
29#include <pad.h>
30#include <pcb_track.h>
31#include <zone.h>
32#include <pcb_shape.h>
33#include <pcb_generator.h>
34#include <pcb_text.h>
35#include <pcb_table.h>
36#include <pcb_tablecell.h>
37#include <board_commit.h>
38#include <eda_group.h>
39#include <layer_ids.h>
40#include <kidialog.h>
41#include <tools/pcb_tool_base.h>
42#include <tool/tool_manager.h>
44
46#include <pcb_painter.h>
47
48#include <geometry/shape.h>
50#include <geometry/shape_arc.h>
52
53#include <drc/drc_rule.h>
54#include <drc/drc_engine.h>
55
57
58#include <wx/log.h>
59
60#include <memory>
61
62#include <advanced_config.h>
63#include <pcbnew_settings.h>
64#include <macros.h>
65
66#include "pns_kicad_iface.h"
67#include "pns_arc.h"
68#include "pns_sizes_settings.h"
69#include "pns_item.h"
70#include "pns_layerset.h"
71#include "pns_line.h"
72#include "pns_solid.h"
73#include "pns_segment.h"
74#include "pns_node.h"
75#include "pns_router.h"
76#include "pns_debug_decorator.h"
77#include "router_preview_item.h"
78
80
81
83{
84 const PNS::ITEM* A;
85 const PNS::ITEM* B;
86 bool Flag;
87
88 bool operator==(const CLEARANCE_CACHE_KEY& other) const
89 {
90 return A == other.A && B == other.B && Flag == other.Flag;
91 }
92};
93
94namespace std
95{
96 template <>
98 {
99 std::size_t operator()( const CLEARANCE_CACHE_KEY& k ) const
100 {
101 size_t retval = 0xBADC0FFEE0DDF00D;
102 hash_combine( retval, hash<const void*>()( k.A ), hash<const void*>()( k.B ), hash<int>()( k.Flag ) );
103 return retval;
104 }
105 };
106}
107
108
110{
111public:
112 PNS_PCBNEW_RULE_RESOLVER( BOARD* aBoard, PNS::ROUTER_IFACE* aRouterIface );
114
115 int Clearance( const PNS::ITEM* aA, const PNS::ITEM* aB,
116 bool aUseClearanceEpsilon = true ) override;
117
119 int DpNetPolarity( PNS::NET_HANDLE aNet ) override;
120 bool DpNetPair( const PNS::ITEM* aItem, PNS::NET_HANDLE& aNetP,
121 PNS::NET_HANDLE& aNetN ) override;
122
123 int NetCode( PNS::NET_HANDLE aNet ) override;
124 wxString NetName( PNS::NET_HANDLE aNet ) override;
125
126 bool IsInNetTie( const PNS::ITEM* aA ) override;
127 bool IsNetTieExclusion( const PNS::ITEM* aItem, const VECTOR2I& aCollisionPos,
128 const PNS::ITEM* aCollidingItem ) override;
129
130 bool IsDrilledHole( const PNS::ITEM* aItem ) override;
131 bool IsNonPlatedSlot( const PNS::ITEM* aItem ) override;
132
137 bool IsKeepout( const PNS::ITEM* aObstacle, const PNS::ITEM* aItem, bool* aEnforce ) override;
138
139 bool QueryConstraint( PNS::CONSTRAINT_TYPE aType, const PNS::ITEM* aItemA,
140 const PNS::ITEM* aItemB, int aLayer,
141 PNS::CONSTRAINT* aConstraint ) override;
142
143 int ClearanceEpsilon() const override { return m_clearanceEpsilon; }
144
145 void ClearCacheForItems( std::vector<const PNS::ITEM*>& aItems ) override;
146 void ClearCaches() override;
147 void ClearTemporaryCaches() override;
148
149private:
150 BOARD_ITEM* getBoardItem( const PNS::ITEM* aItem, PCB_LAYER_ID aBoardLayer, int aIdx = 0 );
151
152private:
159
160 std::unordered_map<CLEARANCE_CACHE_KEY, int> m_clearanceCache;
161 std::unordered_map<CLEARANCE_CACHE_KEY, int> m_tempClearanceCache;
162};
163
164
166 PNS::ROUTER_IFACE* aRouterIface ) :
167 m_routerIface( aRouterIface ),
168 m_board( aBoard ),
169 m_dummyTracks{ { aBoard }, { aBoard } },
170 m_dummyArcs{ { aBoard }, { aBoard } },
171 m_dummyVias{ { aBoard }, { aBoard } }
172{
173 for( PCB_TRACK& track : m_dummyTracks )
174 track.SetFlags( ROUTER_TRANSIENT );
175
176 for( PCB_ARC& arc : m_dummyArcs )
177 arc.SetFlags( ROUTER_TRANSIENT );
178
179 for ( PCB_VIA& via : m_dummyVias )
180 via.SetFlags( ROUTER_TRANSIENT );
181
182 if( aBoard )
183 m_clearanceEpsilon = aBoard->GetDesignSettings().GetDRCEpsilon();
184 else
185 m_clearanceEpsilon = 0;
186}
187
188
192
193
195{
196 BOARD_ITEM* item = aA->BoardItem();
197
198 return item && item->GetParentFootprint() && item->GetParentFootprint()->IsNetTie();
199}
200
201
203 const VECTOR2I& aCollisionPos,
204 const PNS::ITEM* aCollidingItem )
205{
206 if( !aItem || !aCollidingItem )
207 return false;
208
209 std::shared_ptr<DRC_ENGINE> drcEngine = m_board->GetDesignSettings().m_DRCEngine;
210 BOARD_ITEM* item = aItem->BoardItem();
211 BOARD_ITEM* collidingItem = aCollidingItem->BoardItem();
212
213 FOOTPRINT* collidingFp = collidingItem->GetParentFootprint();
214 FOOTPRINT* itemFp = item ? item->GetParentFootprint() : nullptr;
215
216 if( collidingFp && itemFp && ( collidingFp == itemFp ) && itemFp->IsNetTie() )
217 {
218 // Two items colliding from the same net tie footprint are not checked
219 return true;
220 }
221
222 if( drcEngine )
223 {
224 return drcEngine->IsNetTieExclusion( NetCode( aItem->Net() ),
225 m_routerIface->GetBoardLayerFromPNSLayer( aItem->Layer() ),
226 aCollisionPos, collidingItem );
227 }
228
229 return false;
230}
231
232
233bool PNS_PCBNEW_RULE_RESOLVER::IsKeepout( const PNS::ITEM* aObstacle, const PNS::ITEM* aItem,
234 bool* aEnforce )
235{
236 auto checkKeepout =
237 []( const ZONE* aKeepout, const BOARD_ITEM* aOther )
238 {
239 if( !aOther )
240 return false;
241
242 if( aKeepout->GetDoNotAllowTracks() && aOther->IsType( { PCB_ARC_T, PCB_TRACE_T } ) )
243 return true;
244
245 if( aKeepout->GetDoNotAllowVias() && aOther->Type() == PCB_VIA_T )
246 return true;
247
248 if( aKeepout->GetDoNotAllowPads() && aOther->Type() == PCB_PAD_T )
249 return true;
250
251 // Incomplete test, but better than nothing:
252 if( aKeepout->GetDoNotAllowFootprints() && aOther->Type() == PCB_PAD_T )
253 {
254 return !aKeepout->GetParentFootprint()
255 || aKeepout->GetParentFootprint() != aOther->GetParentFootprint();
256 }
257
258 return false;
259 };
260
261 if( aObstacle->Parent() && aObstacle->Parent()->Type() == PCB_ZONE_T )
262 {
263 const ZONE* zone = static_cast<ZONE*>( aObstacle->Parent() );
264
265 if( zone->GetIsRuleArea() && zone->HasKeepoutParametersSet() )
266 {
267 *aEnforce = checkKeepout( zone,
268 getBoardItem( aItem, m_routerIface->GetBoardLayerFromPNSLayer(
269 aObstacle->Layer() ) ) );
270 return true;
271 }
272 }
273
274 return false;
275}
276
277
278static bool isCopper( const PNS::ITEM* aItem )
279{
280 if ( !aItem )
281 return false;
282
283 const BOARD_ITEM *parent = aItem->Parent();
284
285 return !parent || parent->IsOnCopperLayer();
286}
287
288
289static bool isHole( const PNS::ITEM* aItem )
290{
291 if ( !aItem )
292 return false;
293
294 return aItem->OfKind( PNS::ITEM::HOLE_T );
295}
296
297
298static bool isEdge( const PNS::ITEM* aItem )
299{
300 if ( !aItem )
301 return false;
302
303 const PCB_SHAPE *parent = dynamic_cast<PCB_SHAPE*>( aItem->BoardItem() );
304
305 return parent && ( parent->IsOnLayer( Edge_Cuts ) || parent->IsOnLayer( Margin ) );
306}
307
308
310{
311 if( !isHole( aItem ) )
312 return false;
313
314 BOARD_ITEM* parent = aItem->Parent();
315
316 if( !parent && aItem->ParentPadVia() )
317 parent = aItem->ParentPadVia()->Parent();
318
319 return parent && parent->HasDrilledHole();
320}
321
322
324{
325 if( !isHole( aItem ) )
326 return false;
327
328 BOARD_ITEM* parent = aItem->Parent();
329
330 if( !parent && aItem->ParentPadVia() )
331 parent = aItem->ParentPadVia()->Parent();
332
333 if( parent )
334 {
335 if( parent->Type() == PCB_PAD_T )
336 {
337 PAD* pad = static_cast<PAD*>( parent );
338
339 return pad->GetAttribute() == PAD_ATTRIB::NPTH
340 && pad->GetDrillSizeX() != pad->GetDrillSizeY();
341 }
342
343 // Via holes are (currently) always round, and always plated
344 }
345
346 return false;
347}
348
349
351{
352 switch( aItem->Kind() )
353 {
354 case PNS::ITEM::ARC_T:
355 m_dummyArcs[aIdx].SetLayer( aBoardLayer );
356 m_dummyArcs[aIdx].SetNet( static_cast<NETINFO_ITEM*>( aItem->Net() ) );
357 m_dummyArcs[aIdx].SetStart( aItem->Anchor( 0 ) );
358 m_dummyArcs[aIdx].SetEnd( aItem->Anchor( 1 ) );
359 return &m_dummyArcs[aIdx];
360
361 case PNS::ITEM::VIA_T:
363 m_dummyVias[aIdx].SetLayer( aBoardLayer );
364 m_dummyVias[aIdx].SetNet( static_cast<NETINFO_ITEM*>( aItem->Net() ) );
365 m_dummyVias[aIdx].SetStart( aItem->Anchor( 0 ) );
366 return &m_dummyVias[aIdx];
367
370 m_dummyTracks[aIdx].SetLayer( aBoardLayer );
371 m_dummyTracks[aIdx].SetNet( static_cast<NETINFO_ITEM*>( aItem->Net() ) );
372 m_dummyTracks[aIdx].SetStart( aItem->Anchor( 0 ) );
373 m_dummyTracks[aIdx].SetEnd( aItem->Anchor( 1 ) );
374 return &m_dummyTracks[aIdx];
375
376 default:
377 return nullptr;
378 }
379}
380
381
383 const PNS::ITEM* aItemA, const PNS::ITEM* aItemB,
384 int aPNSLayer, PNS::CONSTRAINT* aConstraint )
385{
386 std::shared_ptr<DRC_ENGINE> drcEngine = m_board->GetDesignSettings().m_DRCEngine;
387
388 if( !drcEngine )
389 return false;
390
391 DRC_CONSTRAINT_T hostType;
392
393 switch ( aType )
394 {
407 default: return false; // should not happen
408 }
409
410 BOARD_ITEM* parentA = aItemA ? aItemA->BoardItem() : nullptr;
411 BOARD_ITEM* parentB = aItemB ? aItemB->BoardItem() : nullptr;
412 PCB_LAYER_ID board_layer = m_routerIface->GetBoardLayerFromPNSLayer( aPNSLayer );
413 DRC_CONSTRAINT hostConstraint;
414
415 // A track being routed may not have a BOARD_ITEM associated yet.
416 if( aItemA && !parentA )
417 parentA = getBoardItem( aItemA, board_layer, 0 );
418
419 if( aItemB && !parentB )
420 parentB = getBoardItem( aItemB, board_layer, 1 );
421
422 if( parentA )
423 hostConstraint = drcEngine->EvalRules( hostType, parentA, parentB, board_layer );
424
425 if( hostConstraint.IsNull() )
426 return false;
427
428 if( hostConstraint.GetSeverity() == RPT_SEVERITY_IGNORE )
429 {
430 aConstraint->m_Value.SetMin( -1 );
431 aConstraint->m_RuleName = hostConstraint.GetName();
432 aConstraint->m_Type = aType;
433 return true;
434 }
435
436 switch ( aType )
437 {
450 aConstraint->m_Value = hostConstraint.GetValue();
451 aConstraint->m_RuleName = hostConstraint.GetName();
452 aConstraint->m_Type = aType;
453 aConstraint->m_IsTimeDomain = hostConstraint.GetOption( DRC_CONSTRAINT::OPTIONS::TIME_DOMAIN );
454 return true;
455
456 default:
457 return false;
458 }
459}
460
461
462void PNS_PCBNEW_RULE_RESOLVER::ClearCacheForItems( std::vector<const PNS::ITEM*>& aItems )
463{
464 int n_pruned = 0;
465 std::set<const PNS::ITEM*> remainingItems( aItems.begin(), aItems.end() );
466
467/* We need to carefully check both A and B item pointers in the cache against dirty/invalidated
468 items in the set, as the clearance relation is commutative ( CL[a,b] == CL[b,a] ). The code
469 below is a bit ugly, but works in O(n*log(m)) and is run once or twice during ROUTER::Move() call
470 - so I hope it still gets better performance than no cache at all */
471 for( auto it = m_clearanceCache.begin(); it != m_clearanceCache.end(); )
472 {
473 bool dirty = remainingItems.find( it->first.A ) != remainingItems.end();
474 dirty |= remainingItems.find( it->first.B) != remainingItems.end();
475
476 if( dirty )
477 {
478 it = m_clearanceCache.erase( it );
479 n_pruned++;
480 } else
481 it++;
482 }
483#if 0
484 printf("ClearCache : n_pruned %d\n", n_pruned );
485#endif
486}
487
488
494
495
500
501
503 bool aUseClearanceEpsilon )
504{
505 CLEARANCE_CACHE_KEY key = { aA, aB, aUseClearanceEpsilon };
506
507 // Search cache (used for actual board items)
508 auto it = m_clearanceCache.find( key );
509
510 if( it != m_clearanceCache.end() )
511 return it->second;
512
513 // Search cache (used for temporary items within an algorithm)
514 it = m_tempClearanceCache.find( key );
515
516 if( it != m_tempClearanceCache.end() )
517 return it->second;
518
519 PNS::CONSTRAINT constraint;
520 int rv = 0;
521 PNS_LAYER_RANGE layers;
522
523 if( !aB )
524 layers = aA->Layers();
525 else if( isEdge( aA ) )
526 layers = aB->Layers();
527 else if( isEdge( aB ) )
528 layers = aA->Layers();
529 else
530 layers = aA->Layers().Intersection( aB->Layers() );
531
532 // Normalize layer range (no -1 magic numbers)
534
535 for( int layer = layers.Start(); layer <= layers.End(); ++layer )
536 {
537 if( IsDrilledHole( aA ) && IsDrilledHole( aB ) )
538 {
539 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_HOLE_TO_HOLE, aA, aB, layer, &constraint ) )
540 {
541 if( constraint.m_Value.Min() > rv )
542 rv = constraint.m_Value.Min();
543 }
544 }
545 else if( isHole( aA ) || isHole( aB ) )
546 {
547 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_HOLE_CLEARANCE, aA, aB, layer, &constraint ) )
548 {
549 if( constraint.m_Value.Min() > rv )
550 rv = constraint.m_Value.Min();
551 }
552 }
553
554 // No 'else'; plated holes get both HOLE_CLEARANCE and CLEARANCE
555 if( isCopper( aA ) && ( !aB || isCopper( aB ) ) )
556 {
557 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_CLEARANCE, aA, aB, layer, &constraint ) )
558 {
559 if( constraint.m_Value.Min() > rv )
560 rv = constraint.m_Value.Min();
561 }
562 }
563
564 // No 'else'; non-plated milled holes get both HOLE_CLEARANCE and EDGE_CLEARANCE
565 if( isEdge( aA ) || IsNonPlatedSlot( aA ) || isEdge( aB ) || IsNonPlatedSlot( aB ) )
566 {
567 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_EDGE_CLEARANCE, aA, aB, layer, &constraint ) )
568 {
569 if( constraint.m_Value.Min() > rv )
570 rv = constraint.m_Value.Min();
571 }
572 }
573
574 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_PHYSICAL_CLEARANCE, aA, aB, layer, &constraint ) )
575 {
576 if( constraint.m_Value.Min() > rv )
577 rv = constraint.m_Value.Min();
578 }
579 }
580
581 if( aUseClearanceEpsilon && rv > 0 )
582 rv = std::max( 0, rv - m_clearanceEpsilon );
583
584 /*
585 * It makes no sense to put items that have no owning NODE in the cache - they can be
586 * allocated on stack and we can't really invalidate them in the cache when they are
587 * destroyed. Probably a better idea would be to use a static unique counter in PNS::ITEM
588 * constructor to generate the cache keys.
589 *
590 * However, algorithms DO greatly benefit from using the cache, so ownerless items need to be
591 * cached. In order to easily clear those only, a temporary cache is created. If this doesn't
592 * seem nice, an alternative is clearing the full cache once it reaches a certain size. Also
593 * not pretty, but VERY effective to keep things interactive.
594 */
595 if( aA && aB )
596 {
597 if ( aA->Owner() && aB->Owner() )
598 m_clearanceCache[ key ] = rv;
599 else
600 m_tempClearanceCache[ key ] = rv;
601 }
602
603 return rv;
604}
605
606
607bool PNS_KICAD_IFACE_BASE::inheritTrackWidth( PNS::ITEM* aItem, int* aInheritedWidth )
608{
609 VECTOR2I p;
610
611 assert( aItem->Owner() != nullptr );
612
613 auto tryGetTrackWidth =
614 []( PNS::ITEM* aPnsItem ) -> int
615 {
616 switch( aPnsItem->Kind() )
617 {
618 case PNS::ITEM::SEGMENT_T: return static_cast<PNS::SEGMENT*>( aPnsItem )->Width();
619 case PNS::ITEM::ARC_T: return static_cast<PNS::ARC*>( aPnsItem )->Width();
620 default: return -1;
621 }
622 };
623
624 int itemTrackWidth = tryGetTrackWidth( aItem );
625
626 if( itemTrackWidth > 0 )
627 {
628 *aInheritedWidth = itemTrackWidth;
629 return true;
630 }
631
632 switch( aItem->Kind() )
633 {
634 case PNS::ITEM::VIA_T: p = static_cast<PNS::VIA*>( aItem )->Pos(); break;
635 case PNS::ITEM::SOLID_T: p = static_cast<PNS::SOLID*>( aItem )->Pos(); break;
636 default: return false;
637 }
638
639 const PNS::JOINT* jt = static_cast<const PNS::NODE*>( aItem->Owner() )->FindJoint( p, aItem );
640
641 assert( jt != nullptr );
642
643 int mval = INT_MAX;
644
645 PNS::ITEM_SET linkedSegs( jt->CLinks() );
647
648 for( PNS::ITEM* item : linkedSegs.Items() )
649 {
650 int w = tryGetTrackWidth( item );
651
652 if( w > 0 )
653 mval = std::min( w, mval );
654 }
655
656 if( mval == INT_MAX )
657 return false;
658
659 *aInheritedWidth = mval;
660 return true;
661}
662
663
665 PNS::NET_HANDLE aNet, VECTOR2D aStartPosition )
666{
667 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
668 PNS::CONSTRAINT constraint;
669
670 if( aStartItem && m_startLayer < 0 )
671 m_startLayer = aStartItem->Layer();
672
673 aSizes.SetClearance( bds.m_MinClearance );
674 aSizes.SetMinClearance( bds.m_MinClearance );
675 aSizes.SetClearanceSource( _( "board minimum clearance" ) );
676
677 int startAnchor = 0;
678 VECTOR2I startPosInt( aStartPosition.x, aStartPosition.y );
679
680 if( aStartItem && aStartItem->Kind() == PNS::ITEM::SEGMENT_T )
681 {
682 // Find the start anchor which is closest to the start mouse location
683 double anchor0Distance = startPosInt.Distance( aStartItem->Anchor( 0 ) );
684 double anchor1Distance = startPosInt.Distance( aStartItem->Anchor( 1 ) );
685
686 if( anchor1Distance < anchor0Distance )
687 startAnchor = 1;
688 }
689
690 if( aStartItem )
691 {
692 PNS::SEGMENT dummyTrack;
693 dummyTrack.SetEnds( aStartItem->Anchor( startAnchor ), aStartItem->Anchor( startAnchor ) );
694 dummyTrack.SetLayer( m_startLayer );
695 dummyTrack.SetNet( static_cast<NETINFO_ITEM*>( aStartItem->Net() ) );
696
697 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_CLEARANCE, &dummyTrack,
698 nullptr, m_startLayer, &constraint ) )
699 {
700 if( constraint.m_Value.Min() >= bds.m_MinClearance )
701 {
702 aSizes.SetClearance( constraint.m_Value.Min() );
703 aSizes.SetClearanceSource( constraint.m_RuleName );
704 }
705 }
706 }
707
708 int trackWidth = bds.m_TrackMinWidth;
709 bool found = false;
710 aSizes.SetWidthSource( _( "board minimum track width" ) );
711
712 if( bds.m_UseConnectedTrackWidth && !bds.m_TempOverrideTrackWidth && aStartItem != nullptr )
713 {
714 found = inheritTrackWidth( aStartItem, &trackWidth );
715
716 if( found )
717 aSizes.SetWidthSource( _( "existing track" ) );
718 }
719
720 if( !found && bds.UseNetClassTrack() && aStartItem )
721 {
722 PNS::SEGMENT dummyTrack;
723 dummyTrack.SetEnds( aStartItem->Anchor( startAnchor ), aStartItem->Anchor( startAnchor ) );
724 dummyTrack.SetLayer( m_startLayer );
725 dummyTrack.SetNet( static_cast<NETINFO_ITEM*>( aStartItem->Net() ) );
726
727 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_WIDTH, &dummyTrack, nullptr,
728 m_startLayer, &constraint ) )
729 {
730 trackWidth = std::max( trackWidth, constraint.m_Value.Opt() );
731 found = true;
732
733 if( trackWidth == constraint.m_Value.Opt() )
734 aSizes.SetWidthSource( constraint.m_RuleName );
735 }
736 }
737
738 if( !found )
739 {
740 trackWidth = std::max( trackWidth, bds.GetCurrentTrackWidth() );
741
742 if( bds.UseNetClassTrack() )
743 aSizes.SetWidthSource( _( "netclass 'Default'" ) );
744 else if( trackWidth == bds.GetCurrentTrackWidth() )
745 aSizes.SetWidthSource( _( "user choice" ) );
746 }
747
748 aSizes.SetTrackWidth( trackWidth );
751
752 int viaDiameter = bds.m_ViasMinSize;
753 int viaDrill = bds.m_MinThroughDrill;
754
755 PNS::VIA dummyVia, coupledVia;
756
757 if( aStartItem )
758 {
759 dummyVia.SetNet( aStartItem->Net() );
760 coupledVia.SetNet( m_ruleResolver->DpCoupledNet( aStartItem->Net() ) );
761 }
762
763 if( bds.UseNetClassVia() && aStartItem ) // netclass value
764 {
765 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_VIA_DIAMETER, &dummyVia,
766 nullptr, m_startLayer, &constraint ) )
767 {
768 viaDiameter = std::max( viaDiameter, constraint.m_Value.Opt() );
769 }
770
771 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_VIA_HOLE, &dummyVia,
772 nullptr, m_startLayer, &constraint ) )
773 {
774 viaDrill = std::max( viaDrill, constraint.m_Value.Opt() );
775 }
776 }
777 else
778 {
779 viaDiameter = bds.GetCurrentViaSize();
780 viaDrill = bds.GetCurrentViaDrill();
781 }
782
783 aSizes.SetViaDiameter( viaDiameter );
784 aSizes.SetViaDrill( viaDrill );
785
786 int diffPairWidth = bds.m_TrackMinWidth;
787 int diffPairGap = bds.m_MinClearance;
788 int diffPairViaGap = bds.m_MinClearance;
789
790 aSizes.SetDiffPairWidthSource( _( "board minimum track width" ) );
791 aSizes.SetDiffPairGapSource( _( "board minimum clearance" ) );
792
793 found = false;
794
795 // First try to pick up diff pair width from starting track, if enabled
796 if( bds.m_UseConnectedTrackWidth && aStartItem )
797 found = inheritTrackWidth( aStartItem, &diffPairWidth );
798
799 // Next, pick up gap from netclass, and width also if we didn't get a starting width above
800 if( bds.UseNetClassDiffPair() && aStartItem )
801 {
802 PNS::NET_HANDLE coupledNet = m_ruleResolver->DpCoupledNet( aStartItem->Net() );
803
804 PNS::SEGMENT dummyTrack;
805 dummyTrack.SetEnds( aStartItem->Anchor( 0 ), aStartItem->Anchor( 0 ) );
806 dummyTrack.SetLayer( m_startLayer );
807 dummyTrack.SetNet( static_cast<NETINFO_ITEM*>( aStartItem->Net() ) );
808
809 PNS::SEGMENT coupledTrack;
810 dummyTrack.SetEnds( aStartItem->Anchor( 0 ), aStartItem->Anchor( 0 ) );
811 dummyTrack.SetLayer( m_startLayer );
812 dummyTrack.SetNet( static_cast<NETINFO_ITEM*>( coupledNet ) );
813
814 if( !found
815 && m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_WIDTH, &dummyTrack,
816 &coupledTrack, m_startLayer, &constraint ) )
817 {
818 diffPairWidth = std::max( diffPairWidth, constraint.m_Value.Opt() );
819
820 if( diffPairWidth == constraint.m_Value.Opt() )
821 aSizes.SetDiffPairWidthSource( constraint.m_RuleName );
822 }
823
824 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_DIFF_PAIR_GAP, &dummyTrack,
825 &coupledTrack, m_startLayer, &constraint ) )
826 {
827 diffPairGap = std::max( diffPairGap, constraint.m_Value.Opt() );
828 diffPairViaGap = std::max( diffPairViaGap, constraint.m_Value.Opt() );
829
830 if( diffPairGap == constraint.m_Value.Opt() )
831 aSizes.SetDiffPairGapSource( constraint.m_RuleName );
832 }
833 }
834 else
835 {
836 diffPairWidth = bds.GetCurrentDiffPairWidth();
837 diffPairGap = bds.GetCurrentDiffPairGap();
838 diffPairViaGap = bds.GetCurrentDiffPairViaGap();
839
840 aSizes.SetDiffPairWidthSource( _( "user choice" ) );
841 aSizes.SetDiffPairGapSource( _( "user choice" ) );
842 }
843
844 aSizes.SetDiffPairWidth( diffPairWidth );
845 aSizes.SetDiffPairGap( diffPairGap );
846 aSizes.SetDiffPairViaGap( diffPairViaGap );
847 aSizes.SetDiffPairViaGapSameAsTraceGap( false );
848
849 int holeToHoleMin = bds.m_HoleToHoleMin;
850
851 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_HOLE_TO_HOLE, &dummyVia,
852 &dummyVia, UNDEFINED_LAYER, &constraint ) )
853 {
854 holeToHoleMin = constraint.m_Value.Min();
855 }
856
857 aSizes.SetHoleToHole( holeToHoleMin );
858
859 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_HOLE_TO_HOLE, &dummyVia,
860 &coupledVia, UNDEFINED_LAYER, &constraint ) )
861 {
862 holeToHoleMin = constraint.m_Value.Min();
863 }
864
865 aSizes.SetDiffPairHoleToHole( std::max( holeToHoleMin, aSizes.GetHoleToHole() ) );
866
867 return true;
868}
869
870
871int PNS_KICAD_IFACE_BASE::StackupHeight( int aFirstLayer, int aSecondLayer ) const
872{
873 if( !m_board || !m_board->GetDesignSettings().m_UseHeightForLengthCalcs )
874 return 0;
875
876 BOARD_STACKUP& stackup = m_board->GetDesignSettings().GetStackupDescriptor();
877
878 return stackup.GetLayerDistance( GetBoardLayerFromPNSLayer( aFirstLayer ),
879 GetBoardLayerFromPNSLayer( aSecondLayer ) );
880}
881
882
884{
885 return m_board->DpCoupledNet( static_cast<NETINFO_ITEM*>( aNet ) );
886}
887
888
890{
891 return m_routerIface->GetNetCode( aNet );
892}
893
894
896{
897 return m_routerIface->GetNetName( aNet );
898}
899
900
902{
903 wxString refName;
904
905 if( NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aNet ) )
906 refName = net->GetNetname();
907
908 wxString dummy1;
909
910 return m_board->MatchDpSuffix( refName, dummy1 );
911}
912
913
915 PNS::NET_HANDLE& aNetN )
916{
917 if( !aItem || !aItem->Net() )
918 return false;
919
920 wxString netNameP = static_cast<NETINFO_ITEM*>( aItem->Net() )->GetNetname();
921 wxString netNameN, netNameCoupled;
922
923 int r = m_board->MatchDpSuffix( netNameP, netNameCoupled );
924
925 if( r == 0 )
926 {
927 return false;
928 }
929 else if( r == 1 )
930 {
931 netNameN = netNameCoupled;
932 }
933 else
934 {
935 netNameN = netNameP;
936 netNameP = netNameCoupled;
937 }
938
939 PNS::NET_HANDLE netInfoP = m_board->FindNet( netNameP );
940 PNS::NET_HANDLE netInfoN = m_board->FindNet( netNameN );
941
942 if( !netInfoP || !netInfoN )
943 return false;
944
945 aNetP = netInfoP;
946 aNetN = netInfoN;
947
948 return true;
949}
950
951
953{
954public:
957 m_iface( aIface ),
958 m_view( nullptr ),
959 m_items( nullptr ),
960 m_depth( 0 )
961 {}
962
968
969 void SetView( KIGFX::VIEW* aView )
970 {
971 Clear();
972 delete m_items;
973 m_items = nullptr;
974 m_view = aView;
975
976 if( m_view == nullptr )
977 return;
978
979 if( m_view->GetGAL() )
980 m_depth = m_view->GetGAL()->GetMinDepth();
981
983 m_items->SetLayer( LAYER_SELECT_OVERLAY ) ;
984 m_view->Add( m_items );
985 }
986
987 void AddPoint( const VECTOR2I& aP, const KIGFX::COLOR4D& aColor, int aSize,
988 const wxString& aName = wxT( "" ),
989 const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override
990
991 {
993
994 sh.SetWidth( 10000 );
995
996 sh.Append( aP.x - aSize, aP.y - aSize );
997 sh.Append( aP.x + aSize, aP.y + aSize );
998 sh.Append( aP.x, aP.y );
999 sh.Append( aP.x - aSize, aP.y + aSize );
1000 sh.Append( aP.x + aSize, aP.y - aSize );
1001
1002 AddShape( &sh, aColor, sh.Width(), aName, aSrcLoc );
1003 }
1004
1005 void AddItem( const PNS::ITEM* aItem, const KIGFX::COLOR4D& aColor, int aOverrideWidth = 0,
1006 const wxString& aName = wxT( "" ),
1007 const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override
1008 {
1009 if( !m_view || !aItem )
1010 return;
1011
1012 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aItem, m_iface, m_view );
1013
1014 pitem->SetColor( aColor.WithAlpha( 0.5 ) );
1015 pitem->SetWidth( aOverrideWidth );
1016 pitem->SetDepth( nextDepth() );
1017
1018 m_items->Add( pitem );
1019 m_view->Update( m_items );
1020 }
1021
1022 void AddShape( const BOX2I& aBox, const KIGFX::COLOR4D& aColor, int aOverrideWidth = 0,
1023 const wxString& aName = wxT( "" ),
1024 const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override
1025 {
1027 l.SetWidth( aOverrideWidth );
1028
1029 VECTOR2I o = aBox.GetOrigin();
1030 VECTOR2I s = aBox.GetSize();
1031
1032 l.Append( o );
1033 l.Append( o.x + s.x, o.y );
1034 l.Append( o.x + s.x, o.y + s.y );
1035 l.Append( o.x, o.y + s.y );
1036 l.Append( o );
1037
1038 AddShape( &l, aColor, aOverrideWidth, aName, aSrcLoc );
1039 }
1040
1041 void AddShape( const SHAPE* aShape, const KIGFX::COLOR4D& aColor, int aOverrideWidth = 0,
1042 const wxString& aName = wxT( "" ),
1043 const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override
1044 {
1045 if( !m_view || !aShape )
1046 return;
1047
1048 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( *aShape, m_iface, m_view );
1049
1050 pitem->SetColor( aColor.WithAlpha( 0.5 ) );
1051 pitem->SetWidth( aOverrideWidth );
1052 pitem->SetDepth( nextDepth() );
1053
1054 m_items->Add( pitem );
1055 m_view->Update( m_items );
1056 }
1057
1058 void Clear() override
1059 {
1060 if( m_view && m_items )
1061 {
1062 m_items->FreeItems();
1063 m_view->Update( m_items );
1064
1065 if( m_view->GetGAL() )
1066 m_depth = m_view->GetGAL()->GetMinDepth();
1067 }
1068 }
1069
1070 virtual void Message( const wxString& msg,
1071 const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override
1072 {
1073 printf("PNS: %s\n", msg.c_str().AsChar() );
1074 }
1075
1076private:
1077 double nextDepth()
1078 {
1079 // Use different depths so that the transculent shapes won't overwrite each other.
1080
1081 m_depth++;
1082
1083 if( m_depth >= 0 && m_view->GetGAL() )
1084 m_depth = m_view->GetGAL()->GetMinDepth();
1085
1086 return m_depth;
1087 }
1088
1092
1093 double m_depth;
1094};
1095
1096
1101
1102
1104{
1105 m_ruleResolver = nullptr;
1106 m_board = nullptr;
1107 m_world = nullptr;
1108 m_debugDecorator = nullptr;
1109 m_startLayer = -1;
1110}
1111
1112
1114{
1115 m_tool = nullptr;
1116 m_view = nullptr;
1117 m_previewItems = nullptr;
1118 m_commitFlags = 0;
1119}
1120
1121
1127
1128
1130{
1131 if( m_previewItems )
1132 {
1133 m_previewItems->FreeItems();
1134 delete m_previewItems;
1135 }
1136}
1137
1138
1139std::vector<std::unique_ptr<PNS::SOLID>> PNS_KICAD_IFACE_BASE::syncPad( PAD* aPad )
1140{
1141 std::vector<std::unique_ptr<PNS::SOLID>> solids;
1142 PNS_LAYER_RANGE layers( 0, aPad->BoardCopperLayerCount() - 1 );
1143 LSEQ lmsk = aPad->GetLayerSet().CuStack();
1144
1145 // ignore non-copper pads except for those with holes
1146 if( lmsk.empty() && aPad->GetDrillSize().x == 0 )
1147 return solids;
1148
1149 switch( aPad->GetAttribute() )
1150 {
1151 case PAD_ATTRIB::PTH:
1152 case PAD_ATTRIB::NPTH:
1153 break;
1154
1155 case PAD_ATTRIB::CONN:
1156 case PAD_ATTRIB::SMD:
1157 {
1158 bool is_copper = false;
1159
1160 if( !lmsk.empty() && aPad->GetAttribute() != PAD_ATTRIB::NPTH )
1161 {
1162 layers = SetLayersFromPCBNew( lmsk.front(), lmsk.front() );
1163 is_copper = true;
1164 }
1165
1166 if( !is_copper )
1167 return solids;
1168
1169 break;
1170 }
1171
1172 default:
1173 wxLogTrace( wxT( "PNS" ), wxT( "unsupported pad type 0x%x" ), aPad->GetAttribute() );
1174 return solids;
1175 }
1176
1177 auto makeSolidFromPadLayer =
1178 [&]( PCB_LAYER_ID aLayer )
1179 {
1180 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
1181
1182 if( aPad->GetAttribute() == PAD_ATTRIB::NPTH )
1183 solid->SetRoutable( false );
1184
1185 if( aPad->Padstack().Mode() == PADSTACK::MODE::CUSTOM )
1186 {
1187 solid->SetLayer( GetPNSLayerFromBoardLayer( aLayer ) );
1188 }
1189 else if( aPad->Padstack().Mode() == PADSTACK::MODE::FRONT_INNER_BACK )
1190 {
1191 if( aLayer == F_Cu || aLayer == B_Cu )
1192 solid->SetLayer( GetPNSLayerFromBoardLayer( aLayer ) );
1193 else
1194 solid->SetLayers( PNS_LAYER_RANGE( 1, aPad->BoardCopperLayerCount() - 2 ) );
1195 }
1196 else
1197 {
1198 solid->SetLayers( layers );
1199 }
1200
1201 solid->SetNet( aPad->GetNet() );
1202 solid->SetParent( aPad );
1203 solid->SetPadToDie( aPad->GetPadToDieLength() );
1204 solid->SetPadToDieDelay( aPad->GetPadToDieDelay() );
1205 solid->SetOrientation( aPad->GetOrientation() );
1206
1207 if( aPad->IsFreePad() )
1208 solid->SetIsFreePad();
1209
1210 VECTOR2I wx_c = aPad->ShapePos( aLayer );
1211 VECTOR2I offset = aPad->GetOffset( aLayer );
1212
1213 VECTOR2I c( wx_c.x, wx_c.y );
1214
1215 RotatePoint( offset, aPad->GetOrientation() );
1216
1217 solid->SetPos( VECTOR2I( c.x - offset.x, c.y - offset.y ) );
1218 solid->SetOffset( VECTOR2I( offset.x, offset.y ) );
1219
1220 if( aPad->GetDrillSize().x > 0 )
1221 {
1222 solid->SetHole( new PNS::HOLE( aPad->GetEffectiveHoleShape()->Clone() ) );
1223 solid->Hole()->SetLayers( PNS_LAYER_RANGE( 0, aPad->BoardCopperLayerCount() - 1 ) );
1224 }
1225
1226 // We generate a single SOLID for a pad, so we have to treat it as ALWAYS_FLASHED and
1227 // then perform layer-specific flashing tests internally.
1228 const std::shared_ptr<SHAPE>& shape =
1230
1231 if( shape->HasIndexableSubshapes() && shape->GetIndexableSubshapeCount() == 1 )
1232 {
1233 std::vector<const SHAPE*> subshapes;
1234 shape->GetIndexableSubshapes( subshapes );
1235
1236 solid->SetShape( subshapes[0]->Clone() );
1237 }
1238 // For anything that's not a single shape we use a polygon. Multiple shapes have a tendency
1239 // to confuse the hull generator. https://gitlab.com/kicad/code/kicad/-/issues/15553
1240 else
1241 {
1242 const std::shared_ptr<SHAPE_POLY_SET>& poly =
1243 aPad->GetEffectivePolygon( aLayer, ERROR_OUTSIDE );
1244
1245 if( poly->OutlineCount() )
1246 solid->SetShape( new SHAPE_SIMPLE( poly->Outline( 0 ) ) );
1247 }
1248
1249 solids.emplace_back( std::move( solid ) );
1250 };
1251
1252 aPad->Padstack().ForEachUniqueLayer( makeSolidFromPadLayer );
1253
1254 return solids;
1255}
1256
1257
1258std::unique_ptr<PNS::SEGMENT> PNS_KICAD_IFACE_BASE::syncTrack( PCB_TRACK* aTrack )
1259{
1260 auto segment = std::make_unique<PNS::SEGMENT>( SEG( aTrack->GetStart(), aTrack->GetEnd() ),
1261 aTrack->GetNet() );
1262
1263 segment->SetWidth( aTrack->GetWidth() );
1264 segment->SetLayer( GetPNSLayerFromBoardLayer( aTrack->GetLayer() ) );
1265 segment->SetParent( aTrack );
1266
1267 if( aTrack->IsLocked() )
1268 segment->Mark( PNS::MK_LOCKED );
1269
1270 if( PCB_GENERATOR* generator = dynamic_cast<PCB_GENERATOR*>( aTrack->GetParentGroup() ) )
1271 {
1272 if( !generator->HasFlag( IN_EDIT ) )
1273 segment->Mark( PNS::MK_LOCKED );
1274 }
1275
1276 return segment;
1277}
1278
1279
1280std::unique_ptr<PNS::ARC> PNS_KICAD_IFACE_BASE::syncArc( PCB_ARC* aArc )
1281{
1282 auto arc = std::make_unique<PNS::ARC>( SHAPE_ARC( aArc->GetStart(), aArc->GetMid(),
1283 aArc->GetEnd(), aArc->GetWidth() ),
1284 aArc->GetNet() );
1285
1286 arc->SetLayer( GetPNSLayerFromBoardLayer( aArc->GetLayer() ) );
1287 arc->SetParent( aArc );
1288
1289 if( aArc->IsLocked() )
1290 arc->Mark( PNS::MK_LOCKED );
1291
1292 if( PCB_GENERATOR* generator = dynamic_cast<PCB_GENERATOR*>( aArc->GetParentGroup() ) )
1293 {
1294 if( !generator->HasFlag( IN_EDIT ) )
1295 arc->Mark( PNS::MK_LOCKED );
1296 }
1297
1298 return arc;
1299}
1300
1301
1302std::unique_ptr<PNS::VIA> PNS_KICAD_IFACE_BASE::syncVia( PCB_VIA* aVia )
1303{
1304 PCB_LAYER_ID top, bottom;
1305 aVia->LayerPair( &top, &bottom );
1306
1307 /*
1308 * NOTE about PNS via padstacks:
1309 *
1310 * PNS::VIA has no knowledge about how many layers are in the board, and there is no fixed
1311 * reference to the "back layer" in the PNS. That means that there is no way for a VIA to know
1312 * the difference between its bottom layer and the bottom layer of the overall board (i.e. if
1313 * the via is a blind/buried via). For this reason, PNS::VIA::STACK_MODE::FRONT_INNER_BACK
1314 * cannot be used for blind/buried vias. This mode will always assume that the via's top layer
1315 * is the "front" layer and the via's bottom layer is the "back" layer, but from KiCad's point
1316 * of view, at least at the moment, front/inner/back padstack mode is board-scoped, not
1317 * via-scoped, so a buried via would only use the inner layer size even if its padstack mode is
1318 * set to PADSTACK::MODE::FRONT_INNER_BACK and different sizes are defined for front or back.
1319 * For this kind of via, the PNS VIA stack mode will be set to NORMAL because effectively it has
1320 * the same size on every layer it exists on.
1321 */
1322
1323 auto via = std::make_unique<PNS::VIA>( aVia->GetPosition(),
1324 SetLayersFromPCBNew( aVia->TopLayer(), aVia->BottomLayer() ),
1325 0,
1326 aVia->GetDrillValue(),
1327 aVia->GetNet(),
1328 aVia->GetViaType() );
1329 via->SetUnconnectedLayerMode( aVia->Padstack().UnconnectedLayerMode() );
1330
1331 auto syncDiameter =
1332 [&]( PCB_LAYER_ID aLayer )
1333 {
1334 via->SetDiameter( GetPNSLayerFromBoardLayer( aLayer ), aVia->GetWidth( aLayer ) );
1335 };
1336
1337 switch( aVia->Padstack().Mode() )
1338 {
1340 via->SetDiameter( 0, aVia->GetWidth( PADSTACK::ALL_LAYERS ) );
1341 break;
1342
1344 if( aVia->GetViaType() == VIATYPE::BLIND_BURIED )
1345 {
1346 via->SetDiameter( 0, aVia->GetWidth( PADSTACK::INNER_LAYERS ) );
1347 }
1348 else
1349 {
1351 aVia->Padstack().ForEachUniqueLayer( syncDiameter );
1352 }
1353
1354 break;
1355
1357 via->SetStackMode( PNS::VIA::STACK_MODE::CUSTOM );
1358 aVia->Padstack().ForEachUniqueLayer( syncDiameter );
1359 }
1360
1361 via->SetParent( aVia );
1362
1363 if( aVia->IsLocked() )
1364 via->Mark( PNS::MK_LOCKED );
1365
1366 if( PCB_GENERATOR* generator = dynamic_cast<PCB_GENERATOR*>( aVia->GetParentGroup() ) )
1367 {
1368 if( !generator->HasFlag( IN_EDIT ) )
1369 via->Mark( PNS::MK_LOCKED );
1370 }
1371
1372 via->SetIsFree( aVia->GetIsFree() );
1373 via->SetHole( PNS::HOLE::MakeCircularHole( aVia->GetPosition(),
1374 aVia->GetDrillValue() / 2,
1375 SetLayersFromPCBNew( aVia->TopLayer(), aVia->BottomLayer() ) ) );
1376
1377 return via;
1378}
1379
1380
1381bool PNS_KICAD_IFACE_BASE::syncZone( PNS::NODE* aWorld, ZONE* aZone, SHAPE_POLY_SET* aBoardOutline )
1382{
1383 static wxString msg;
1384 SHAPE_POLY_SET* poly;
1385
1386 if( !aZone->GetIsRuleArea() || !aZone->HasKeepoutParametersSet() )
1387 return false;
1388
1389 LSET layers = aZone->GetLayerSet();
1390
1391 poly = aZone->Outline();
1392 poly->CacheTriangulation( false );
1393
1394 if( !poly->IsTriangulationUpToDate() )
1395 {
1396 UNITS_PROVIDER unitsProvider( pcbIUScale, GetUnits() );
1397 msg.Printf( _( "%s is malformed." ), aZone->GetItemDescription( &unitsProvider, true ) );
1398
1399 KIDIALOG dlg( nullptr, msg, KIDIALOG::KD_WARNING );
1400 dlg.ShowDetailedText( _( "This zone cannot be handled by the router.\n"
1401 "Please verify it is not a self-intersecting polygon." ) );
1402 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
1403 dlg.ShowModal();
1404
1405 return false;
1406 }
1407
1408 for( PCB_LAYER_ID layer : LAYER_RANGE( F_Cu, B_Cu, m_board->GetCopperLayerCount() ) )
1409 {
1410 if( !layers[ layer ] )
1411 continue;
1412
1413 for( int polyId = 0; polyId < poly->TriangulatedPolyCount(); polyId++ )
1414 {
1415 const SHAPE_POLY_SET::TRIANGULATED_POLYGON* tri = poly->TriangulatedPolygon( polyId );
1416
1417 for( size_t i = 0; i < tri->GetTriangleCount(); i++)
1418 {
1419 VECTOR2I a, b, c;
1420 tri->GetTriangle( i, a, b, c );
1421 SHAPE_SIMPLE* triShape = new SHAPE_SIMPLE;
1422
1423 triShape->Append( a );
1424 triShape->Append( b );
1425 triShape->Append( c );
1426
1427 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
1428
1429 solid->SetLayer( GetPNSLayerFromBoardLayer( layer ) );
1430 solid->SetNet( nullptr );
1431 solid->SetParent( aZone );
1432 solid->SetShape( triShape );
1433 solid->SetIsCompoundShapePrimitive();
1434 solid->SetRoutable( false );
1435
1436 aWorld->Add( std::move( solid ) );
1437 }
1438 }
1439 }
1440
1441 return true;
1442}
1443
1444
1446{
1447 if( !IsKicadCopperLayer( aLayer ) )
1448 return false;
1449
1450 if( aItem->Type() == PCB_FIELD_T && !static_cast<PCB_FIELD*>( aItem )->IsVisible() )
1451 return false;
1452
1453 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
1454 SHAPE_SIMPLE* shape = new SHAPE_SIMPLE;
1455
1456 solid->SetLayer( GetPNSLayerFromBoardLayer( aLayer ) );
1457 solid->SetNet( nullptr );
1458 solid->SetParent( aItem );
1459 solid->SetShape( shape ); // takes ownership
1460 solid->SetRoutable( false );
1461
1462 SHAPE_POLY_SET cornerBuffer;
1463
1464 aItem->TransformShapeToPolygon( cornerBuffer, aItem->GetLayer(), 0, aItem->GetMaxError(), ERROR_OUTSIDE );
1465
1466 cornerBuffer.Simplify();
1467
1468 if( !cornerBuffer.OutlineCount() )
1469 return false;
1470
1471 for( const VECTOR2I& pt : cornerBuffer.Outline( 0 ).CPoints() )
1472 shape->Append( pt );
1473
1474 aWorld->Add( std::move( solid ) );
1475
1476 return true;
1477}
1478
1479
1481{
1482 if( aItem->GetLayer() == Edge_Cuts
1483 || aItem->GetLayer() == Margin
1484 || IsKicadCopperLayer( aItem->GetLayer() ) )
1485 {
1486 std::vector<SHAPE*> shapes = aItem->MakeEffectiveShapes();
1487
1488 for( SHAPE* shape : shapes )
1489 {
1490 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
1491
1492 if( aItem->GetLayer() == Edge_Cuts || aItem->GetLayer() == Margin )
1493 {
1494 solid->SetLayers( PNS_LAYER_RANGE( 0, m_board->GetCopperLayerCount() - 1 ) );
1495 solid->SetRoutable( false );
1496 }
1497 else
1498 {
1499 solid->SetLayer( GetPNSLayerFromBoardLayer( aItem->GetLayer() ) );
1500 solid->SetRoutable( aItem->Type() != PCB_TABLECELL_T );
1501 }
1502
1503 if( aItem->GetLayer() == Edge_Cuts )
1504 {
1505 switch( shape->Type() )
1506 {
1507 case SH_SEGMENT: static_cast<SHAPE_SEGMENT*>( shape )->SetWidth( 0 ); break;
1508 case SH_ARC: static_cast<SHAPE_ARC*>( shape )->SetWidth( 0 ); break;
1509 case SH_LINE_CHAIN: static_cast<SHAPE_LINE_CHAIN*>( shape )->SetWidth( 0 ); break;
1510 default: /* remaining shapes don't have width */ break;
1511 }
1512 }
1513
1514 solid->SetAnchorPoints( aItem->GetConnectionPoints() );
1515 solid->SetNet( aItem->GetNet() );
1516 solid->SetParent( aItem );
1517 solid->SetShape( shape ); // takes ownership
1518
1519 if( shapes.size() > 1 )
1520 solid->SetIsCompoundShapePrimitive();
1521
1522 aWorld->Add( std::move( solid ) );
1523 }
1524
1525 return true;
1526 }
1527
1528 return false;
1529}
1530
1531
1533{
1534 m_board = aBoard;
1535 wxLogTrace( wxT( "PNS" ), wxT( "m_board = %p" ), m_board );
1536}
1537
1538
1540{
1541 return ::IsCopperLayer( GetBoardLayerFromPNSLayer( aPNSLayer ) );
1542}
1543
1544
1545
1547{
1548 return ::IsCopperLayer( aKicadLayer );
1549}
1550
1551
1553{
1554 if( !m_view )
1555 return false;
1556
1557 for( int i = aLayer.Start(); i <= aLayer.End(); i++ )
1558 {
1559 if( m_view->IsLayerVisible( GetBoardLayerFromPNSLayer( i ) ) )
1560 return true;
1561 }
1562
1563 return false;
1564}
1565
1566
1567bool PNS_KICAD_IFACE_BASE::IsFlashedOnLayer( const PNS::ITEM* aItem, int aLayer ) const
1568{
1570 if( aLayer < 0 )
1571 return true;
1572
1573 if( aItem->Parent() )
1574 {
1575 switch( aItem->Parent()->Type() )
1576 {
1577 case PCB_VIA_T:
1578 {
1579 const PCB_VIA* via = static_cast<const PCB_VIA*>( aItem->Parent() );
1580
1581 return via->FlashLayer( GetBoardLayerFromPNSLayer( aLayer ) );
1582 }
1583
1584 case PCB_PAD_T:
1585 {
1586 const PAD* pad = static_cast<const PAD*>( aItem->Parent() );
1587
1588 return pad->FlashLayer( GetBoardLayerFromPNSLayer( aLayer ) );
1589 }
1590
1591 default:
1592 break;
1593 }
1594 }
1595
1596 if( aItem->OfKind( PNS::ITEM::VIA_T ) )
1597 return static_cast<const PNS::VIA*>( aItem )->ConnectsLayer( aLayer );
1598
1599 return aItem->Layers().Overlaps( aLayer );
1600}
1601
1602
1604 const PNS_LAYER_RANGE& aLayer ) const
1605{
1606 PNS_LAYER_RANGE test = aItem->Layers().Intersection( aLayer );
1607
1608 if( aItem->Parent() )
1609 {
1610 switch( aItem->Parent()->Type() )
1611 {
1612 case PCB_VIA_T:
1613 {
1614 const PCB_VIA* via = static_cast<const PCB_VIA*>( aItem->Parent() );
1615
1616 for( int layer = test.Start(); layer <= test.End(); ++layer )
1617 {
1618 if( via->FlashLayer( GetBoardLayerFromPNSLayer( layer ) ) )
1619 return true;
1620 }
1621
1622 return false;
1623 }
1624
1625 case PCB_PAD_T:
1626 {
1627 const PAD* pad = static_cast<const PAD*>( aItem->Parent() );
1628
1629 for( int layer = test.Start(); layer <= test.End(); ++layer )
1630 {
1631 if( pad->FlashLayer( GetBoardLayerFromPNSLayer( layer ) ) )
1632 return true;
1633 }
1634
1635 return false;
1636 }
1637
1638 default:
1639 break;
1640 }
1641 }
1642
1643 if( aItem->OfKind( PNS::ITEM::VIA_T ) )
1644 {
1645 const PNS::VIA* via = static_cast<const PNS::VIA*>( aItem );
1646
1647 for( int layer = test.Start(); layer <= test.End(); ++layer )
1648 {
1649 if( via->ConnectsLayer( layer ) )
1650 return true;
1651 }
1652
1653 return false;
1654 }
1655
1656 return test.Start() <= test.End();
1657}
1658
1659
1661{
1662 // by default, all items are visible (new ones created by the router have parent == NULL
1663 // as they have not been committed yet to the BOARD)
1664 if( !m_view || !aItem->Parent() )
1665 return true;
1666
1667 BOARD_ITEM* item = aItem->Parent();
1668 bool isOnVisibleLayer = true;
1669 RENDER_SETTINGS* settings = m_view->GetPainter()->GetSettings();
1670
1671 if( settings->GetHighContrast() )
1672 isOnVisibleLayer = item->IsOnLayer( settings->GetPrimaryHighContrastLayer() );
1673
1674 if( m_view->IsVisible( item ) && isOnVisibleLayer )
1675 {
1676 for( PCB_LAYER_ID layer : item->GetLayerSet() )
1677 {
1678 if( item->ViewGetLOD( layer, m_view ) < m_view->GetScale() )
1679 return true;
1680 }
1681 }
1682
1683 // Items hidden in the router are not hidden on the board
1684 if( m_hiddenItems.find( item ) != m_hiddenItems.end() )
1685 return true;
1686
1687 return false;
1688}
1689
1690
1692{
1693 if( !m_board )
1694 {
1695 wxLogTrace( wxT( "PNS" ), wxT( "No board attached, aborting sync." ) );
1696 return;
1697 }
1698
1699 int worstClearance = m_board->GetMaxClearanceValue();
1700
1701 m_world = aWorld;
1702
1703 for( BOARD_ITEM* gitem : m_board->Drawings() )
1704 {
1705 if ( gitem->Type() == PCB_SHAPE_T || gitem->Type() == PCB_TEXTBOX_T )
1706 {
1707 syncGraphicalItem( aWorld, static_cast<PCB_SHAPE*>( gitem ) );
1708 }
1709 else if( gitem->Type() == PCB_TEXT_T )
1710 {
1711 syncTextItem( aWorld, static_cast<PCB_TEXT*>( gitem ), gitem->GetLayer() );
1712 }
1713 else if( gitem->Type() == PCB_TABLE_T )
1714 {
1715 syncTextItem( aWorld, static_cast<PCB_TABLE*>( gitem ), gitem->GetLayer() );
1716 }
1717 }
1718
1719 SHAPE_POLY_SET buffer;
1720 SHAPE_POLY_SET* boardOutline = nullptr;
1721
1722 if( m_board->GetBoardPolygonOutlines( buffer ) )
1723 boardOutline = &buffer;
1724
1725 for( ZONE* zone : m_board->Zones() )
1726 {
1727 syncZone( aWorld, zone, boardOutline );
1728 }
1729
1730 for( FOOTPRINT* footprint : m_board->Footprints() )
1731 {
1732 for( PAD* pad : footprint->Pads() )
1733 {
1734 std::vector<std::unique_ptr<PNS::SOLID>> solids = syncPad( pad );
1735
1736 for( std::unique_ptr<PNS::SOLID>& solid : solids )
1737 aWorld->Add( std::move( solid ) );
1738
1739 std::optional<int> clearanceOverride = pad->GetClearanceOverrides( nullptr );
1740
1741 if( clearanceOverride.has_value() )
1742 worstClearance = std::max( worstClearance, clearanceOverride.value() );
1743
1744 if( pad->GetProperty() == PAD_PROP::CASTELLATED )
1745 {
1746 std::unique_ptr<SHAPE> hole;
1747 hole.reset( pad->GetEffectiveHoleShape()->Clone() );
1748 aWorld->AddEdgeExclusion( std::move( hole ) );
1749 }
1750 }
1751
1752 syncTextItem( aWorld, &footprint->Reference(), footprint->Reference().GetLayer() );
1753 syncTextItem( aWorld, &footprint->Value(), footprint->Value().GetLayer() );
1754
1755 for( ZONE* zone : footprint->Zones() )
1756 syncZone( aWorld, zone, boardOutline );
1757
1758 for( PCB_FIELD* field : footprint->GetFields() )
1759 syncTextItem( aWorld, static_cast<PCB_TEXT*>( field ), field->GetLayer() );
1760
1761 for( BOARD_ITEM* item : footprint->GraphicalItems() )
1762 {
1763 if( item->Type() == PCB_SHAPE_T || item->Type() == PCB_TEXTBOX_T )
1764 {
1765 syncGraphicalItem( aWorld, static_cast<PCB_SHAPE*>( item ) );
1766 }
1767 else if( item->Type() == PCB_TEXT_T )
1768 {
1769 syncTextItem( aWorld, static_cast<PCB_TEXT*>( item ), item->GetLayer() );
1770 }
1771 else if( item->Type() == PCB_TABLE_T )
1772 {
1773 syncTextItem( aWorld, static_cast<PCB_TABLE*>( item ), item->GetLayer() );
1774 }
1775 }
1776 }
1777
1778 for( PCB_TRACK* t : m_board->Tracks() )
1779 {
1780 KICAD_T type = t->Type();
1781
1782 if( type == PCB_TRACE_T )
1783 {
1784 if( std::unique_ptr<PNS::SEGMENT> segment = syncTrack( t ) )
1785 aWorld->Add( std::move( segment ), true );
1786 }
1787 else if( type == PCB_ARC_T )
1788 {
1789 if( std::unique_ptr<PNS::ARC> arc = syncArc( static_cast<PCB_ARC*>( t ) ) )
1790 aWorld->Add( std::move( arc ), true );
1791 }
1792 else if( type == PCB_VIA_T )
1793 {
1794 if( std::unique_ptr<PNS::VIA> via = syncVia( static_cast<PCB_VIA*>( t ) ) )
1795 aWorld->Add( std::move( via ) );
1796 }
1797 }
1798
1799 // NB: if this were ever to become a long-lived object we would need to dirty its
1800 // clearance cache here....
1801 delete m_ruleResolver;
1803
1805 aWorld->SetMaxClearance( worstClearance + m_ruleResolver->ClearanceEpsilon() );
1806}
1807
1808
1810{
1811 for( BOARD_ITEM* item : m_hiddenItems )
1812 m_view->SetVisible( item, true );
1813
1814 m_hiddenItems.clear();
1815
1816 if( m_previewItems )
1817 {
1818 m_previewItems->FreeItems();
1819 m_view->Update( m_previewItems );
1820 }
1821
1822 if( m_debugDecorator )
1823 m_debugDecorator->Clear();
1824}
1825
1826
1831
1832
1833void PNS_KICAD_IFACE::DisplayItem( const PNS::ITEM* aItem, int aClearance, bool aEdit, int aFlags )
1834{
1835 if( aItem->IsVirtual() )
1836 return;
1837
1838 if( ZONE* zone = dynamic_cast<ZONE*>( aItem->Parent() ) )
1839 {
1840 if( zone->GetIsRuleArea() )
1841 aFlags |= PNS_SEMI_SOLID;
1842 }
1843
1844 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aItem, this, m_view, aFlags );
1845
1846 // Note: SEGMENT_T is used for placed tracks; LINE_T is used for the routing head
1848 static int tracksOrVias = tracks | PNS::ITEM::VIA_T;
1849
1850 if( aClearance >= 0 )
1851 {
1852 pitem->SetClearance( aClearance );
1853
1854 auto* settings = static_cast<PCBNEW_SETTINGS*>( m_tool->GetManager()->GetSettings() );
1855
1856 switch( settings->m_Display.m_TrackClearance )
1857 {
1860 pitem->ShowClearance( aItem->OfKind( tracksOrVias ) );
1861 break;
1862
1864 pitem->ShowClearance( aItem->OfKind( tracksOrVias ) && !aEdit );
1865 break;
1866
1867 case SHOW_WHILE_ROUTING:
1868 pitem->ShowClearance( aItem->OfKind( tracks ) && !aEdit );
1869 break;
1870
1871 default:
1872 pitem->ShowClearance( false );
1873 break;
1874 }
1875 }
1876
1877 m_previewItems->Add( pitem );
1878 m_view->Update( m_previewItems );
1879}
1880
1881
1882void PNS_KICAD_IFACE::DisplayPathLine( const SHAPE_LINE_CHAIN& aLine, int aImportance )
1883{
1884 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aLine, this, m_view );
1886
1887 COLOR4D color;
1888
1889 if( aImportance >= 1 )
1890 color = COLOR4D( 1.0, 1.0, 0.0, 0.6 );
1891 else if( aImportance == 0 )
1892 color = COLOR4D( 0.7, 0.7, 0.7, 0.6 );
1893
1894 pitem->SetColor( color );
1895
1896 m_previewItems->Add( pitem );
1897 m_view->Update( m_previewItems );
1898}
1899
1900
1902{
1903 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aRatline, this, m_view );
1904
1905 KIGFX::RENDER_SETTINGS* renderSettings = m_view->GetPainter()->GetSettings();
1906 KIGFX::PCB_RENDER_SETTINGS* rs = static_cast<KIGFX::PCB_RENDER_SETTINGS*>( renderSettings );
1907 bool colorByNet = rs->GetNetColorMode() != NET_COLOR_MODE::OFF;
1908 COLOR4D defaultColor = rs->GetColor( nullptr, LAYER_RATSNEST );
1909 COLOR4D color = defaultColor;
1910
1911 std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_board->GetConnectivity();
1912 std::set<int> highlightedNets = rs->GetHighlightNetCodes();
1913 std::map<int, KIGFX::COLOR4D>& netColors = rs->GetNetColorMap();
1914 int netCode = -1;
1915
1916 if( NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aNet ) )
1917 netCode = net->GetNetCode();
1918
1919 const NETCLASS* nc = nullptr;
1920 const NET_SETTINGS* netSettings = connectivity->GetNetSettings();
1921
1922 if( connectivity->HasNetNameForNetCode( netCode ) )
1923 {
1924 const wxString& netName = connectivity->GetNetNameForNetCode( netCode );
1925
1926 if( netSettings && netSettings->HasEffectiveNetClass( netName ) )
1927 nc = netSettings->GetCachedEffectiveNetClass( netName ).get();
1928 }
1929
1930 if( colorByNet && netColors.count( netCode ) )
1931 color = netColors.at( netCode );
1932 else if( colorByNet && nc && nc->HasPcbColor() )
1933 color = nc->GetPcbColor();
1934 else
1935 color = defaultColor;
1936
1938 color = defaultColor;
1939
1940 pitem->SetColor( color.Brightened( 0.5 ).WithAlpha( std::min( 1.0, color.a + 0.4 ) ) );
1941
1942 m_previewItems->Add( pitem );
1943 m_view->Update( m_previewItems );
1944}
1945
1946
1948{
1949 BOARD_ITEM* parent = aItem->Parent();
1950
1951 if( parent )
1952 {
1953 if( m_view->IsVisible( parent ) )
1954 m_hiddenItems.insert( parent );
1955
1956 m_view->SetVisible( parent, false );
1957 m_view->Update( parent, KIGFX::APPEARANCE );
1958
1959 for( ZONE* td : m_board->Zones() )
1960 {
1961 if( td->IsTeardropArea()
1962 && td->GetBoundingBox().Intersects( aItem->Parent()->GetBoundingBox() )
1963 && td->Outline()->Collide( aItem->Shape( td->GetLayer() ) ) )
1964 {
1965 m_view->SetVisible( td, false );
1966 m_view->Update( td, KIGFX::APPEARANCE );
1967 }
1968 }
1969 }
1970}
1971
1972
1976
1977
1979{
1980 BOARD_ITEM* parent = aItem->Parent();
1981
1982 if( aItem->OfKind( PNS::ITEM::SOLID_T ) && parent->Type() == PCB_PAD_T )
1983 {
1984 PAD* pad = static_cast<PAD*>( parent );
1985 VECTOR2I pos = static_cast<PNS::SOLID*>( aItem )->Pos();
1986
1987 m_fpOffsets[ pad ].p_old = pos;
1988 return;
1989 }
1990
1991 if( parent )
1992 {
1993 if( EDA_GROUP* group = parent->GetParentGroup() )
1994 m_itemGroups[parent] = group;
1995
1996 m_commit->Remove( parent );
1997 }
1998}
1999
2000
2004
2005
2007{
2008 BOARD_ITEM* board_item = aItem->Parent();
2009
2010 switch( aItem->Kind() )
2011 {
2012 case PNS::ITEM::ARC_T:
2013 {
2014 PNS::ARC* arc = static_cast<PNS::ARC*>( aItem );
2015 PCB_ARC* arc_board = static_cast<PCB_ARC*>( board_item );
2016 const SHAPE_ARC* arc_shape = static_cast<const SHAPE_ARC*>( arc->Shape( -1 ) );
2017
2018 m_commit->Modify( arc_board );
2019
2020 arc_board->SetStart( VECTOR2I( arc_shape->GetP0() ) );
2021 arc_board->SetEnd( VECTOR2I( arc_shape->GetP1() ) );
2022 arc_board->SetMid( VECTOR2I( arc_shape->GetArcMid() ) );
2023 arc_board->SetWidth( arc->Width() );
2024 break;
2025 }
2026
2028 {
2029 PNS::SEGMENT* seg = static_cast<PNS::SEGMENT*>( aItem );
2030 PCB_TRACK* track = static_cast<PCB_TRACK*>( board_item );
2031 const SEG& s = seg->Seg();
2032
2033 m_commit->Modify( track );
2034
2035 track->SetStart( VECTOR2I( s.A.x, s.A.y ) );
2036 track->SetEnd( VECTOR2I( s.B.x, s.B.y ) );
2037 track->SetWidth( seg->Width() );
2038 break;
2039 }
2040
2041 case PNS::ITEM::VIA_T:
2042 {
2043 PCB_VIA* via_board = static_cast<PCB_VIA*>( board_item );
2044 PNS::VIA* via = static_cast<PNS::VIA*>( aItem );
2045
2046 m_commit->Modify( via_board );
2047
2048 via_board->SetPosition( VECTOR2I( via->Pos().x, via->Pos().y ) );
2049 via_board->SetWidth( PADSTACK::ALL_LAYERS, via->Diameter( 0 ) );
2050 via_board->SetDrill( via->Drill() );
2051 via_board->SetNet( static_cast<NETINFO_ITEM*>( via->Net() ) );
2052 via_board->SetViaType( via->ViaType() ); // MUST be before SetLayerPair()
2053 via_board->Padstack().SetUnconnectedLayerMode( via->UnconnectedLayerMode() );
2054 via_board->SetIsFree( via->IsFree() );
2055 via_board->SetLayerPair( GetBoardLayerFromPNSLayer( via->Layers().Start() ),
2056 GetBoardLayerFromPNSLayer( via->Layers().End() ) );
2057 break;
2058 }
2059
2060 case PNS::ITEM::SOLID_T:
2061 {
2062 if( aItem->Parent()->Type() == PCB_PAD_T )
2063 {
2064 PAD* pad = static_cast<PAD*>( aItem->Parent() );
2065 VECTOR2I pos = static_cast<PNS::SOLID*>( aItem )->Pos();
2066
2067 // Don't add to commit; we'll add the parent footprints when processing the m_fpOffsets
2068
2069 m_fpOffsets[pad].p_old = pad->GetPosition();
2070 m_fpOffsets[pad].p_new = pos;
2071 }
2072 break;
2073 }
2074
2075 default:
2076 m_commit->Modify( aItem->Parent() );
2077 break;
2078 }
2079}
2080
2081
2083{
2084 modifyBoardItem( aItem );
2085}
2086
2087
2089{
2090}
2091
2092
2094{
2095 BOARD_CONNECTED_ITEM* newBoardItem = nullptr;
2096 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aItem->Net() );
2097
2098 if( !net )
2100
2101 switch( aItem->Kind() )
2102 {
2103 case PNS::ITEM::ARC_T:
2104 {
2105 PNS::ARC* arc = static_cast<PNS::ARC*>( aItem );
2106 PCB_ARC* new_arc = new PCB_ARC( m_board, static_cast<const SHAPE_ARC*>( arc->Shape( -1 ) ) );
2107 new_arc->SetWidth( arc->Width() );
2108 new_arc->SetLayer( GetBoardLayerFromPNSLayer( arc->Layers().Start() ) );
2109 new_arc->SetNet( net );
2110
2111 if( aItem->GetSourceItem() && aItem->GetSourceItem()->IsType( { PCB_TRACE_T, PCB_ARC_T } ) )
2112 {
2113 PCB_TRACK* sourceTrack = static_cast<PCB_TRACK*>( aItem->GetSourceItem() );
2114 new_arc->SetHasSolderMask( sourceTrack->HasSolderMask() );
2115 new_arc->SetLocalSolderMaskMargin( sourceTrack->GetLocalSolderMaskMargin() );
2116 }
2117
2118 newBoardItem = new_arc;
2119 break;
2120 }
2121
2123 {
2124 PNS::SEGMENT* seg = static_cast<PNS::SEGMENT*>( aItem );
2125 PCB_TRACK* track = new PCB_TRACK( m_board );
2126 const SEG& s = seg->Seg();
2127 track->SetStart( VECTOR2I( s.A.x, s.A.y ) );
2128 track->SetEnd( VECTOR2I( s.B.x, s.B.y ) );
2129 track->SetWidth( seg->Width() );
2130 track->SetLayer( GetBoardLayerFromPNSLayer( seg->Layers().Start() ) );
2131 track->SetNet( net );
2132
2133 if( aItem->GetSourceItem() && aItem->GetSourceItem()->IsType( { PCB_TRACE_T, PCB_ARC_T } ) )
2134 {
2135 PCB_TRACK* sourceTrack = static_cast<PCB_TRACK*>( aItem->GetSourceItem() );
2136 track->SetHasSolderMask( sourceTrack->HasSolderMask() );
2137 track->SetLocalSolderMaskMargin( sourceTrack->GetLocalSolderMaskMargin() );
2138 }
2139
2140 newBoardItem = track;
2141 break;
2142 }
2143
2144 case PNS::ITEM::VIA_T:
2145 {
2146 PCB_VIA* via_board = new PCB_VIA( m_board );
2147 PNS::VIA* via = static_cast<PNS::VIA*>( aItem );
2148 via_board->SetPosition( VECTOR2I( via->Pos().x, via->Pos().y ) );
2149 via_board->SetWidth( PADSTACK::ALL_LAYERS, via->Diameter( 0 ) );
2150 via_board->SetDrill( via->Drill() );
2151 via_board->SetNet( net );
2152 via_board->SetViaType( via->ViaType() ); // MUST be before SetLayerPair()
2153 via_board->Padstack().SetUnconnectedLayerMode( via->UnconnectedLayerMode() );
2154 via_board->SetIsFree( via->IsFree() );
2155 via_board->SetLayerPair( GetBoardLayerFromPNSLayer( via->Layers().Start() ),
2156 GetBoardLayerFromPNSLayer( via->Layers().End() ) );
2157
2158 if( aItem->GetSourceItem() && aItem->GetSourceItem()->Type() == PCB_VIA_T )
2159 {
2160 PCB_VIA* sourceVia = static_cast<PCB_VIA*>( aItem->GetSourceItem() );
2161 via_board->SetFrontTentingMode( sourceVia->GetFrontTentingMode() );
2162 via_board->SetBackTentingMode( sourceVia->GetBackTentingMode() );
2163 }
2164
2165 newBoardItem = via_board;
2166 break;
2167 }
2168
2169 case PNS::ITEM::SOLID_T:
2170 {
2171 PAD* pad = static_cast<PAD*>( aItem->Parent() );
2172 VECTOR2I pos = static_cast<PNS::SOLID*>( aItem )->Pos();
2173
2174 m_fpOffsets[pad].p_new = pos;
2175 return nullptr;
2176 }
2177
2178 default:
2179 return nullptr;
2180 }
2181
2182 if( net->GetNetCode() <= 0 )
2183 {
2184 NETINFO_ITEM* newNetInfo = newBoardItem->GetNet();
2185
2186 newNetInfo->SetParent( m_board );
2187 newNetInfo->SetNetClass( m_board->GetDesignSettings().m_NetSettings->GetDefaultNetclass() );
2188 }
2189
2190 if( newBoardItem )
2191 {
2192 if( BOARD_ITEM* src = aItem->GetSourceItem() )
2193 {
2194 if( m_itemGroups.contains( src ) )
2195 m_replacementMap[src].push_back( newBoardItem );
2196 }
2197 }
2198
2199 return newBoardItem;
2200}
2201
2202
2204{
2205 BOARD_CONNECTED_ITEM* boardItem = createBoardItem( aItem );
2206
2207 if( boardItem )
2208 {
2209 aItem->SetParent( boardItem );
2210 boardItem->ClearFlags();
2211
2212 m_commit->Add( boardItem );
2213 }
2214}
2215
2216
2218{
2219 std::set<FOOTPRINT*> processedFootprints;
2220
2221 EraseView();
2222
2223 for( const auto& [ pad, fpOffset ] : m_fpOffsets )
2224 {
2225 VECTOR2I offset = fpOffset.p_new - fpOffset.p_old;
2226 FOOTPRINT* footprint = pad->GetParentFootprint();
2227 VECTOR2I p_orig = footprint->GetPosition();
2228 VECTOR2I p_new = p_orig + offset;
2229
2230 if( processedFootprints.find( footprint ) != processedFootprints.end() )
2231 continue;
2232
2233 processedFootprints.insert( footprint );
2234 m_commit->Modify( footprint );
2235 footprint->SetPosition( p_new );
2236 }
2237
2238 m_fpOffsets.clear();
2239
2240 for( const auto& [ src, items ] : m_replacementMap )
2241 {
2242 if( auto it = m_itemGroups.find( src ); it != m_itemGroups.end() )
2243 {
2244 EDA_GROUP* group = it->second;
2245 m_commit->Modify( group->AsEdaItem(), nullptr, RECURSE_MODE::NO_RECURSE );
2246
2247 for( BOARD_ITEM* bi : items )
2248 group->AddItem( bi );
2249 }
2250 }
2251
2252 m_itemGroups.clear();
2253 m_replacementMap.clear();
2254
2255 m_commit->Push( _( "Routing" ), m_commitFlags );
2256 m_commit = std::make_unique<BOARD_COMMIT>( m_tool );
2257}
2258
2259
2261{
2262 return static_cast<EDA_UNITS>( m_tool->GetManager()->GetSettings()->m_System.units );
2263}
2264
2265
2267{
2268 wxLogTrace( wxT( "PNS" ), wxT( "SetView %p" ), aView );
2269
2270 if( m_previewItems )
2271 {
2272 m_previewItems->FreeItems();
2273 delete m_previewItems;
2274 }
2275
2276 m_view = aView;
2279
2280 if(m_view)
2281 m_view->Add( m_previewItems );
2282
2283 delete m_debugDecorator;
2284
2285 auto dec = new PNS_PCBNEW_DEBUG_DECORATOR( this );
2286 m_debugDecorator = dec;
2287
2288 dec->SetDebugEnabled( ADVANCED_CFG::GetCfg().m_ShowRouterDebugGraphics );
2289
2290 if( ADVANCED_CFG::GetCfg().m_ShowRouterDebugGraphics )
2291 dec->SetView( m_view );
2292}
2293
2294
2296{
2297 if( aNet )
2298 return static_cast<NETINFO_ITEM*>( aNet )->GetNetCode();
2299 else
2300 return -1;
2301}
2302
2303
2305{
2306 if( aNet )
2307 return static_cast<NETINFO_ITEM*>( aNet )->GetNetname();
2308 else
2309 return wxEmptyString;
2310}
2311
2312
2314{
2315 wxLogTrace( wxT( "PNS" ), wxT( "Update-net %s" ), GetNetName( aNet ) );
2316}
2317
2318
2323
2324
2329
2330
2332{
2333 m_tool = aTool;
2334 m_commit = std::make_unique<BOARD_COMMIT>( m_tool );
2335}
2336
2337
2339{
2340 if( aLayer < 0 )
2342
2343 if( aLayer == 0 )
2344 return F_Cu;
2345
2346 if( aLayer == m_board->GetCopperLayerCount() - 1 )
2347 return B_Cu;
2348
2349 return static_cast<PCB_LAYER_ID>( ( aLayer + 1 ) * 2 );
2350}
2351
2352
2354{
2355 if( aLayer < 0 )
2356 return -1;
2357
2358 if( aLayer == F_Cu )
2359 return 0;
2360
2361 if( aLayer == B_Cu )
2362 return m_board->GetCopperLayerCount() - 1;
2363
2364 return ( aLayer / 2 ) - 1;
2365}
2366
2367
2372
2373
2379
2380
2382 const PNS::SOLID* aEndPad, const NETCLASS* aNetClass )
2383{
2384 std::vector<LENGTH_DELAY_CALCULATION_ITEM> lengthItems = getLengthDelayCalculationItems( aLine, aNetClass );
2385
2386 const PAD* startPad = nullptr;
2387 const PAD* endPad = nullptr;
2388
2389 if( aStartPad )
2390 startPad = static_cast<PAD*>( aStartPad->Parent() );
2391
2392 if( aEndPad )
2393 endPad = static_cast<PAD*>( aEndPad->Parent() );
2394
2395 constexpr PATH_OPTIMISATIONS opts = {
2396 .OptimiseViaLayers = false, .MergeTracks = false, .OptimiseTracesInPads = false, .InferViaInPad = true
2397 };
2398 const BOARD* board = GetBoard();
2399 return board->GetLengthCalculation()->CalculateLength( lengthItems, opts, startPad, endPad );
2400}
2401
2402
2404 const PNS::SOLID* aEndPad, const NETCLASS* aNetClass )
2405{
2406 std::vector<LENGTH_DELAY_CALCULATION_ITEM> lengthItems = getLengthDelayCalculationItems( aLine, aNetClass );
2407
2408 const PAD* startPad = nullptr;
2409 const PAD* endPad = nullptr;
2410
2411 if( aStartPad )
2412 startPad = static_cast<PAD*>( aStartPad->Parent() );
2413
2414 if( aEndPad )
2415 endPad = static_cast<PAD*>( aEndPad->Parent() );
2416
2417 constexpr PATH_OPTIMISATIONS opts = {
2418 .OptimiseViaLayers = false, .MergeTracks = false, .OptimiseTracesInPads = false, .InferViaInPad = true
2419 };
2420 const BOARD* board = GetBoard();
2421 return board->GetLengthCalculation()->CalculateDelay( lengthItems, opts, startPad, endPad );
2422}
2423
2424
2425int64_t PNS_KICAD_IFACE_BASE::CalculateLengthForDelay( int64_t aDesiredDelay, const int aWidth,
2426 const bool aIsDiffPairCoupled, const int aDiffPairCouplingGap,
2427 const int aPNSLayer, const NETCLASS* aNetClass )
2428{
2430 ctx.NetClass = aNetClass;
2431 ctx.Width = aWidth;
2432 ctx.IsDiffPairCoupled = aIsDiffPairCoupled;
2433 ctx.DiffPairCouplingGap = aDiffPairCouplingGap;
2434 ctx.Layer = GetBoardLayerFromPNSLayer( aPNSLayer );
2435
2436 const BOARD* board = GetBoard();
2437 return board->GetLengthCalculation()->CalculateLengthForDelay( aDesiredDelay, ctx );
2438}
2439
2440
2442 bool aIsDiffPairCoupled, int aDiffPairCouplingGap,
2443 int aPNSLayer, const NETCLASS* aNetClass )
2444{
2446 ctx.NetClass = aNetClass;
2447 ctx.Width = aWidth;
2448 ctx.IsDiffPairCoupled = aIsDiffPairCoupled;
2449 ctx.DiffPairCouplingGap = aDiffPairCouplingGap;
2450 ctx.Layer = GetBoardLayerFromPNSLayer( aPNSLayer );
2451
2452 const BOARD* board = GetBoard();
2454}
2455
2456
2457std::vector<LENGTH_DELAY_CALCULATION_ITEM>
2459{
2460 std::vector<LENGTH_DELAY_CALCULATION_ITEM> lengthItems;
2461
2462 for( int idx = 0; idx < aLine.Size(); idx++ )
2463 {
2464 const PNS::ITEM* lineItem = aLine[idx];
2465
2466 if( const PNS::LINE* l = dyn_cast<const PNS::LINE*>( lineItem ) )
2467 {
2469 item.SetLine( l->CLine() );
2470
2471 const PCB_LAYER_ID layer = GetBoardLayerFromPNSLayer( lineItem->Layer() );
2472 item.SetLayers( layer );
2473 item.SetEffectiveNetClass( aNetClass );
2474
2475 lengthItems.emplace_back( std::move( item ) );
2476 }
2477 else if( lineItem->OfKind( PNS::ITEM::VIA_T ) && idx > 0 && idx < aLine.Size() - 1 )
2478 {
2479 const int layerPrev = aLine[idx - 1]->Layer();
2480 const int layerNext = aLine[idx + 1]->Layer();
2481 const PCB_LAYER_ID pcbLayerPrev = GetBoardLayerFromPNSLayer( layerPrev );
2482 const PCB_LAYER_ID pcbLayerNext = GetBoardLayerFromPNSLayer( layerNext );
2483
2484 if( layerPrev != layerNext )
2485 {
2487 item.SetVia( static_cast<PCB_VIA*>( lineItem->GetSourceItem() ) );
2488 item.SetLayers( pcbLayerPrev, pcbLayerNext ); // TODO: BUG IS HERE!!!
2489 item.SetEffectiveNetClass( aNetClass );
2490 lengthItems.emplace_back( std::move( item ) );
2491 }
2492 }
2493 }
2494
2495 return lengthItems;
2496}
int color
@ ERROR_OUTSIDE
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
@ 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,...
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:79
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition board_item.h:232
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:314
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition board_item.h:280
FOOTPRINT * GetParentFootprint() const
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition board_item.h:252
virtual bool HasDrilledHole() const
Definition board_item.h:161
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:151
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:317
LENGTH_DELAY_CALCULATION * GetLengthCalculation() const
Returns the track length calculator.
Definition board.h:1339
constexpr const Vec & GetOrigin() const
Definition box2.h:210
constexpr const SizeVec & GetSize() const
Definition box2.h:206
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition color4d.h:398
wxString GetName() const
Definition drc_rule.h:170
SEVERITY GetSeverity() const
Definition drc_rule.h:183
const MINOPTMAX< int > & GetValue() const
Definition drc_rule.h:162
bool GetOption(OPTIONS option) const
Definition drc_rule.h:195
bool IsNull() const
Definition drc_rule.h:157
A set of EDA_ITEMs (i.e., without duplicates).
Definition eda_group.h:46
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:110
virtual EDA_GROUP * GetParentGroup() const
Definition eda_item.h:116
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:144
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition eda_item.h:192
virtual std::vector< SHAPE * > MakeEffectiveShapes(bool aEdgeOnly=false) const
Make a set of SHAPE objects representing the EDA_SHAPE.
Definition eda_shape.h:379
virtual bool IsVisible() const
Definition eda_text.h:186
void SetPosition(const VECTOR2I &aPos) override
bool IsNetTie() const
Definition footprint.h:340
VECTOR2I GetPosition() const override
Definition footprint.h:245
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:104
COLOR4D WithAlpha(double aAlpha) const
Return a color with the same color, but the given alpha.
Definition color4d.h:311
PCB specific render settings.
Definition pcb_painter.h:81
NET_COLOR_MODE GetNetColorMode() const
COLOR4D GetColor(const VIEW_ITEM *aItem, int aLayer) const override
Returns the color that should be used to draw the specific VIEW_ITEM on the specific layer using curr...
std::map< int, KIGFX::COLOR4D > & GetNetColorMap()
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
const std::set< int > & GetHighlightNetCodes() const
Return the netcode of currently highlighted net.
PCB_LAYER_ID GetPrimaryHighContrastLayer() const
Return the board layer which is in high-contrast mode.
Extend VIEW_ITEM by possibility of grouping items into a single object.
Definition view_group.h:43
virtual double ViewGetLOD(int aLayer, const VIEW *aView) const
Return the level of detail (LOD) of the item.
Definition view_item.h:155
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:66
Lightweight class which holds a pad, via, or a routed trace outline.
void SetLine(const SHAPE_LINE_CHAIN &aLine)
Sets the source SHAPE_LINE_CHAIN of this item.
void SetVia(const PCB_VIA *aVia)
Sets the VIA associated with this item.
void SetEffectiveNetClass(const NETCLASS *aNetClass)
Sets the effective net class for the item.
void SetLayers(const PCB_LAYER_ID aStart, const PCB_LAYER_ID aEnd=PCB_LAYER_ID::UNDEFINED_LAYER)
Sets the first and last layers associated with this item.
int64_t CalculateLengthForDelay(int64_t aDesiredDelay, const TIME_DOMAIN_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 TIME_DOMAIN_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:246
T Min() const
Definition minoptmax.h:33
void SetMin(T v)
Definition minoptmax.h:41
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:373
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::...
Definition padstack.cpp:882
void SetUnconnectedLayerMode(UNCONNECTED_LAYER_MODE aMode)
Definition padstack.h:315
UNCONNECTED_LAYER_MODE UnconnectedLayerMode() const
Definition padstack.h:314
@ NORMAL
Shape is the same on all layers.
Definition padstack.h:139
@ CUSTOM
Shapes can be defined on arbitrary layers.
Definition padstack.h:141
@ FRONT_INNER_BACK
Up to three shapes can be defined (F_Cu, inner copper layers, B_Cu)
Definition padstack.h:140
MODE Mode() const
Definition padstack.h:295
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition padstack.h:145
static constexpr PCB_LAYER_ID INNER_LAYERS
! The layer identifier to use for "inner layers" on top/inner/bottom padstacks
Definition padstack.h:148
Definition pad.h:54
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition pad.h:437
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:537
const VECTOR2I & GetDrillSize() const
Definition pad.h:305
PAD_ATTRIB GetAttribute() const
Definition pad.h:440
int GetPadToDieDelay() const
Definition pad.h:456
const PADSTACK & Padstack() const
Definition pad.h:321
const VECTOR2I & GetOffset(PCB_LAYER_ID aLayer) const
Definition pad.h:317
bool IsFreePad() const
Definition pad.cpp:284
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition pad.h:408
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(PCB_LAYER_ID aLayer, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition pad.cpp:525
VECTOR2I ShapePos(PCB_LAYER_ID aLayer) const
Definition pad.cpp:1068
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
Return a SHAPE_SEGMENT object representing the pad's hole.
Definition pad.cpp:598
int GetPadToDieLength() const
Definition pad.h:453
void SetMid(const VECTOR2I &aMid)
Definition pcb_track.h:344
const VECTOR2I & GetMid() const
Definition pcb_track.h:345
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:175
void SetEnd(const VECTOR2I &aEnd)
Definition pcb_track.h:148
bool HasSolderMask() const
Definition pcb_track.h:176
void SetStart(const VECTOR2I &aStart)
Definition pcb_track.h:151
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
Definition pcb_track.h:178
std::optional< int > GetLocalSolderMaskMargin() const
Definition pcb_track.h:179
const VECTOR2I & GetStart() const
Definition pcb_track.h:152
const VECTOR2I & GetEnd() const
Definition pcb_track.h:149
virtual void SetWidth(int aWidth)
Definition pcb_track.h:145
virtual int GetWidth() const
Definition pcb_track.h:146
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:704
PCB_LAYER_ID BottomLayer() const
VECTOR2I GetPosition() const override
Definition pcb_track.h:557
const PADSTACK & Padstack() const
Definition pcb_track.h:459
void SetFrontTentingMode(TENTING_MODE aMode)
TENTING_MODE GetFrontTentingMode() const
void SetDrill(int aDrill)
Set the drill value for vias.
Definition pcb_track.h:670
void SetBackTentingMode(TENTING_MODE aMode)
void SetIsFree(bool aFree=true)
Definition pcb_track.h:705
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:452
TENTING_MODE GetBackTentingMode() const
PCB_LAYER_ID TopLayer() const
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:451
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)
int Width() const override
Definition pns_arc.h:88
const SHAPE * Shape(int aLayer) const override
Return the geometrical shape of the item.
Definition pns_arc.h:78
static HOLE * MakeCircularHole(const VECTOR2I &pos, int radius, PNS_LAYER_RANGE aLayers)
Definition pns_hole.cpp:131
int Size() const
ITEM_SET & ExcludeItem(const ITEM *aItem)
ITEM_SET & FilterKinds(int aKindMask, bool aInvert=false)
std::vector< ITEM * > & Items()
Definition pns_itemset.h:87
Base class for PNS router board items.
Definition pns_item.h:98
BOARD_ITEM * Parent() const
Definition pns_item.h:199
virtual ITEM * ParentPadVia() const
Definition pns_item.h:293
virtual const SHAPE * Shape(int aLayer) const
Return the geometrical shape of the item.
Definition pns_item.h:242
const PNS_LAYER_RANGE & Layers() const
Definition pns_item.h:212
virtual NET_HANDLE Net() const
Definition pns_item.h:210
PnsKind Kind() const
Return the type (kind) of the item.
Definition pns_item.h:173
void SetNet(NET_HANDLE aNet)
Definition pns_item.h:209
BOARD_ITEM * GetSourceItem() const
Definition pns_item.h:202
virtual int Layer() const
Definition pns_item.h:216
void SetLayer(int aLayer)
Definition pns_item.h:215
void SetParent(BOARD_ITEM *aParent)
Definition pns_item.h:191
bool OfKind(int aKindMask) const
Definition pns_item.h:181
bool IsVirtual() const
Definition pns_item.h:295
virtual VECTOR2I Anchor(int n) const
Definition pns_item.h:268
virtual BOARD_ITEM * BoardItem() const
Definition pns_item.h:207
A 2D point on a given set of layers and belonging to a certain net, that links together a number of b...
Definition pns_joint.h:43
const ITEM_SET & CLinks() const
Definition pns_joint.h:308
Represents a track on a PCB, connecting two non-trivial joints (that is, vias, pads,...
Definition pns_line.h:62
Keep the router "world" - i.e.
Definition pns_node.h:232
void SetMaxClearance(int aClearance)
Assign a clearance resolution function object.
Definition pns_node.h:259
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:665
void SetRuleResolver(RULE_RESOLVER *aFunc)
Definition pns_node.h:265
void AddEdgeExclusion(std::unique_ptr< SHAPE > aShape)
Definition pns_node.cpp:709
const ITEM_OWNER * Owner() const
Return the owner of this item, or NULL if there's none.
Definition pns_item.h:72
const SEG & Seg() const
Definition pns_segment.h:93
void SetEnds(const VECTOR2I &a, const VECTOR2I &b)
int Width() const override
Definition pns_segment.h:88
void SetTrackWidth(int aWidth)
void SetBoardMinTrackWidth(int aWidth)
void SetDiffPairViaGapSameAsTraceGap(bool aEnable)
void SetDiffPairWidth(int aWidth)
void SetDiffPairWidthSource(const wxString &aSource)
void SetDiffPairGapSource(const wxString &aSource)
void SetDiffPairGap(int aGap)
void SetHoleToHole(int aHoleToHole)
void SetViaDrill(int aDrill)
void SetDiffPairViaGap(int aGap)
void SetDiffPairHoleToHole(int aHoleToHole)
void SetMinClearance(int aClearance)
void SetClearance(int aClearance)
void SetViaDiameter(int aDiameter)
void SetClearanceSource(const wxString &aSource)
void SetWidthSource(const wxString &aSource)
void SetTrackWidthIsExplicit(bool aIsExplicit)
bool syncGraphicalItem(PNS::NODE *aWorld, PCB_SHAPE *aItem)
bool inheritTrackWidth(PNS::ITEM *aItem, int *aInheritedWidth)
void AddItem(PNS::ITEM *aItem) override
virtual EDA_UNITS GetUnits() const
PNS::DEBUG_DECORATOR * m_debugDecorator
void SetDebugDecorator(PNS::DEBUG_DECORATOR *aDec)
bool syncZone(PNS::NODE *aWorld, ZONE *aZone, SHAPE_POLY_SET *aBoardOutline)
void SetBoard(BOARD *aBoard)
long long int CalculateRoutedPathLength(const PNS::ITEM_SET &aLine, const PNS::SOLID *aStartPad, const PNS::SOLID *aEndPad, const NETCLASS *aNetClass) override
int64_t CalculateRoutedPathDelay(const PNS::ITEM_SET &aLine, const PNS::SOLID *aStartPad, const PNS::SOLID *aEndPad, const NETCLASS *aNetClass) override
std::unique_ptr< PNS::ARC > syncArc(PCB_ARC *aArc)
void RemoveItem(PNS::ITEM *aItem) override
bool IsPNSCopperLayer(int aPNSLayer) const override
int64_t CalculateLengthForDelay(int64_t aDesiredDelay, int aWidth, bool aIsDiffPairCoupled, int aDiffPairCouplingGap, int aPNSLayer, const NETCLASS *aNetClass) override
PNS::RULE_RESOLVER * GetRuleResolver() override
bool syncTextItem(PNS::NODE *aWorld, BOARD_ITEM *aItem, PCB_LAYER_ID aLayer)
std::vector< LENGTH_DELAY_CALCULATION_ITEM > getLengthDelayCalculationItems(const PNS::ITEM_SET &aLine, const NETCLASS *aNetClass) const
bool IsKicadCopperLayer(PCB_LAYER_ID aPcbnewLayer) const
std::vector< std::unique_ptr< PNS::SOLID > > syncPad(PAD *aPad)
void SetStartLayerFromPCBNew(PCB_LAYER_ID aLayer)
bool IsFlashedOnLayer(const PNS::ITEM *aItem, int aLayer) const override
PCB_LAYER_ID GetBoardLayerFromPNSLayer(int aLayer) const override
BOARD * GetBoard() const
void SyncWorld(PNS::NODE *aWorld) override
int StackupHeight(int aFirstLayer, int aSecondLayer) const override
int64_t CalculateDelayForShapeLineChain(const SHAPE_LINE_CHAIN &aShape, int aWidth, bool aIsDiffPairCoupled, int aDiffPairCouplingGap, int aPNSLayer, const NETCLASS *aNetClass) override
PNS::DEBUG_DECORATOR * GetDebugDecorator() override
std::unique_ptr< PNS::SEGMENT > syncTrack(PCB_TRACK *aTrack)
PNS_PCBNEW_RULE_RESOLVER * m_ruleResolver
PNS::NET_HANDLE GetOrphanedNetHandle() override
std::unique_ptr< PNS::VIA > syncVia(PCB_VIA *aVia)
int GetPNSLayerFromBoardLayer(PCB_LAYER_ID aLayer) const override
PNS_LAYER_RANGE SetLayersFromPCBNew(PCB_LAYER_ID aStartLayer, PCB_LAYER_ID aEndLayer)
void UpdateItem(PNS::ITEM *aItem) override
bool ImportSizes(PNS::SIZES_SETTINGS &aSizes, PNS::ITEM *aStartItem, PNS::NET_HANDLE aNet, VECTOR2D aStartPosition) override
void SetView(KIGFX::VIEW *aView)
void RemoveItem(PNS::ITEM *aItem) override
void AddItem(PNS::ITEM *aItem) override
void UpdateItem(PNS::ITEM *aItem) override
std::map< PAD *, OFFSET > m_fpOffsets
int GetNetCode(PNS::NET_HANDLE aNet) const override
virtual void SetHostTool(PCB_TOOL_BASE *aTool)
void DisplayItem(const PNS::ITEM *aItem, int aClearance, bool aEdit=false, int aFlags=0) override
std::unique_ptr< BOARD_COMMIT > m_commit
void EraseView() override
void HideItem(PNS::ITEM *aItem) override
void UpdateNet(PNS::NET_HANDLE aNet) override
BOARD_CONNECTED_ITEM * createBoardItem(PNS::ITEM *aItem)
KIGFX::VIEW * m_view
void DisplayPathLine(const SHAPE_LINE_CHAIN &aLine, int aImportance) override
std::unordered_map< BOARD_ITEM *, EDA_GROUP * > m_itemGroups
bool IsItemVisible(const PNS::ITEM *aItem) const override
std::unordered_set< BOARD_ITEM * > m_hiddenItems
EDA_UNITS GetUnits() const override
bool IsAnyLayerVisible(const PNS_LAYER_RANGE &aLayer) const override
PCB_TOOL_BASE * m_tool
void modifyBoardItem(PNS::ITEM *aItem)
void Commit() override
KIGFX::VIEW_GROUP * m_previewItems
void DisplayRatline(const SHAPE_LINE_CHAIN &aRatline, PNS::NET_HANDLE aNet) override
std::unordered_map< BOARD_ITEM *, std::vector< BOARD_ITEM * > > m_replacementMap
wxString GetNetName(PNS::NET_HANDLE aNet) const override
~PNS_KICAD_IFACE() override
Represent a contiguous set of PCB layers.
int Start() const
bool Overlaps(const PNS_LAYER_RANGE &aOther) const
int End() const
PNS_LAYER_RANGE Intersection(const PNS_LAYER_RANGE &aOther) const
Shortcut for comparisons/overlap tests.
PNS_PCBNEW_DEBUG_DECORATOR(PNS::ROUTER_IFACE *aIface)
void AddPoint(const VECTOR2I &aP, const KIGFX::COLOR4D &aColor, int aSize, const wxString &aName=wxT(""), const SRC_LOCATION_INFO &aSrcLoc=SRC_LOCATION_INFO()) override
void AddShape(const BOX2I &aBox, const KIGFX::COLOR4D &aColor, int aOverrideWidth=0, const wxString &aName=wxT(""), const SRC_LOCATION_INFO &aSrcLoc=SRC_LOCATION_INFO()) override
void AddItem(const PNS::ITEM *aItem, const KIGFX::COLOR4D &aColor, int aOverrideWidth=0, const wxString &aName=wxT(""), const SRC_LOCATION_INFO &aSrcLoc=SRC_LOCATION_INFO()) override
virtual void Message(const wxString &msg, const SRC_LOCATION_INFO &aSrcLoc=SRC_LOCATION_INFO()) override
void SetView(KIGFX::VIEW *aView)
void AddShape(const SHAPE *aShape, const KIGFX::COLOR4D &aColor, int aOverrideWidth=0, const wxString &aName=wxT(""), const SRC_LOCATION_INFO &aSrcLoc=SRC_LOCATION_INFO()) override
int NetCode(PNS::NET_HANDLE aNet) override
PNS_PCBNEW_RULE_RESOLVER(BOARD *aBoard, PNS::ROUTER_IFACE *aRouterIface)
bool IsDrilledHole(const PNS::ITEM *aItem) override
void ClearTemporaryCaches() override
bool QueryConstraint(PNS::CONSTRAINT_TYPE aType, const PNS::ITEM *aItemA, const PNS::ITEM *aItemB, int aLayer, PNS::CONSTRAINT *aConstraint) override
int ClearanceEpsilon() const override
BOARD_ITEM * getBoardItem(const PNS::ITEM *aItem, PCB_LAYER_ID aBoardLayer, int aIdx=0)
bool IsKeepout(const PNS::ITEM *aObstacle, const PNS::ITEM *aItem, bool *aEnforce) override
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
wxString NetName(PNS::NET_HANDLE aNet) override
void SetWidth(int aWidth)
void SetClearance(int aClearance)
static constexpr double PathOverlayDepth
void SetColor(const KIGFX::COLOR4D &aColor)
double GetOriginDepth() const
void SetDepth(double aDepth)
void ShowClearance(bool aEnabled)
Definition seg.h:42
VECTOR2I A
Definition seg.h:49
VECTOR2I B
Definition seg.h:50
const VECTOR2I & GetArcMid() const
Definition shape_arc.h:118
const VECTOR2I & GetP1() const
Definition shape_arc.h:117
const VECTOR2I & GetP0() const
Definition shape_arc.h:116
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 std::vector< VECTOR2I > & CPoints() const
void GetTriangle(int index, VECTOR2I &a, VECTOR2I &b, VECTOR2I &c) const
Represent a set of closed polygons.
bool IsTriangulationUpToDate() const
virtual void CacheTriangulation(bool aPartition=true, bool aSimplify=false)
Build a polygon triangulation, needed to draw a polygon on OpenGL and in some other calculations.
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
const TRIANGULATED_POLYGON * TriangulatedPolygon(int aIndex) const
unsigned int TriangulatedPolyCount() const
Return the number of triangulated polygons.
int OutlineCount() const
Return the number of outlines in the set.
SHAPE * Clone() const override
Return a dynamically allocated copy of the shape.
Represent a simple polygon consisting of a zero-thickness closed chain of connected line segments.
void Append(int aX, int aY)
Append a new point at the end of the polygon.
An abstract shape on 2D plane.
Definition shape.h:126
double Distance(const VECTOR2< extended_type > &aVector) const
Compute the distance between two vectors.
Definition vector2d.h:561
VECTOR2_TRAITS< int32_t >::extended_type extended_type
Definition vector2d.h:73
Handle a list of polygons defining a copper zone.
Definition zone.h:74
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
Definition zone.cpp:1154
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition zone.h:704
bool GetDoNotAllowVias() const
Definition zone.h:720
bool GetDoNotAllowPads() const
Definition zone.h:722
bool GetDoNotAllowTracks() const
Definition zone.h:721
SHAPE_POLY_SET * Outline()
Definition zone.h:335
bool GetDoNotAllowFootprints() const
Definition zone.h:723
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:695
DRC_CONSTRAINT_T
Definition drc_rule.h:47
@ VIA_DIAMETER_CONSTRAINT
Definition drc_rule.h:70
@ DIFF_PAIR_GAP_CONSTRAINT
Definition drc_rule.h:73
@ TRACK_WIDTH_CONSTRAINT
Definition drc_rule.h:59
@ EDGE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:53
@ LENGTH_CONSTRAINT
Definition drc_rule.h:71
@ CLEARANCE_CONSTRAINT
Definition drc_rule.h:49
@ MAX_UNCOUPLED_CONSTRAINT
Definition drc_rule.h:74
@ SKEW_CONSTRAINT
Definition drc_rule.h:72
@ HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:51
@ HOLE_SIZE_CONSTRAINT
Definition drc_rule.h:54
@ PHYSICAL_CLEARANCE_CONSTRAINT
Definition drc_rule.h:77
@ HOLE_TO_HOLE_CONSTRAINT
Definition drc_rule.h:52
#define _(s)
@ NO_RECURSE
Definition eda_item.h:52
#define ROUTER_TRANSIENT
transient items that should NOT be cached
#define IN_EDIT
Item currently edited.
EDA_UNITS
Definition eda_units.h:48
static constexpr void hash_combine(std::size_t &seed)
This is a dummy function to take the final case of hash_combine below.
Definition hash.h:32
constexpr PCB_LAYER_ID PCBNEW_LAYER_ID_START
Definition layer_ids.h:174
@ ALWAYS_FLASHED
Always flashed for connectivity.
Definition layer_ids.h:186
@ LAYER_RATSNEST
Definition layer_ids.h:252
@ LAYER_SELECT_OVERLAY
Selected items overlay.
Definition layer_ids.h:279
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.
@ 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:87
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:83
@ PTH
Plated through hole pad.
Definition padstack.h:82
@ CONN
Like smd, does not appear on the solder paste layer (default) Note: also has a special attribute in G...
Definition padstack.h:84
@ CASTELLATED
a pad with a castellated through hole
Definition padstack.h:105
@ BLIND_BURIED
Definition pcb_track.h:68
@ 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)
@ 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
Struct to control which optimisations the length calculation code runs on the given path objects.
An abstract function object, returning a design rule (clearance, diff pair gap, etc) required between...
Definition pns_node.h:73
wxString m_RuleName
Definition pns_node.h:77
bool m_IsTimeDomain
Definition pns_node.h:80
MINOPTMAX< int > m_Value
Definition pns_node.h:75
CONSTRAINT_TYPE m_Type
Definition pns_node.h:74
A data structure to contain basic geometry data which can affect signal propagation calculations.
PCB_LAYER_ID Layer
The layer this track is on.
bool IsDiffPairCoupled
Whether this track or via is a member of a coupled differential pair.
int64_t DiffPairCouplingGap
The gap between coupled tracks.
int64_t Width
The width (in internal units) of the track.
const NETCLASS * NetClass
The net class this track belongs to.
std::size_t operator()(const CLEARANCE_CACHE_KEY &k) const
arc1_slc SetWidth(0)
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_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:97
@ 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:107
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:92
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition typeinfo.h:90
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:95
@ 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
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