KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_track.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
6 * Copyright (C) 2012 Wayne Stambaugh <[email protected]>
7 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, you may find one here:
21 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22 * or you may search the http://www.gnu.org website for the version 2 license,
23 * or you may write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 */
26
27#include "pcb_track.h"
28
29#include <pcb_base_frame.h>
30#include <core/mirror.h>
32#include <board.h>
35#include <base_units.h>
36#include <layer_range.h>
38#include <lset.h>
39#include <cstdlib>
40#include <string_utils.h>
41#include <view/view.h>
45#include <geometry/seg.h>
48#include <geometry/shape_arc.h>
49#include <drc/drc_engine.h>
50#include <pcb_painter.h>
51#include <trigo.h>
53
54#include <google/protobuf/any.pb.h>
55#include <api/api_enums.h>
56#include <api/api_utils.h>
57#include <api/api_pcb_utils.h>
58#include <api/board/board_types.pb.h>
59
62
64 BOARD_CONNECTED_ITEM( aParent, idtype )
65{
66 m_width = pcbIUScale.mmToIU( 0.2 ); // Gives a reasonable default width
67 m_hasSolderMask = false;
68}
69
70
72{
73 return new PCB_TRACK( *this );
74}
75
76
77void PCB_TRACK::CopyFrom( const BOARD_ITEM* aOther )
78{
79 wxCHECK( aOther && aOther->Type() == PCB_TRACE_T, /* void */ );
80 *this = *static_cast<const PCB_TRACK*>( aOther );
81}
82
83
84PCB_ARC::PCB_ARC( BOARD_ITEM* aParent, const SHAPE_ARC* aArc ) :
85 PCB_TRACK( aParent, PCB_ARC_T )
86{
87 m_Start = aArc->GetP0();
88 m_End = aArc->GetP1();
89 m_Mid = aArc->GetArcMid();
90}
91
92
94{
95 return new PCB_ARC( *this );
96}
97
98
99void PCB_ARC::CopyFrom( const BOARD_ITEM* aOther )
100{
101 wxCHECK( aOther && aOther->Type() == PCB_ARC_T, /* void */ );
102 *this = *static_cast<const PCB_ARC*>( aOther );
103}
104
105
107 PCB_TRACK( aParent, PCB_VIA_T ),
108 m_padStack( this )
109{
111 Padstack().Drill().start = F_Cu;
112 Padstack().Drill().end = B_Cu;
114
116
117 // Padstack layerset is not used for vias right now
118 m_padStack.LayerSet().reset();
119
120 // For now, vias are always circles
122
125
126 m_isFree = false;
127}
128
129
130PCB_VIA::PCB_VIA( const PCB_VIA& aOther ) :
131 PCB_TRACK( aOther.GetParent(), PCB_VIA_T ),
132 m_padStack( this )
133{
134 PCB_VIA::operator=( aOther );
135
136 const_cast<KIID&>( m_Uuid ) = aOther.m_Uuid;
138}
139
140
142{
144
145 m_Start = aOther.m_Start;
146 m_End = aOther.m_End;
147
148 m_viaType = aOther.m_viaType;
149 m_padStack = aOther.m_padStack;
150 m_isFree = aOther.m_isFree;
151
152 return *this;
153}
154
155
156void PCB_VIA::CopyFrom( const BOARD_ITEM* aOther )
157{
158 wxCHECK( aOther && aOther->Type() == PCB_VIA_T, /* void */ );
159 *this = *static_cast<const PCB_VIA*>( aOther );
160}
161
162
164{
165 return new PCB_VIA( *this );
166}
167
168
169wxString PCB_VIA::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
170{
171 wxString formatStr;
172
173 switch( GetViaType() )
174 {
175 case VIATYPE::BLIND: formatStr = _( "Blind via %s on %s" ); break;
176 case VIATYPE::BURIED: formatStr = _( "Buried via %s on %s" ); break;
177 case VIATYPE::MICROVIA: formatStr = _( "Micro via %s on %s" ); break;
178 default: formatStr = _( "Via %s on %s" ); break;
179 }
180
181 return wxString::Format( formatStr, GetNetnameMsg(), layerMaskDescribe() );
182}
183
184
186{
187 return BITMAPS::via;
188}
189
190
191bool PCB_TRACK::operator==( const BOARD_ITEM& aBoardItem ) const
192{
193 if( aBoardItem.Type() != Type() )
194 return false;
195
196 const PCB_TRACK& other = static_cast<const PCB_TRACK&>( aBoardItem );
197
198 return *this == other;
199}
200
201
202bool PCB_TRACK::operator==( const PCB_TRACK& aOther ) const
203{
204 return m_Start == aOther.m_Start
205 && m_End == aOther.m_End
206 && m_layer == aOther.m_layer
207 && m_width == aOther.m_width
210}
211
212
213double PCB_TRACK::Similarity( const BOARD_ITEM& aOther ) const
214{
215 if( aOther.Type() != Type() )
216 return 0.0;
217
218 const PCB_TRACK& other = static_cast<const PCB_TRACK&>( aOther );
219
220 double similarity = 1.0;
221
222 if( m_layer != other.m_layer )
223 similarity *= 0.9;
224
225 if( m_width != other.m_width )
226 similarity *= 0.9;
227
228 if( m_Start != other.m_Start )
229 similarity *= 0.9;
230
231 if( m_End != other.m_End )
232 similarity *= 0.9;
233
234 if( m_hasSolderMask != other.m_hasSolderMask )
235 similarity *= 0.9;
236
238 similarity *= 0.9;
239
240 return similarity;
241}
242
243
244bool PCB_ARC::operator==( const BOARD_ITEM& aBoardItem ) const
245{
246 if( aBoardItem.Type() != Type() )
247 return false;
248
249 const PCB_ARC& other = static_cast<const PCB_ARC&>( aBoardItem );
250
251 return *this == other;
252}
253
254
255bool PCB_ARC::operator==( const PCB_TRACK& aOther ) const
256{
257 if( aOther.Type() != Type() )
258 return false;
259
260 const PCB_ARC& other = static_cast<const PCB_ARC&>( aOther );
261
262 return *this == other;
263}
264
265
266bool PCB_ARC::operator==( const PCB_ARC& aOther ) const
267{
268 return m_Start == aOther.m_Start
269 && m_End == aOther.m_End
270 && m_Mid == aOther.m_Mid
271 && m_layer == aOther.m_layer
272 && GetWidth() == aOther.GetWidth()
275}
276
277
278double PCB_ARC::Similarity( const BOARD_ITEM& aOther ) const
279{
280 if( aOther.Type() != Type() )
281 return 0.0;
282
283 const PCB_ARC& other = static_cast<const PCB_ARC&>( aOther );
284
285 double similarity = 1.0;
286
287 if( m_layer != other.m_layer )
288 similarity *= 0.9;
289
290 if( GetWidth() != other.GetWidth() )
291 similarity *= 0.9;
292
293 if( m_Start != other.m_Start )
294 similarity *= 0.9;
295
296 if( m_End != other.m_End )
297 similarity *= 0.9;
298
299 if( m_Mid != other.m_Mid )
300 similarity *= 0.9;
301
302 if( m_hasSolderMask != other.m_hasSolderMask )
303 similarity *= 0.9;
304
306 similarity *= 0.9;
307
308 return similarity;
309}
310
311
312bool PCB_VIA::operator==( const BOARD_ITEM& aBoardItem ) const
313{
314 if( aBoardItem.Type() != Type() )
315 return false;
316
317 const PCB_VIA& other = static_cast<const PCB_VIA&>( aBoardItem );
318
319 return *this == other;
320}
321
322
323bool PCB_VIA::operator==( const PCB_TRACK& aOther ) const
324{
325 if( aOther.Type() != Type() )
326 return false;
327
328 const PCB_VIA& other = static_cast<const PCB_VIA&>( aOther );
329
330 return *this == other;
331}
332
333
334bool PCB_VIA::operator==( const PCB_VIA& aOther ) const
335{
336 return m_Start == aOther.m_Start
337 && m_End == aOther.m_End
338 && m_layer == aOther.m_layer
339 && m_padStack == aOther.m_padStack
340 && m_viaType == aOther.m_viaType
342}
343
344
345double PCB_VIA::Similarity( const BOARD_ITEM& aOther ) const
346{
347 if( aOther.Type() != Type() )
348 return 0.0;
349
350 const PCB_VIA& other = static_cast<const PCB_VIA&>( aOther );
351
352 double similarity = 1.0;
353
354 if( m_layer != other.m_layer )
355 similarity *= 0.9;
356
357 if( m_Start != other.m_Start )
358 similarity *= 0.9;
359
360 if( m_End != other.m_End )
361 similarity *= 0.9;
362
363 if( m_padStack != other.m_padStack )
364 similarity *= 0.9;
365
366 if( m_viaType != other.m_viaType )
367 similarity *= 0.9;
368
370 similarity *= 0.9;
371
372 return similarity;
373}
374
375
376void PCB_VIA::SetWidth( int aWidth )
377{
378 m_padStack.SetSize( { aWidth, aWidth }, PADSTACK::ALL_LAYERS );
379}
380
381
383{
384 return m_padStack.Size( PADSTACK::ALL_LAYERS ).x;
385}
386
387
388void PCB_VIA::SetWidth( PCB_LAYER_ID aLayer, int aWidth )
389{
390 m_padStack.SetSize( { aWidth, aWidth }, aLayer );
391}
392
393
395{
396 return m_padStack.Size( aLayer ).x;
397}
398
399
400void PCB_TRACK::Serialize( google::protobuf::Any &aContainer ) const
401{
402 kiapi::board::types::Track track;
403
404 track.mutable_id()->set_value( m_Uuid.AsStdString() );
405 track.mutable_start()->set_x_nm( GetStart().x );
406 track.mutable_start()->set_y_nm( GetStart().y );
407 track.mutable_end()->set_x_nm( GetEnd().x );
408 track.mutable_end()->set_y_nm( GetEnd().y );
409 track.mutable_width()->set_value_nm( GetWidth() );
411 track.set_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
412 : kiapi::common::types::LockedState::LS_UNLOCKED );
413 PackNet( track.mutable_net() );
414 // TODO m_hasSolderMask and m_solderMaskMargin
415
416 aContainer.PackFrom( track );
417}
418
419
420bool PCB_TRACK::Deserialize( const google::protobuf::Any &aContainer )
421{
422 kiapi::board::types::Track track;
423
424 if( !aContainer.UnpackTo( &track ) )
425 return false;
426
427 const_cast<KIID&>( m_Uuid ) = KIID( track.id().value() );
428 SetStart( VECTOR2I( track.start().x_nm(), track.start().y_nm() ) );
429 SetEnd( VECTOR2I( track.end().x_nm(), track.end().y_nm() ) );
430 SetWidth( track.width().value_nm() );
432 UnpackNet( track.net() );
433 SetLocked( track.locked() == kiapi::common::types::LockedState::LS_LOCKED );
434 // TODO m_hasSolderMask and m_solderMaskMargin
435
436 return true;
437}
438
439
440void PCB_ARC::Serialize( google::protobuf::Any &aContainer ) const
441{
442 kiapi::board::types::Arc arc;
443
444 arc.mutable_id()->set_value( m_Uuid.AsStdString() );
445 arc.mutable_start()->set_x_nm( GetStart().x );
446 arc.mutable_start()->set_y_nm( GetStart().y );
447 arc.mutable_mid()->set_x_nm( GetMid().x );
448 arc.mutable_mid()->set_y_nm( GetMid().y );
449 arc.mutable_end()->set_x_nm( GetEnd().x );
450 arc.mutable_end()->set_y_nm( GetEnd().y );
451 arc.mutable_width()->set_value_nm( GetWidth() );
453 arc.set_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
454 : kiapi::common::types::LockedState::LS_UNLOCKED );
455 PackNet( arc.mutable_net() );
456 // TODO m_hasSolderMask and m_solderMaskMargin
457
458 aContainer.PackFrom( arc );
459}
460
461
462bool PCB_ARC::Deserialize( const google::protobuf::Any &aContainer )
463{
464 kiapi::board::types::Arc arc;
465
466 if( !aContainer.UnpackTo( &arc ) )
467 return false;
468
469 const_cast<KIID&>( m_Uuid ) = KIID( arc.id().value() );
470 SetStart( VECTOR2I( arc.start().x_nm(), arc.start().y_nm() ) );
471 SetMid( VECTOR2I( arc.mid().x_nm(), arc.mid().y_nm() ) );
472 SetEnd( VECTOR2I( arc.end().x_nm(), arc.end().y_nm() ) );
473 SetWidth( arc.width().value_nm() );
475 UnpackNet( arc.net() );
476 SetLocked( arc.locked() == kiapi::common::types::LockedState::LS_LOCKED );
477 // TODO m_hasSolderMask and m_solderMaskMargin
478
479 return true;
480}
481
482
483void PCB_VIA::Serialize( google::protobuf::Any &aContainer ) const
484{
485 kiapi::board::types::Via via;
486
487 via.mutable_id()->set_value( m_Uuid.AsStdString() );
488 via.mutable_position()->set_x_nm( GetPosition().x );
489 via.mutable_position()->set_y_nm( GetPosition().y );
490
491 PADSTACK padstack = Padstack();
492
493 google::protobuf::Any padStackWrapper;
494 padstack.Serialize( padStackWrapper );
495 padStackWrapper.UnpackTo( via.mutable_pad_stack() );
496
497 // PADSTACK::m_layerSet is not used by vias
498 via.mutable_pad_stack()->clear_layers();
499 kiapi::board::PackLayerSet( *via.mutable_pad_stack()->mutable_layers(), GetLayerSet() );
500
502 via.set_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
503 : kiapi::common::types::LockedState::LS_UNLOCKED );
504 PackNet( via.mutable_net() );
505
506 aContainer.PackFrom( via );
507}
508
509
510bool PCB_VIA::Deserialize( const google::protobuf::Any &aContainer )
511{
512 kiapi::board::types::Via via;
513
514 if( !aContainer.UnpackTo( &via ) )
515 return false;
516
517 const_cast<KIID&>( m_Uuid ) = KIID( via.id().value() );
518 SetStart( VECTOR2I( via.position().x_nm(), via.position().y_nm() ) );
519 SetEnd( GetStart() );
520
521 google::protobuf::Any padStackWrapper;
522 padStackWrapper.PackFrom( via.pad_stack() );
523
524 if( !m_padStack.Deserialize( padStackWrapper ) )
525 return false;
526
527 // PADSTACK::m_layerSet is not used by vias
528 m_padStack.LayerSet().reset();
529
531 UnpackNet( via.net() );
532 SetLocked( via.locked() == kiapi::common::types::LockedState::LS_LOCKED );
533
534 return true;
535}
536
537
539{
540 SEG a( m_Start, m_End );
541 SEG b( aTrack.GetStart(), aTrack.GetEnd() );
542 return a.ApproxCollinear( b );
543}
544
545
547{
548 DRC_CONSTRAINT constraint;
549
550 if( GetBoard() && GetBoard()->GetDesignSettings().m_DRCEngine )
551 {
553
554 constraint = bds.m_DRCEngine->EvalRules( TRACK_WIDTH_CONSTRAINT, this, nullptr, m_layer );
555 }
556
557 if( aSource )
558 *aSource = constraint.GetName();
559
560 return constraint.Value();
561}
562
563
565{
566 DRC_CONSTRAINT constraint;
567
568 if( GetBoard() && GetBoard()->GetDesignSettings().m_DRCEngine )
569 {
571
572 constraint = bds.m_DRCEngine->EvalRules( VIA_DIAMETER_CONSTRAINT, this, nullptr, m_layer );
573 }
574
575 if( aSource )
576 *aSource = constraint.GetName();
577
578 return constraint.Value();
579}
580
581
583{
584 DRC_CONSTRAINT constraint;
585
586 if( GetBoard() && GetBoard()->GetDesignSettings().m_DRCEngine )
587 {
589
590 constraint = bds.m_DRCEngine->EvalRules( HOLE_SIZE_CONSTRAINT, this, nullptr, m_layer );
591 }
592
593 if( aSource )
594 *aSource = constraint.GetName();
595
596 return constraint.Value();
597}
598
599
600int PCB_VIA::GetMinAnnulus( PCB_LAYER_ID aLayer, wxString* aSource ) const
601{
602 if( !FlashLayer( aLayer ) )
603 {
604 if( aSource )
605 *aSource = _( "removed annular ring" );
606
607 return 0;
608 }
609
610 DRC_CONSTRAINT constraint;
611
612 if( GetBoard() && GetBoard()->GetDesignSettings().m_DRCEngine )
613 {
615
616 constraint = bds.m_DRCEngine->EvalRules( ANNULAR_WIDTH_CONSTRAINT, this, nullptr, aLayer );
617 }
618
619 if( constraint.Value().HasMin() )
620 {
621 if( aSource )
622 *aSource = constraint.GetName();
623
624 return constraint.Value().Min();
625 }
626
627 return 0;
628}
629
630
632{
633 if( m_padStack.Drill().size.x > 0 ) // Use the specific value.
634 return m_padStack.Drill().size.x;
635
636 // Use the default value from the Netclass
637 NETCLASS* netclass = GetEffectiveNetClass();
638
640 return netclass->GetuViaDrill();
641
642 return netclass->GetViaDrill();
643}
644
645
646EDA_ITEM_FLAGS PCB_TRACK::IsPointOnEnds( const VECTOR2I& point, int min_dist ) const
647{
649
650 if( min_dist < 0 )
651 min_dist = m_width / 2;
652
653 if( min_dist == 0 )
654 {
655 if( m_Start == point )
657
658 if( m_End == point )
659 result |= ENDPOINT;
660 }
661 else
662 {
663 double dist = m_Start.Distance( point );
664
665 if( min_dist >= dist )
667
668 dist = m_End.Distance( point );
669
670 if( min_dist >= dist )
671 result |= ENDPOINT;
672 }
673
674 return result;
675}
676
677
679{
680 // end of track is round, this is its radius, rounded up
681 int radius = ( m_width + 1 ) / 2;
682 int ymax, xmax, ymin, xmin;
683
684 if( Type() == PCB_VIA_T )
685 {
686 ymax = m_Start.y;
687 xmax = m_Start.x;
688
689 ymin = m_Start.y;
690 xmin = m_Start.x;
691 }
692 else if( Type() == PCB_ARC_T )
693 {
694 std::shared_ptr<SHAPE> arc = GetEffectiveShape();
695 BOX2I bbox = arc->BBox();
696
697 xmin = bbox.GetLeft();
698 xmax = bbox.GetRight();
699 ymin = bbox.GetTop();
700 ymax = bbox.GetBottom();
701 }
702 else
703 {
704 ymax = std::max( m_Start.y, m_End.y );
705 xmax = std::max( m_Start.x, m_End.x );
706
707 ymin = std::min( m_Start.y, m_End.y );
708 xmin = std::min( m_Start.x, m_End.x );
709 }
710
711 ymax += radius;
712 xmax += radius;
713
714 ymin -= radius;
715 xmin -= radius;
716
717 // return a rectangle which is [pos,dim) in nature. therefore the +1
718 return BOX2ISafe( VECTOR2I( xmin, ymin ),
719 VECTOR2L( (int64_t) xmax - xmin + 1, (int64_t) ymax - ymin + 1 ) );
720}
721
722
724{
725 int radius = 0;
726
728 [&]( PCB_LAYER_ID aLayer )
729 {
730 radius = std::max( radius, GetWidth( aLayer ) );
731 } );
732
733 // via is round, this is its radius, rounded up
734 radius = ( radius + 1 ) / 2;
735
736 int ymax = m_Start.y + radius;
737 int xmax = m_Start.x + radius;
738
739 int ymin = m_Start.y - radius;
740 int xmin = m_Start.x - radius;
741
742 // return a rectangle which is [pos,dim) in nature. therefore the +1
743 return BOX2ISafe( VECTOR2I( xmin, ymin ),
744 VECTOR2L( (int64_t) xmax - xmin + 1, (int64_t) ymax - ymin + 1 ) );
745}
746
747
749{
750 int radius = GetWidth( aLayer );
751
752 // via is round, this is its radius, rounded up
753 radius = ( radius + 1 ) / 2;
754
755 int ymax = m_Start.y + radius;
756 int xmax = m_Start.x + radius;
757
758 int ymin = m_Start.y - radius;
759 int xmin = m_Start.x - radius;
760
761 // return a rectangle which is [pos,dim) in nature. therefore the +1
762 return BOX2ISafe( VECTOR2I( xmin, ymin ),
763 VECTOR2L( (int64_t) xmax - xmin + 1, (int64_t) ymax - ymin + 1 ) );
764}
765
766
768{
769 return m_Start.Distance( m_End );
770}
771
772
774{
775 const BOARD* board = GetBoard();
776
777 if( !board )
778 return 0.0;
779
780 const LENGTH_DELAY_CALCULATION* calc = board->GetLengthCalculation();
781 std::vector<LENGTH_DELAY_CALCULATION_ITEM> items{ calc->GetLengthCalculationItem( this ) };
782 constexpr PATH_OPTIMISATIONS opts = { .OptimiseViaLayers = false,
783 .MergeTracks = false,
784 .OptimiseTracesInPads = false,
785 .InferViaInPad = false
786 };
787
788 return (double) calc->CalculateDelay( items, opts );
789}
790
791
792void PCB_TRACK::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
793{
794 RotatePoint( m_Start, aRotCentre, aAngle );
795 RotatePoint( m_End, aRotCentre, aAngle );
796}
797
798
799void PCB_ARC::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
800{
801 RotatePoint( m_Start, aRotCentre, aAngle );
802 RotatePoint( m_End, aRotCentre, aAngle );
803 RotatePoint( m_Mid, aRotCentre, aAngle );
804}
805
806
807void PCB_TRACK::Mirror( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
808{
809 MIRROR( m_Start, aCentre, aFlipDirection );
810 MIRROR( m_End, aCentre, aFlipDirection );
811}
812
813
814void PCB_ARC::Mirror( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
815{
816 MIRROR( m_Start, aCentre, aFlipDirection );
817 MIRROR( m_End, aCentre, aFlipDirection );
818 MIRROR( m_Mid, aCentre, aFlipDirection );
819}
820
821
822void PCB_TRACK::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
823{
824 if( aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
825 {
826 m_Start.x = aCentre.x - ( m_Start.x - aCentre.x );
827 m_End.x = aCentre.x - ( m_End.x - aCentre.x );
828 }
829 else
830 {
831 m_Start.y = aCentre.y - ( m_Start.y - aCentre.y );
832 m_End.y = aCentre.y - ( m_End.y - aCentre.y );
833 }
834
836}
837
838
839void PCB_ARC::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
840{
841 if( aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
842 {
843 m_Start.x = aCentre.x - ( m_Start.x - aCentre.x );
844 m_End.x = aCentre.x - ( m_End.x - aCentre.x );
845 m_Mid.x = aCentre.x - ( m_Mid.x - aCentre.x );
846 }
847 else
848 {
849 m_Start.y = aCentre.y - ( m_Start.y - aCentre.y );
850 m_End.y = aCentre.y - ( m_End.y - aCentre.y );
851 m_Mid.y = aCentre.y - ( m_Mid.y - aCentre.y );
852 }
853
855}
856
857
858bool PCB_ARC::IsCCW() const
859{
860 VECTOR2L start = m_Start;
861 VECTOR2L start_end = m_End - start;
862 VECTOR2L start_mid = m_Mid - start;
863
864 return start_end.Cross( start_mid ) < 0;
865}
866
867
868void PCB_VIA::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
869{
870 if( aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
871 {
872 m_Start.x = aCentre.x - ( m_Start.x - aCentre.x );
873 m_End.x = aCentre.x - ( m_End.x - aCentre.x );
874 }
875 else
876 {
877 m_Start.y = aCentre.y - ( m_Start.y - aCentre.y );
878 m_End.y = aCentre.y - ( m_End.y - aCentre.y );
879 }
880
882 {
883 PCB_LAYER_ID top_layer;
884 PCB_LAYER_ID bottom_layer;
885 LayerPair( &top_layer, &bottom_layer );
886 top_layer = GetBoard()->FlipLayer( top_layer );
887 bottom_layer = GetBoard()->FlipLayer( bottom_layer );
888 SetLayerPair( top_layer, bottom_layer );
889 }
890}
891
892
893INSPECT_RESULT PCB_TRACK::Visit( INSPECTOR inspector, void* testData,
894 const std::vector<KICAD_T>& aScanTypes )
895{
896 for( KICAD_T scanType : aScanTypes )
897 {
898 if( scanType == Type() )
899 {
900 if( INSPECT_RESULT::QUIT == inspector( this, testData ) )
902 }
903 }
904
906}
907
908
909std::shared_ptr<SHAPE_SEGMENT> PCB_VIA::GetEffectiveHoleShape() const
910{
911 return std::make_shared<SHAPE_SEGMENT>( SEG( m_Start, m_Start ), Padstack().Drill().size.x );
912}
913
914// clang-format off: the suggestion is slightly less readable
916{
917 switch( aMode )
918 {
919 case TENTING_MODE::FROM_RULES: m_padStack.FrontOuterLayers().has_solder_mask.reset(); break;
920 case TENTING_MODE::TENTED: m_padStack.FrontOuterLayers().has_solder_mask = true; break;
921 case TENTING_MODE::NOT_TENTED: m_padStack.FrontOuterLayers().has_solder_mask = false; break;
922 }
923}
924
925
927{
928 if( m_padStack.FrontOuterLayers().has_solder_mask.has_value() )
929 {
930 return *m_padStack.FrontOuterLayers().has_solder_mask ?
932 }
933
935}
936
937
939{
940 switch( aMode )
941 {
942 case TENTING_MODE::FROM_RULES: m_padStack.BackOuterLayers().has_solder_mask.reset(); break;
943 case TENTING_MODE::TENTED: m_padStack.BackOuterLayers().has_solder_mask = true; break;
944 case TENTING_MODE::NOT_TENTED: m_padStack.BackOuterLayers().has_solder_mask = false; break;
945 }
946}
947
948
950{
951 if( m_padStack.BackOuterLayers().has_solder_mask.has_value() )
952 {
953 return *m_padStack.BackOuterLayers().has_solder_mask ?
955 }
956
958}
959
960
962{
963 switch( aMode )
964 {
965 case COVERING_MODE::FROM_RULES: m_padStack.FrontOuterLayers().has_covering.reset(); break;
966 case COVERING_MODE::COVERED: m_padStack.FrontOuterLayers().has_covering = true; break;
967 case COVERING_MODE::NOT_COVERED: m_padStack.FrontOuterLayers().has_covering = false; break;
968 }
969}
970
971
973{
974 if( m_padStack.FrontOuterLayers().has_covering.has_value() )
975 {
976 return *m_padStack.FrontOuterLayers().has_covering ?
978 }
979
981}
982
983
985{
986 switch( aMode )
987 {
988 case COVERING_MODE::FROM_RULES: m_padStack.BackOuterLayers().has_covering.reset(); break;
989 case COVERING_MODE::COVERED: m_padStack.BackOuterLayers().has_covering = true; break;
990 case COVERING_MODE::NOT_COVERED: m_padStack.BackOuterLayers().has_covering = false; break;
991 }
992}
993
994
996{
997 if( m_padStack.BackOuterLayers().has_covering.has_value() )
998 {
999 return *m_padStack.BackOuterLayers().has_covering ?
1001 }
1002
1004}
1005
1006
1008{
1009 switch( aMode )
1010 {
1011 case PLUGGING_MODE::FROM_RULES: m_padStack.FrontOuterLayers().has_plugging.reset(); break;
1012 case PLUGGING_MODE::PLUGGED: m_padStack.FrontOuterLayers().has_plugging = true; break;
1013 case PLUGGING_MODE::NOT_PLUGGED: m_padStack.FrontOuterLayers().has_plugging = false; break;
1014 }
1015}
1016
1017
1019{
1020 if( m_padStack.FrontOuterLayers().has_plugging.has_value() )
1021 {
1022 return *m_padStack.FrontOuterLayers().has_plugging ?
1024 }
1025
1027}
1028
1029
1031{
1032 switch( aMode )
1033 {
1034 case PLUGGING_MODE::FROM_RULES: m_padStack.BackOuterLayers().has_plugging.reset(); break;
1035 case PLUGGING_MODE::PLUGGED: m_padStack.BackOuterLayers().has_plugging = true; break;
1036 case PLUGGING_MODE::NOT_PLUGGED: m_padStack.BackOuterLayers().has_plugging = false; break;
1037 }
1038}
1039
1040
1042{
1043 if( m_padStack.BackOuterLayers().has_plugging.has_value() )
1044 {
1045 return *m_padStack.BackOuterLayers().has_plugging ?
1047 }
1048
1050}
1051
1052
1054{
1055 switch( aMode )
1056 {
1057 case CAPPING_MODE::FROM_RULES: m_padStack.Drill().is_capped.reset(); break;
1058 case CAPPING_MODE::CAPPED: m_padStack.Drill().is_capped = true; break;
1059 case CAPPING_MODE::NOT_CAPPED: m_padStack.Drill().is_capped = false; break;
1060 }
1061}
1062
1063
1065{
1066 if( m_padStack.Drill().is_capped.has_value() )
1067 {
1068 return *m_padStack.Drill().is_capped ?
1070 }
1071
1073}
1074
1075
1077{
1078 switch( aMode )
1079 {
1080 case FILLING_MODE::FROM_RULES: m_padStack.Drill().is_filled.reset(); break;
1081 case FILLING_MODE::FILLED: m_padStack.Drill().is_filled = true; break;
1082 case FILLING_MODE::NOT_FILLED: m_padStack.Drill().is_filled = false; break;
1083 }
1084}
1085
1086
1088{
1089 if( m_padStack.Drill().is_filled.has_value() )
1090 {
1091 return *m_padStack.Drill().is_filled ?
1093 }
1094
1096}
1097// clang-format on: the suggestion is slightly less readable
1098
1099
1101{
1102 wxCHECK_MSG( IsFrontLayer( aLayer ) || IsBackLayer( aLayer ), true,
1103 "Invalid layer passed to IsTented" );
1104
1105 bool front = IsFrontLayer( aLayer );
1106
1107 if( front && m_padStack.FrontOuterLayers().has_solder_mask.has_value() )
1108 return *m_padStack.FrontOuterLayers().has_solder_mask;
1109
1110 if( !front && m_padStack.BackOuterLayers().has_solder_mask.has_value() )
1111 return *m_padStack.BackOuterLayers().has_solder_mask;
1112
1113 if( const BOARD* board = GetBoard() )
1114 {
1115 return front ? board->GetDesignSettings().m_TentViasFront
1116 : board->GetDesignSettings().m_TentViasBack;
1117 }
1118
1119 return true;
1120}
1121
1122
1124{
1125 if( const BOARD* board = GetBoard() )
1126 return board->GetDesignSettings().m_SolderMaskExpansion;
1127 else
1128 return 0;
1129}
1130
1131
1133{
1134 int margin = 0;
1135
1136 if( GetBoard() && GetBoard()->GetDesignSettings().m_DRCEngine )
1137 {
1138 DRC_CONSTRAINT constraint;
1139 std::shared_ptr<DRC_ENGINE> drcEngine = GetBoard()->GetDesignSettings().m_DRCEngine;
1140
1141 constraint = drcEngine->EvalRules( SOLDER_MASK_EXPANSION_CONSTRAINT, this, nullptr, m_layer );
1142
1143 if( constraint.m_Value.HasOpt() )
1144 margin = constraint.m_Value.Opt();
1145 }
1146 else if( m_solderMaskMargin.has_value() )
1147 {
1148 margin = m_solderMaskMargin.value();
1149 }
1150
1151 // Ensure the resulting mask opening has a non-negative size
1152 if( margin < 0 )
1153 margin = std::max( margin, -m_width / 2 );
1154
1155 return margin;
1156}
1157
1158
1160{
1161 if( aLayer == m_layer )
1162 {
1163 return true;
1164 }
1165
1166 if( m_hasSolderMask && ( ( aLayer == F_Mask && m_layer == F_Cu )
1167 || ( aLayer == B_Mask && m_layer == B_Cu ) ) )
1168 {
1169 return true;
1170 }
1171
1172 return false;
1173}
1174
1175
1177{
1178#if 0
1179 // Nice and simple, but raises its ugly head in performance profiles....
1180 return GetLayerSet().test( aLayer );
1181#endif
1182 if( IsCopperLayer( aLayer ) &&
1183 LAYER_RANGE::Contains( Padstack().Drill().start, Padstack().Drill().end, aLayer ) )
1184 {
1185 return true;
1186 }
1187
1188 // Test for via on mask layers: a via on on a mask layer if not tented and if
1189 // it is on the corresponding external copper layer
1190 if( aLayer == F_Mask )
1191 return Padstack().Drill().start == F_Cu && !IsTented( F_Mask );
1192 else if( aLayer == B_Mask )
1193 return Padstack().Drill().end == B_Cu && !IsTented( B_Mask );
1194
1195 return false;
1196}
1197
1198
1199bool PCB_VIA::HasValidLayerPair( int aCopperLayerCount )
1200{
1201 // return true if top and bottom layers are valid, depending on the copper layer count
1202 // aCopperLayerCount is expected >= 2
1203
1204 int layer_id = aCopperLayerCount*2;
1205
1206 if( Padstack().Drill().start > B_Cu )
1207 {
1208 if( Padstack().Drill().start > layer_id )
1209 return false;
1210 }
1211 if( Padstack().Drill().end > B_Cu )
1212 {
1213 if( Padstack().Drill().end > layer_id )
1214 return false;
1215 }
1216
1217 return true;
1218}
1219
1220
1222{
1223 return Padstack().Drill().start;
1224}
1225
1226
1228{
1229 Padstack().Drill().start = aLayer;
1230}
1231
1232
1233void PCB_TRACK::SetLayerSet( const LSET& aLayerSet )
1234{
1235 aLayerSet.RunOnLayers(
1236 [&]( PCB_LAYER_ID layer )
1237 {
1238 if( IsCopperLayer( layer ) )
1239 SetLayer( layer );
1240 else if( IsSolderMaskLayer( layer ) )
1241 SetHasSolderMask( true );
1242 } );
1243}
1244
1245
1247{
1248 LSET layermask( { m_layer } );
1249
1250 if( m_hasSolderMask )
1251 {
1252 if( layermask.test( F_Cu ) )
1253 layermask.set( F_Mask );
1254 else if( layermask.test( B_Cu ) )
1255 layermask.set( B_Mask );
1256 }
1257
1258 return layermask;
1259}
1260
1261
1263{
1264 LSET layermask;
1265
1266 if( Padstack().Drill().start < PCBNEW_LAYER_ID_START )
1267 return layermask;
1268
1269 if( GetViaType() == VIATYPE::THROUGH )
1270 {
1271 layermask = LSET::AllCuMask( BoardCopperLayerCount() );
1272 }
1273 else
1274 {
1275 LAYER_RANGE range( Padstack().Drill().start, Padstack().Drill().end, BoardCopperLayerCount() );
1276
1277 int cnt = BoardCopperLayerCount();
1278 // PCB_LAYER_IDs are numbered from front to back, this is top to bottom.
1279 for( PCB_LAYER_ID id : range )
1280 {
1281 layermask.set( id );
1282
1283 if( --cnt <= 0 )
1284 break;
1285 }
1286 }
1287
1288 if( !IsTented( F_Mask ) && layermask.test( F_Cu ) )
1289 layermask.set( F_Mask );
1290
1291 if( !IsTented( B_Mask ) && layermask.test( B_Cu ) )
1292 layermask.set( B_Mask );
1293
1294 return layermask;
1295}
1296
1297
1298void PCB_VIA::SetLayerSet( const LSET& aLayerSet )
1299{
1300 // Vias do not use a LSET, just a top and bottom layer pair
1301 // So we need to set these 2 layers according to the allowed layers in aLayerSet
1302
1303 // For via through, only F_Cu and B_Cu are allowed. aLayerSet is ignored
1304 if( GetViaType() == VIATYPE::THROUGH )
1305 {
1306 Padstack().Drill().start = F_Cu;
1307 Padstack().Drill().end = B_Cu;
1308 return;
1309 }
1310
1311 // For blind buried vias, find the top and bottom layers
1312 bool top_found = false;
1313 bool bottom_found = false;
1314
1315 aLayerSet.RunOnLayers(
1316 [&]( PCB_LAYER_ID layer )
1317 {
1318 // tpo layer and bottom Layer are copper layers, so consider only copper layers
1319 if( IsCopperLayer( layer ) )
1320 {
1321 // The top layer is the first layer found in list and
1322 // cannot the B_Cu
1323 if( !top_found && layer != B_Cu )
1324 {
1325 Padstack().Drill().start = layer;
1326 top_found = true;
1327 }
1328
1329 // The bottom layer is the last layer found in list or B_Cu
1330 if( !bottom_found )
1331 Padstack().Drill().end = layer;
1332
1333 if( layer == B_Cu )
1334 bottom_found = true;
1335 }
1336 } );
1337}
1338
1339
1340void PCB_VIA::SetLayerPair( PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer )
1341{
1342 Padstack().Drill().start = aTopLayer;
1343 Padstack().Drill().end = aBottomLayer;
1345}
1346
1347
1349{
1350 // refuse invalid via
1351 if( aLayer == Padstack().Drill().end )
1352 return;
1353
1354 Padstack().Drill().start = aLayer;
1356}
1357
1358
1360{
1361 // refuse invalid via
1362 if( aLayer == Padstack().Drill().start )
1363 return;
1364
1365 Padstack().Drill().end = aLayer;
1367}
1368
1369
1370void PCB_VIA::LayerPair( PCB_LAYER_ID* top_layer, PCB_LAYER_ID* bottom_layer ) const
1371{
1372 PCB_LAYER_ID t_layer = F_Cu;
1373 PCB_LAYER_ID b_layer = B_Cu;
1374
1375 if( GetViaType() != VIATYPE::THROUGH )
1376 {
1377 b_layer = Padstack().Drill().end;
1378 t_layer = Padstack().Drill().start;
1379
1380 if( !IsCopperLayerLowerThan( b_layer, t_layer ) )
1381 std::swap( b_layer, t_layer );
1382 }
1383
1384 if( top_layer )
1385 *top_layer = t_layer;
1386
1387 if( bottom_layer )
1388 *bottom_layer = b_layer;
1389}
1390
1391
1393{
1394 return Padstack().Drill().start;
1395}
1396
1397
1399{
1400 return Padstack().Drill().end;
1401}
1402
1403
1405{
1406 if( GetViaType() == VIATYPE::THROUGH )
1407 {
1408 Padstack().Drill().start = F_Cu;
1409 Padstack().Drill().end = B_Cu;
1410 }
1411
1412 if( !IsCopperLayerLowerThan( Padstack().Drill().end, Padstack().Drill().start) )
1413 std::swap( Padstack().Drill().end, Padstack().Drill().start );
1414}
1415
1416
1417std::optional<PCB_VIA::VIA_PARAMETER_ERROR>
1418PCB_VIA::ValidateViaParameters( std::optional<int> aDiameter,
1419 std::optional<int> aDrill,
1420 std::optional<PCB_LAYER_ID> aStartLayer,
1421 std::optional<PCB_LAYER_ID> aEndLayer )
1422{
1423 VIA_PARAMETER_ERROR error;
1424
1425 if( aDiameter.has_value() && aDiameter.value() < GEOMETRY_MIN_SIZE )
1426 {
1427 error.m_Message = _( "Via diameter is too small." );
1429 return error;
1430 }
1431
1432 if( aDrill.has_value() && aDrill.value() < GEOMETRY_MIN_SIZE )
1433 {
1434 error.m_Message = _( "Via drill is too small." );
1436 return error;
1437 }
1438
1439 if( aDiameter.has_value() && !aDrill.has_value() )
1440 {
1441 error.m_Message = _( "No via hole size defined." );
1443 return error;
1444 }
1445
1446 if( aDrill.has_value() && !aDiameter.has_value() )
1447 {
1448 error.m_Message = _( "No via diameter defined." );
1450 return error;
1451 }
1452
1453 if( aDiameter.has_value() && aDrill.has_value()
1454 && aDiameter.value() <= aDrill.value() )
1455 {
1456 error.m_Message = _( "Via hole size must be smaller than via diameter" );
1458 return error;
1459 }
1460
1461 if( aStartLayer.has_value() && aEndLayer.has_value()
1462 && aStartLayer.value() == aEndLayer.value() )
1463 {
1464 error.m_Message = _( "Via start layer and end layer cannot be the same" );
1466 return error;
1467 }
1468
1469 return std::nullopt;
1470}
1471
1473{
1474 return std::abs( static_cast<int>( Padstack().Drill().start )
1475 - static_cast<int>( Padstack().Drill().end ) ) == 2;
1476}
1477
1479{
1480 if( IsMicroVia() )
1481 return false;
1482
1483 bool startOuter = Padstack().Drill().start == F_Cu || Padstack().Drill().start == B_Cu;
1484 bool endOuter = Padstack().Drill().end == F_Cu || Padstack().Drill().end == B_Cu;
1485
1486 return startOuter ^ endOuter;
1487}
1488
1490{
1491 return Padstack().Drill().start != F_Cu && Padstack().Drill().start != B_Cu
1492 && Padstack().Drill().end != F_Cu && Padstack().Drill().end != B_Cu;
1493}
1494
1495
1496bool PCB_VIA::FlashLayer( const LSET& aLayers ) const
1497{
1498 for( PCB_LAYER_ID layer : aLayers )
1499 {
1500 if( FlashLayer( layer ) )
1501 return true;
1502 }
1503
1504 return false;
1505}
1506
1507
1508bool PCB_VIA::FlashLayer( int aLayer ) const
1509{
1510 // Return the "normal" shape if the caller doesn't specify a particular layer
1511 if( aLayer == UNDEFINED_LAYER )
1512 return true;
1513
1514 const BOARD* board = GetBoard();
1515 PCB_LAYER_ID layer = static_cast<PCB_LAYER_ID>( aLayer );
1516
1517 if( !board )
1518 return true;
1519
1520 if( !IsOnLayer( layer ) )
1521 return false;
1522
1523 if( !IsCopperLayer( layer ) )
1524 return true;
1525
1526 switch( Padstack().UnconnectedLayerMode() )
1527 {
1529 return true;
1530
1532 {
1533 if( layer == Padstack().Drill().start || layer == Padstack().Drill().end )
1534 return true;
1535
1536 // Check for removal below
1537 break;
1538 }
1539
1541 // Check for removal below
1542 break;
1543
1545 return layer == Padstack().Drill().start || layer == Padstack().Drill().end;
1546 }
1547
1548 if( GetZoneLayerOverride( layer ) == ZLO_FORCE_FLASHED )
1549 {
1550 return true;
1551 }
1552 else
1553 {
1554 // Must be static to keep from raising its ugly head in performance profiles
1555 static std::initializer_list<KICAD_T> nonZoneTypes = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T,
1556 PCB_PAD_T };
1557
1558 return board->GetConnectivity()->IsConnectedOnLayer( this, layer, nonZoneTypes );
1559 }
1560}
1561
1562
1564{
1565 std::unique_lock<std::mutex> cacheLock( m_zoneLayerOverridesMutex );
1566
1569}
1570
1571
1573{
1574 static const ZONE_LAYER_OVERRIDE defaultOverride = ZLO_NONE;
1575 auto it = m_zoneLayerOverrides.find( aLayer );
1576 return it != m_zoneLayerOverrides.end() ? it->second : defaultOverride;
1577}
1578
1579
1581{
1582 std::unique_lock<std::mutex> cacheLock( m_zoneLayerOverridesMutex );
1583 m_zoneLayerOverrides[aLayer] = aOverride;
1584}
1585
1586
1588 PCB_LAYER_ID* aBottommost ) const
1589{
1590 *aTopmost = UNDEFINED_LAYER;
1591 *aBottommost = UNDEFINED_LAYER;
1592
1593 static std::initializer_list<KICAD_T> nonZoneTypes = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T,
1594 PCB_PAD_T };
1595
1596 for( int layer = TopLayer(); layer <= BottomLayer(); ++layer )
1597 {
1598 bool connected = false;
1599
1600 if( GetZoneLayerOverride( static_cast<PCB_LAYER_ID>( layer ) ) == ZLO_FORCE_FLASHED )
1601 {
1602 connected = true;
1603 }
1604 else if( GetBoard()->GetConnectivity()->IsConnectedOnLayer( this, layer, nonZoneTypes ) )
1605 {
1606 connected = true;
1607 }
1608
1609 if( connected )
1610 {
1611 if( *aTopmost == UNDEFINED_LAYER )
1612 *aTopmost = ToLAYER_ID( layer );
1613
1614 *aBottommost = ToLAYER_ID( layer );
1615 }
1616 }
1617
1618}
1619
1620
1621std::vector<int> PCB_TRACK::ViewGetLayers() const
1622{
1623 // Show the track and its netname on different layers
1624 const PCB_LAYER_ID layer = GetLayer();
1625 std::vector<int> layers{
1626 layer,
1627 GetNetnameLayer( layer ),
1628 LAYER_CLEARANCE_START + layer,
1629 };
1630
1631 layers.reserve( 6 );
1632
1633 if( m_hasSolderMask )
1634 {
1635 if( m_layer == F_Cu )
1636 layers.push_back( F_Mask );
1637 else if( m_layer == B_Cu )
1638 layers.push_back( B_Mask );
1639 }
1640
1641 if( IsLocked() )
1642 layers.push_back( LAYER_LOCKED_ITEM_SHADOW );
1643
1644 return layers;
1645}
1646
1647
1648double PCB_TRACK::ViewGetLOD( int aLayer, const KIGFX::VIEW* aView ) const
1649{
1650 PCB_PAINTER* painter = static_cast<PCB_PAINTER*>( aView->GetPainter() );
1651 PCB_RENDER_SETTINGS* renderSettings = painter->GetSettings();
1652
1653 if( !aView->IsLayerVisible( LAYER_TRACKS ) )
1654 return LOD_HIDE;
1655
1656 if( IsNetnameLayer( aLayer ) )
1657 {
1659 return LOD_HIDE;
1660
1661 // Hide netnames on dimmed tracks
1662 if( renderSettings->GetHighContrast() )
1663 {
1664 if( m_layer != renderSettings->GetPrimaryHighContrastLayer() )
1665 return LOD_HIDE;
1666 }
1667
1668 VECTOR2I start( GetStart() );
1669 VECTOR2I end( GetEnd() );
1670
1671 // Calc the approximate size of the netname (assume square chars)
1672 SEG::ecoord nameSize = GetDisplayNetname().size() * GetWidth();
1673
1674 if( VECTOR2I( end - start ).SquaredEuclideanNorm() < nameSize * nameSize )
1675 return LOD_HIDE;
1676
1677 BOX2I clipBox = BOX2ISafe( aView->GetViewport() );
1678
1679 ClipLine( &clipBox, start.x, start.y, end.x, end.y );
1680
1681 if( VECTOR2I( end - start ).SquaredEuclideanNorm() == 0 )
1682 return LOD_HIDE;
1683
1684 // Netnames will be shown only if zoom is appropriate
1685 return lodScaleForThreshold( aView, m_width, pcbIUScale.mmToIU( 4.0 ) );
1686 }
1687
1688 if( aLayer == LAYER_LOCKED_ITEM_SHADOW )
1689 {
1690 // Hide shadow if the main layer is not shown
1691 if( !aView->IsLayerVisible( m_layer ) )
1692 return LOD_HIDE;
1693
1694 // Hide shadow on dimmed tracks
1695 if( renderSettings->GetHighContrast() )
1696 {
1697 if( m_layer != renderSettings->GetPrimaryHighContrastLayer() )
1698 return LOD_HIDE;
1699 }
1700 }
1701
1702 // Other layers are shown without any conditions
1703 return LOD_SHOW;
1704}
1705
1706
1708{
1709 BOX2I bbox = GetBoundingBox();
1710
1711 if( const BOARD* board = GetBoard() )
1712 bbox.Inflate( 2 * board->GetDesignSettings().GetBiggestClearanceValue() );
1713 else
1714 bbox.Inflate( GetWidth() ); // Add a bit extra for safety
1715
1716 return bbox;
1717}
1718
1719
1720std::vector<int> PCB_VIA::ViewGetLayers() const
1721{
1722 LAYER_RANGE layers( Padstack().Drill().start, Padstack().Drill().end, MAX_CU_LAYERS );
1723 std::vector<int> ret_layers{ LAYER_VIA_HOLES, LAYER_VIA_HOLEWALLS, LAYER_VIA_NETNAMES };
1724 ret_layers.reserve( MAX_CU_LAYERS + 6 );
1725
1726 // TODO(JE) Rendering order issue
1727#if 0
1728 // Blind/buried vias (and microvias) use a different net name layer
1729 PCB_LAYER_ID layerTop, layerBottom;
1730 LayerPair( &layerTop, &layerBottom );
1731
1732 bool isBlindBuried =
1735 || ( m_viaType == VIATYPE::MICROVIA && ( layerTop != F_Cu || layerBottom != B_Cu ) );
1736#endif
1737 LSET cuMask = LSET::AllCuMask();
1738
1739 if( const BOARD* board = GetBoard() )
1740 cuMask &= board->GetEnabledLayers();
1741
1742 for( PCB_LAYER_ID layer : layers )
1743 {
1744 if( !cuMask.Contains( layer ) )
1745 continue;
1746
1747 ret_layers.push_back( LAYER_VIA_COPPER_START + layer );
1748 ret_layers.push_back( LAYER_CLEARANCE_START + layer );
1749 }
1750
1751 if( IsLocked() )
1752 ret_layers.push_back( LAYER_LOCKED_ITEM_SHADOW );
1753
1754 // Vias can also be on a solder mask layer. They are on these layers or not,
1755 // depending on the plot and solder mask options
1756 if( IsOnLayer( F_Mask ) )
1757 ret_layers.push_back( F_Mask );
1758
1759 if( IsOnLayer( B_Mask ) )
1760 ret_layers.push_back( B_Mask );
1761
1762 return ret_layers;
1763}
1764
1765
1766double PCB_VIA::ViewGetLOD( int aLayer, const KIGFX::VIEW* aView ) const
1767{
1768 PCB_PAINTER* painter = static_cast<PCB_PAINTER*>( aView->GetPainter() );
1769 PCB_RENDER_SETTINGS* renderSettings = painter->GetSettings();
1770 const BOARD* board = GetBoard();
1771
1772 // Meta control for hiding all vias
1773 if( !aView->IsLayerVisible( LAYER_VIAS ) )
1774 return LOD_HIDE;
1775
1776 // In high contrast mode don't show vias that don't cross the high-contrast layer
1777 if( renderSettings->GetHighContrast() )
1778 {
1779 PCB_LAYER_ID highContrastLayer = renderSettings->GetPrimaryHighContrastLayer();
1780
1781 if( LSET::FrontTechMask().Contains( highContrastLayer ) )
1782 highContrastLayer = F_Cu;
1783 else if( LSET::BackTechMask().Contains( highContrastLayer ) )
1784 highContrastLayer = B_Cu;
1785
1786 if( IsCopperLayer( highContrastLayer ) && GetViaType() != VIATYPE::THROUGH )
1787 {
1788 if( IsCopperLayerLowerThan( Padstack().Drill().start, highContrastLayer )
1789 || IsCopperLayerLowerThan( highContrastLayer, Padstack().Drill().end ) )
1790 {
1791 return LOD_HIDE;
1792 }
1793 }
1794 }
1795
1796 if( IsHoleLayer( aLayer ) )
1797 {
1798 LSET visible;
1799
1800 if( board )
1801 {
1802 visible = board->GetVisibleLayers();
1803 visible &= board->GetEnabledLayers();
1804 }
1805 else
1806 {
1807 visible = LSET::AllLayersMask();
1808 }
1809
1811 {
1812 // Show a through via's hole if any physical layer is shown
1813 visible &= LSET::PhysicalLayersMask();
1814
1815 if( !visible.any() )
1816 return LOD_HIDE;
1817 }
1818 else
1819 {
1820 // Show a blind or micro via's hole if it crosses a visible layer
1821 visible &= GetLayerSet();
1822
1823 if( !visible.any() )
1824 return LOD_HIDE;
1825 }
1826
1827 // The hole won't be visible anyway at this scale
1828 return lodScaleForThreshold( aView, GetDrillValue(), pcbIUScale.mmToIU( 0.25 ) );
1829 }
1830 else if( IsNetnameLayer( aLayer ) )
1831 {
1832 if( renderSettings->GetHighContrast() )
1833 {
1834 // Hide netnames unless via is flashed to a high-contrast layer
1835 if( !FlashLayer( renderSettings->GetPrimaryHighContrastLayer() ) )
1836 return LOD_HIDE;
1837 }
1838 else
1839 {
1840 LSET visible;
1841
1842 if( board )
1843 {
1844 visible = board->GetVisibleLayers();
1845 visible &= board->GetEnabledLayers();
1846 }
1847 else
1848 {
1849 visible = LSET::AllLayersMask();
1850 }
1851
1852 // Hide netnames unless pad is flashed to a visible layer
1853 if( !FlashLayer( visible ) )
1854 return LOD_HIDE;
1855 }
1856
1857 int width = GetWidth( ToLAYER_ID( aLayer ) );
1858
1859 // Netnames will be shown only if zoom is appropriate
1860 return lodScaleForThreshold( aView, width, pcbIUScale.mmToIU( 10 ) );
1861 }
1862
1863 if( !IsCopperLayer( aLayer ) )
1864 {
1865 int width = GetWidth( ToLAYER_ID( aLayer ) );
1866
1867 return lodScaleForThreshold( aView, width, pcbIUScale.mmToIU( 0.6 ) );
1868 }
1869
1870 return LOD_SHOW;
1871}
1872
1873
1875{
1876 switch( Type() )
1877 {
1878 case PCB_ARC_T: return _( "Track (arc)" );
1879 case PCB_VIA_T: return _( "Via" );
1880 case PCB_TRACE_T:
1881 default: return _( "Track" );
1882 }
1883}
1884
1885
1886void PCB_TRACK::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1887{
1888 wxString msg;
1889 BOARD* board = GetBoard();
1890
1891 aList.emplace_back( _( "Type" ), GetFriendlyName() );
1892
1893 GetMsgPanelInfoBase_Common( aFrame, aList );
1894
1895 aList.emplace_back( _( "Layer" ), layerMaskDescribe() );
1896
1897 aList.emplace_back( _( "Width" ), aFrame->MessageTextFromValue( m_width ) );
1898
1899 if( Type() == PCB_ARC_T )
1900 {
1901 double radius = static_cast<PCB_ARC*>( this )->GetRadius();
1902 aList.emplace_back( _( "Radius" ), aFrame->MessageTextFromValue( radius ) );
1903 }
1904
1905 double segmentLength = GetLength();
1906 double segmentDelay = GetDelay();
1907
1908 if( segmentDelay == 0.0 )
1909 {
1910 aList.emplace_back( _( "Segment Length" ), aFrame->MessageTextFromValue( segmentLength ) );
1911 }
1912 else
1913 {
1914 aList.emplace_back( _( "Segment Delay" ),
1915 aFrame->MessageTextFromValue( segmentDelay, true, EDA_DATA_TYPE::TIME ) );
1916 }
1917
1918 // Display full track length (in Pcbnew)
1919 if( board && GetNetCode() > 0 )
1920 {
1921 int count = 0;
1922 double trackLen = 0.0;
1923 double lenPadToDie = 0.0;
1924 double trackDelay = 0.0;
1925 double delayPadToDie = 0.0;
1926
1927 std::tie( count, trackLen, lenPadToDie, trackDelay, delayPadToDie ) = board->GetTrackLength( *this );
1928
1929 if( trackDelay == 0.0 )
1930 {
1931 aList.emplace_back( _( "Routed Length" ), aFrame->MessageTextFromValue( trackLen ) );
1932
1933 if( lenPadToDie != 0 )
1934 {
1935 msg = aFrame->MessageTextFromValue( lenPadToDie );
1936 aList.emplace_back( _( "Pad To Die Length" ), msg );
1937
1938 msg = aFrame->MessageTextFromValue( trackLen + lenPadToDie );
1939 aList.emplace_back( _( "Full Length" ), msg );
1940 }
1941 }
1942 else
1943 {
1944 aList.emplace_back( _( "Routed Delay" ),
1945 aFrame->MessageTextFromValue( trackDelay, true, EDA_DATA_TYPE::TIME ) );
1946
1947 if( delayPadToDie != 0.0 )
1948 {
1949 msg = aFrame->MessageTextFromValue( delayPadToDie, true, EDA_DATA_TYPE::TIME );
1950 aList.emplace_back( _( "Pad To Die Delay" ), msg );
1951
1952 msg = aFrame->MessageTextFromValue( trackDelay + delayPadToDie, true, EDA_DATA_TYPE::TIME );
1953 aList.emplace_back( _( "Full Delay" ), msg );
1954 }
1955 }
1956 }
1957
1958 SHAPE_POLY_SET copper;
1960 aList.emplace_back( _( "Copper Area" ),
1961 aFrame->MessageTextFromValue( copper.Area(), true, EDA_DATA_TYPE::AREA ) );
1962
1963 wxString source;
1964 int clearance = GetOwnClearance( GetLayer(), &source );
1965
1966 aList.emplace_back( wxString::Format( _( "Min Clearance: %s" ),
1967 aFrame->MessageTextFromValue( clearance ) ),
1968 wxString::Format( _( "(from %s)" ), source ) );
1969
1970 MINOPTMAX<int> constraintValue = GetWidthConstraint( &source );
1971 msg = aFrame->MessageTextFromMinOptMax( constraintValue );
1972
1973 if( !msg.IsEmpty() )
1974 {
1975 aList.emplace_back( wxString::Format( _( "Width Constraints: %s" ), msg ),
1976 wxString::Format( _( "(from %s)" ), source ) );
1977 }
1978}
1979
1980
1981void PCB_VIA::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1982{
1983 wxString msg;
1984
1985 switch( GetViaType() )
1986 {
1987 case VIATYPE::MICROVIA: msg = _( "Micro Via" ); break;
1988 case VIATYPE::BLIND: msg = _( "Blind Via" ); break;
1989 case VIATYPE::BURIED: msg = _( "Buried Via" ); break;
1990 case VIATYPE::THROUGH: msg = _( "Through Via" ); break;
1991 default: msg = _( "Via" ); break;
1992 }
1993
1994 aList.emplace_back( _( "Type" ), msg );
1995
1996 GetMsgPanelInfoBase_Common( aFrame, aList );
1997
1998 aList.emplace_back( _( "Layer" ), layerMaskDescribe() );
1999 // TODO(JE) padstacks
2000 aList.emplace_back( _( "Diameter" ),
2002 aList.emplace_back( _( "Hole" ), aFrame->MessageTextFromValue( GetDrillValue() ) );
2003
2004 wxString source;
2005 int clearance = GetOwnClearance( GetLayer(), &source );
2006
2007 aList.emplace_back( wxString::Format( _( "Min Clearance: %s" ),
2008 aFrame->MessageTextFromValue( clearance ) ),
2009 wxString::Format( _( "(from %s)" ), source ) );
2010
2011 int minAnnulus = GetMinAnnulus( GetLayer(), &source );
2012
2013 aList.emplace_back( wxString::Format( _( "Min Annular Width: %s" ),
2014 aFrame->MessageTextFromValue( minAnnulus ) ),
2015 wxString::Format( _( "(from %s)" ), source ) );
2016}
2017
2018
2020 std::vector<MSG_PANEL_ITEM>& aList ) const
2021{
2022 aList.emplace_back( _( "Net" ), UnescapeString( GetNetname() ) );
2023
2024 aList.emplace_back( _( "Resolved Netclass" ),
2025 UnescapeString( GetEffectiveNetClass()->GetHumanReadableName() ) );
2026
2027#if 0 // Enable for debugging
2028 if( GetBoard() )
2029 aList.emplace_back( _( "NetCode" ), fmt::format( "{}", GetNetCode() ) );
2030
2031 aList.emplace_back( wxT( "Flags" ), fmt::format( "#08X", m_flags ) );
2032
2033 aList.emplace_back( wxT( "Start pos" ), fmt::format( "{} {}", m_Start.x, m_Start.y ) );
2034 aList.emplace_back( wxT( "End pos" ), fmt::format( "{} {}", m_End.x, m_End.y ) );
2035#endif
2036
2037 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME && IsLocked() )
2038 aList.emplace_back( _( "Status" ), _( "Locked" ) );
2039}
2040
2041
2043{
2044 const BOARD* board = GetBoard();
2045 PCB_LAYER_ID top_layer;
2046 PCB_LAYER_ID bottom_layer;
2047
2048 LayerPair( &top_layer, &bottom_layer );
2049
2050 return board->GetLayerName( top_layer ) + wxT( " - " ) + board->GetLayerName( bottom_layer );
2051}
2052
2053
2054bool PCB_TRACK::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
2055{
2056 return TestSegmentHit( aPosition, m_Start, m_End, aAccuracy + ( m_width / 2 ) );
2057}
2058
2059
2060bool PCB_ARC::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
2061{
2062 double max_dist = aAccuracy + ( GetWidth() / 2.0 );
2063
2064 // Short-circuit common cases where the arc is connected to a track or via at an endpoint
2065 if( GetStart().Distance( aPosition ) <= max_dist || GetEnd().Distance( aPosition ) <= max_dist )
2066 {
2067 return true;
2068 }
2069
2071 VECTOR2L relpos = aPosition - center;
2072 int64_t dist = relpos.EuclideanNorm();
2073 double radius = GetRadius();
2074
2075 if( std::abs( dist - radius ) > max_dist )
2076 return false;
2077
2078 EDA_ANGLE arc_angle = GetAngle();
2079 EDA_ANGLE arc_angle_start = GetArcAngleStart(); // Always 0.0 ... 360 deg
2080 EDA_ANGLE arc_hittest( relpos );
2081
2082 // Calculate relative angle between the starting point of the arc, and the test point
2083 arc_hittest -= arc_angle_start;
2084
2085 // Normalise arc_hittest between 0 ... 360 deg
2086 arc_hittest.Normalize();
2087
2088 if( arc_angle < ANGLE_0 )
2089 return arc_hittest >= ANGLE_360 + arc_angle;
2090
2091 return arc_hittest <= arc_angle;
2092}
2093
2094
2095bool PCB_VIA::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
2096{
2097 bool hit = false;
2098
2100 [&]( PCB_LAYER_ID aLayer )
2101 {
2102 if( hit )
2103 return;
2104
2105 int max_dist = aAccuracy + ( GetWidth( aLayer ) / 2 );
2106
2107 // rel_pos is aPosition relative to m_Start (or the center of the via)
2108 VECTOR2D rel_pos = aPosition - m_Start;
2109 double dist = rel_pos.x * rel_pos.x + rel_pos.y * rel_pos.y;
2110
2111 if( dist <= static_cast<double>( max_dist ) * max_dist )
2112 hit = true;
2113 } );
2114
2115 return hit;
2116}
2117
2118
2119bool PCB_TRACK::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
2120{
2121 BOX2I arect = aRect;
2122 arect.Inflate( aAccuracy );
2123
2124 if( aContained )
2125 return arect.Contains( GetStart() ) && arect.Contains( GetEnd() );
2126 else
2127 return arect.Intersects( GetStart(), GetEnd() );
2128}
2129
2130
2131bool PCB_ARC::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
2132{
2133 BOX2I arect = aRect;
2134 arect.Inflate( aAccuracy );
2135
2136 BOX2I box( GetStart() );
2137 box.Merge( GetMid() );
2138 box.Merge( GetEnd() );
2139
2140 box.Inflate( GetWidth() / 2 );
2141
2142 if( aContained )
2143 return arect.Contains( box );
2144 else
2145 return arect.Intersects( box );
2146}
2147
2148
2149bool PCB_VIA::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
2150{
2151 BOX2I arect = aRect;
2152 arect.Inflate( aAccuracy );
2153
2154 bool hit = false;
2155
2157 [&]( PCB_LAYER_ID aLayer )
2158 {
2159 if( hit )
2160 return;
2161
2162 BOX2I box( GetStart() );
2163 box.Inflate( GetWidth( aLayer ) / 2 );
2164
2165 if( aContained )
2166 hit = arect.Contains( box );
2167 else
2168 hit = arect.IntersectsCircle( GetStart(), GetWidth( aLayer ) / 2 );
2169 } );
2170
2171 return hit;
2172}
2173
2174
2175bool PCB_TRACK::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
2176{
2177 return KIGEOM::ShapeHitTest( aPoly, *GetEffectiveShape(), aContained );
2178}
2179
2180
2181wxString PCB_TRACK::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
2182{
2183 return wxString::Format( Type() == PCB_ARC_T ? _("Track (arc) %s on %s, length %s" )
2184 : _("Track %s on %s, length %s" ),
2185 GetNetnameMsg(),
2186 GetLayerName(),
2187 aUnitsProvider->MessageTextFromValue( GetLength() ) );
2188}
2189
2190
2192{
2193 return BITMAPS::add_tracks;
2194}
2195
2197{
2198 assert( aImage->Type() == PCB_TRACE_T );
2199
2200 std::swap( *((PCB_TRACK*) this), *((PCB_TRACK*) aImage) );
2201}
2202
2204{
2205 assert( aImage->Type() == PCB_ARC_T );
2206
2207 std::swap( *this, *static_cast<PCB_ARC*>( aImage ) );
2208}
2209
2211{
2212 assert( aImage->Type() == PCB_VIA_T );
2213
2214 std::swap( *((PCB_VIA*) this), *((PCB_VIA*) aImage) );
2215}
2216
2217
2223
2224
2226{
2227 auto center = CalcArcCenter( m_Start, m_Mid , m_End );
2228 return std::min( center.Distance( m_Start ), (double) INT_MAX / 2.0 );
2229}
2230
2231
2233{
2235 EDA_ANGLE angle1 = EDA_ANGLE( m_Mid - center ) - EDA_ANGLE( m_Start - center );
2236 EDA_ANGLE angle2 = EDA_ANGLE( m_End - center ) - EDA_ANGLE( m_Mid - center );
2237
2238 return angle1.Normalize180() + angle2.Normalize180();
2239}
2240
2241
2243{
2244 VECTOR2D pos( GetPosition() );
2245 EDA_ANGLE angleStart( m_Start - pos );
2246
2247 return angleStart.Normalize();
2248}
2249
2250
2251// Note: used in python tests. Ignore CLion's claim that it's unused....
2253{
2254 VECTOR2D pos( GetPosition() );
2255 EDA_ANGLE angleEnd( m_End - pos );
2256
2257 return angleEnd.Normalize();
2258}
2259
2260bool PCB_ARC::IsDegenerated( int aThreshold ) const
2261{
2262 // We have lots of code that will blow up if the radius overflows an int.
2263 if( GetRadius() >= (double)INT_MAX/2.0 )
2264 return true;
2265
2266 // Too small arcs cannot be really handled: arc center (and arc radius)
2267 // cannot be safely computed if the distance between mid and end points
2268 // is too small (a few internal units)
2269
2270 // len of both segments must be < aThreshold to be a very small degenerated arc
2271 return ( GetMid() - GetStart() ).EuclideanNorm() < aThreshold
2272 && ( GetMid() - GetEnd() ).EuclideanNorm() < aThreshold;
2273}
2274
2275
2277{
2278 if( a->GetNetCode() != b->GetNetCode() )
2279 return a->GetNetCode() < b->GetNetCode();
2280
2281 if( a->GetLayer() != b->GetLayer() )
2282 return a->GetLayer() < b->GetLayer();
2283
2284 if( a->Type() != b->Type() )
2285 return a->Type() < b->Type();
2286
2287 if( a->m_Uuid != b->m_Uuid )
2288 return a->m_Uuid < b->m_Uuid;
2289
2290 return a < b;
2291}
2292
2293
2294std::shared_ptr<SHAPE> PCB_TRACK::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
2295{
2296 int width = m_width;
2297
2298 if( IsSolderMaskLayer( aLayer ) )
2299 width += 2 * GetSolderMaskExpansion();
2300
2301 return std::make_shared<SHAPE_SEGMENT>( m_Start, m_End, width );
2302}
2303
2304
2305std::shared_ptr<SHAPE> PCB_VIA::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
2306{
2307 if( aFlash == FLASHING::ALWAYS_FLASHED
2308 || ( aFlash == FLASHING::DEFAULT && FlashLayer( aLayer ) ) )
2309 {
2310 int width = 0;
2311
2312 if( aLayer == UNDEFINED_LAYER )
2313 {
2314 Padstack().ForEachUniqueLayer(
2315 [&]( PCB_LAYER_ID layer )
2316 {
2317 width = std::max( width, GetWidth( layer ) );
2318 } );
2319
2320 width /= 2;
2321 }
2322 else
2323 {
2324 PCB_LAYER_ID cuLayer = m_padStack.EffectiveLayerFor( aLayer );
2325 width = GetWidth( cuLayer ) / 2;
2326 }
2327
2328 return std::make_shared<SHAPE_CIRCLE>( m_Start, width );
2329 }
2330 else
2331 {
2332 return std::make_shared<SHAPE_CIRCLE>( m_Start, GetDrillValue() / 2 );
2333 }
2334}
2335
2336
2337std::shared_ptr<SHAPE> PCB_ARC::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
2338{
2339 int width = GetWidth();
2340
2341 if( IsSolderMaskLayer( aLayer ) )
2342 width += 2 * GetSolderMaskExpansion();
2343
2344 SHAPE_ARC arc( GetStart(), GetMid(), GetEnd(), width );
2345
2346 if( arc.IsEffectiveLine() )
2347 return std::make_shared<SHAPE_SEGMENT>( GetStart(), GetEnd(), width );
2348
2349 return std::make_shared<SHAPE_ARC>( arc );
2350}
2351
2352
2354 int aClearance, int aError, ERROR_LOC aErrorLoc,
2355 bool ignoreLineWidth ) const
2356{
2357 wxASSERT_MSG( !ignoreLineWidth, wxT( "IgnoreLineWidth has no meaning for tracks." ) );
2358
2359
2360 switch( Type() )
2361 {
2362 case PCB_VIA_T:
2363 {
2364 int radius = ( static_cast<const PCB_VIA*>( this )->GetWidth( aLayer ) / 2 ) + aClearance;
2365 TransformCircleToPolygon( aBuffer, m_Start, radius, aError, aErrorLoc );
2366 break;
2367 }
2368
2369 case PCB_ARC_T:
2370 {
2371 const PCB_ARC* arc = static_cast<const PCB_ARC*>( this );
2372 int width = m_width + ( 2 * aClearance );
2373
2374 if( IsSolderMaskLayer( aLayer ) )
2375 width += 2 * GetSolderMaskExpansion();
2376
2377 TransformArcToPolygon( aBuffer, arc->GetStart(), arc->GetMid(), arc->GetEnd(), width,
2378 aError, aErrorLoc );
2379 break;
2380 }
2381
2382 default:
2383 {
2384 int width = m_width + ( 2 * aClearance );
2385
2386 if( IsSolderMaskLayer( aLayer ) )
2387 width += 2 * GetSolderMaskExpansion();
2388
2389 TransformOvalToPolygon( aBuffer, m_Start, m_End, width, aError, aErrorLoc );
2390
2391 break;
2392 }
2393 }
2394}
2395
2396
2397static struct TRACK_VIA_DESC
2398{
2400 {
2401 // clang-format off: the suggestion is less readable
2403 .Undefined( VIATYPE::NOT_DEFINED )
2404 .Map( VIATYPE::THROUGH, _HKI( "Through" ) )
2405 .Map( VIATYPE::BLIND, _HKI( "Blind" ) )
2406 .Map( VIATYPE::BURIED, _HKI( "Buried" ) )
2407 .Map( VIATYPE::MICROVIA, _HKI( "Micro" ) );
2408
2410 .Undefined( TENTING_MODE::FROM_RULES )
2411 .Map( TENTING_MODE::FROM_RULES, _HKI( "From design rules" ) )
2412 .Map( TENTING_MODE::TENTED, _HKI( "Tented" ) )
2413 .Map( TENTING_MODE::NOT_TENTED, _HKI( "Not tented" ) );
2414
2416 .Undefined( COVERING_MODE::FROM_RULES )
2417 .Map( COVERING_MODE::FROM_RULES, _HKI( "From design rules" ) )
2418 .Map( COVERING_MODE::COVERED, _HKI( "Covered" ) )
2419 .Map( COVERING_MODE::NOT_COVERED, _HKI( "Not covered" ) );
2420
2422 .Undefined( PLUGGING_MODE::FROM_RULES )
2423 .Map( PLUGGING_MODE::FROM_RULES, _HKI( "From design rules" ) )
2424 .Map( PLUGGING_MODE::PLUGGED, _HKI( "Plugged" ) )
2425 .Map( PLUGGING_MODE::NOT_PLUGGED, _HKI( "Not plugged" ) );
2426
2428 .Undefined( CAPPING_MODE::FROM_RULES )
2429 .Map( CAPPING_MODE::FROM_RULES, _HKI( "From design rules" ) )
2430 .Map( CAPPING_MODE::CAPPED, _HKI( "Capped" ) )
2431 .Map( CAPPING_MODE::NOT_CAPPED, _HKI( "Not capped" ) );
2432
2434 .Undefined( FILLING_MODE::FROM_RULES )
2435 .Map( FILLING_MODE::FROM_RULES, _HKI( "From design rules" ) )
2436 .Map( FILLING_MODE::FILLED, _HKI( "Filled" ) )
2437 .Map( FILLING_MODE::NOT_FILLED, _HKI( "Not filled" ) );
2438 // clang-format on: the suggestion is less readable
2439
2441
2442 if( layerEnum.Choices().GetCount() == 0 )
2443 {
2444 layerEnum.Undefined( UNDEFINED_LAYER );
2445
2446 for( PCB_LAYER_ID layer : LSET::AllLayersMask() )
2447 layerEnum.Map( layer, LSET::Name( layer ) );
2448 }
2449
2450 auto viaDiameterPropertyValidator =
2451 []( const wxAny&& aValue, EDA_ITEM* aItem ) -> VALIDATOR_RESULT
2452 {
2453 if( !aItem || aItem->Type() != PCB_VIA_T )
2454 return std::nullopt;
2455
2456 if( !aValue.CheckType<int>() )
2457 return std::nullopt;
2458
2459 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
2460
2461 std::optional<int> diameter = aValue.As<int>();
2462 std::optional<int> drill = via->GetDrillValue();
2463
2464 if( std::optional<PCB_VIA::VIA_PARAMETER_ERROR> error =
2465 PCB_VIA::ValidateViaParameters( diameter, drill ) )
2466 {
2467 return std::make_unique<VALIDATION_ERROR_MSG>( error->m_Message );
2468 }
2469
2470 return std::nullopt;
2471 };
2472
2473 auto viaDrillPropertyValidator =
2474 []( const wxAny&& aValue, EDA_ITEM* aItem ) -> VALIDATOR_RESULT
2475 {
2476 if( !aItem || aItem->Type() != PCB_VIA_T )
2477 return std::nullopt;
2478
2479 if( !aValue.CheckType<int>() )
2480 return std::nullopt;
2481
2482 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
2483
2484 std::optional<int> diameter = via->GetFrontWidth();
2485 std::optional<int> drill = aValue.As<int>();
2486
2487 if( std::optional<PCB_VIA::VIA_PARAMETER_ERROR> error =
2488 PCB_VIA::ValidateViaParameters( diameter, drill ) )
2489 {
2490 return std::make_unique<VALIDATION_ERROR_MSG>( error->m_Message );
2491 }
2492
2493 return std::nullopt;
2494 };
2495
2496 auto viaStartLayerPropertyValidator =
2497 []( const wxAny&& aValue, EDA_ITEM* aItem ) -> VALIDATOR_RESULT
2498 {
2499 if( !aItem || aItem->Type() != PCB_VIA_T )
2500 return std::nullopt;
2501
2502 PCB_LAYER_ID layer;
2503
2504 if( aValue.CheckType<PCB_LAYER_ID>() )
2505 layer = aValue.As<PCB_LAYER_ID>();
2506 else if( aValue.CheckType<int>() )
2507 layer = static_cast<PCB_LAYER_ID>( aValue.As<int>() );
2508 else
2509 return std::nullopt;
2510
2511 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
2512
2513 if( std::optional<PCB_VIA::VIA_PARAMETER_ERROR> error =
2514 PCB_VIA::ValidateViaParameters( std::nullopt, std::nullopt,
2515 layer, via->BottomLayer() ) )
2516 {
2517 return std::make_unique<VALIDATION_ERROR_MSG>( error->m_Message );
2518 }
2519
2520 return std::nullopt;
2521 };
2522
2523 auto viaEndLayerPropertyValidator =
2524 []( const wxAny&& aValue, EDA_ITEM* aItem ) -> VALIDATOR_RESULT
2525 {
2526 if( !aItem || aItem->Type() != PCB_VIA_T )
2527 return std::nullopt;
2528
2529 PCB_LAYER_ID layer;
2530
2531 if( aValue.CheckType<PCB_LAYER_ID>() )
2532 layer = aValue.As<PCB_LAYER_ID>();
2533 else if( aValue.CheckType<int>() )
2534 layer = static_cast<PCB_LAYER_ID>( aValue.As<int>() );
2535 else
2536 return std::nullopt;
2537
2538 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
2539
2540 if( std::optional<PCB_VIA::VIA_PARAMETER_ERROR> error =
2541 PCB_VIA::ValidateViaParameters( std::nullopt, std::nullopt,
2542 via->TopLayer(), layer ) )
2543 {
2544 return std::make_unique<VALIDATION_ERROR_MSG>( error->m_Message );
2545 }
2546
2547 return std::nullopt;
2548 };
2549
2551
2552 // Track
2555
2556 propMgr.AddProperty( new PROPERTY<PCB_TRACK, int>( _HKI( "Width" ),
2558 propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Position X" ),
2559 new PROPERTY<PCB_TRACK, int>( _HKI( "Start X" ),
2562 propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Position Y" ),
2563 new PROPERTY<PCB_TRACK, int>( _HKI( "Start Y" ),
2566 propMgr.AddProperty( new PROPERTY<PCB_TRACK, int>( _HKI( "End X" ),
2569 propMgr.AddProperty( new PROPERTY<PCB_TRACK, int>( _HKI( "End Y" ),
2572
2573 const wxString groupTechLayers = _HKI( "Technical Layers" );
2574
2575 auto isExternalLayerTrack =
2576 []( INSPECTABLE* aItem )
2577 {
2578 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( aItem ) )
2579 return IsExternalCopperLayer( track->GetLayer() );
2580
2581 return false;
2582 };
2583
2584 propMgr.AddProperty( new PROPERTY<PCB_TRACK, bool>( _HKI( "Soldermask" ),
2586 .SetAvailableFunc( isExternalLayerTrack );
2587 propMgr.AddProperty( new PROPERTY<PCB_TRACK, std::optional<int>>( _HKI( "Soldermask Margin Override" ),
2589 PROPERTY_DISPLAY::PT_SIZE ), groupTechLayers )
2590 .SetAvailableFunc( isExternalLayerTrack );
2591
2592 // Arc
2595
2596 // Via
2599
2600 // TODO test drill, use getdrillvalue?
2601 const wxString groupVia = _HKI( "Via Properties" );
2602
2603 propMgr.Mask( TYPE_HASH( PCB_VIA ), TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Layer" ) );
2604
2605 // clang-format off: the suggestion is less readable
2606 propMgr.AddProperty( new PROPERTY<PCB_VIA, int>( _HKI( "Diameter" ),
2608 .SetValidator( viaDiameterPropertyValidator );
2609 propMgr.AddProperty( new PROPERTY<PCB_VIA, int>( _HKI( "Hole" ),
2611 .SetValidator( viaDrillPropertyValidator );
2612 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, PCB_LAYER_ID>( _HKI( "Layer Top" ),
2614 .SetValidator( viaStartLayerPropertyValidator );
2615 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, PCB_LAYER_ID>( _HKI( "Layer Bottom" ),
2617 .SetValidator( viaEndLayerPropertyValidator );
2618 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, VIATYPE>( _HKI( "Via Type" ),
2620 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, TENTING_MODE>( _HKI( "Front tenting" ),
2622 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, TENTING_MODE>( _HKI( "Back tenting" ),
2624 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, COVERING_MODE>( _HKI( "Front covering" ),
2626 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, COVERING_MODE>( _HKI( "Back covering" ),
2628 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, PLUGGING_MODE>( _HKI( "Front plugging" ),
2630 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, PLUGGING_MODE>( _HKI( "Back plugging" ),
2632 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, CAPPING_MODE>( _HKI( "Capping" ),
2634 propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, FILLING_MODE>( _HKI( "Filling" ),
2636 // clang-format on: the suggestion is less readable
2637 }
2639
types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
Definition api_enums.cpp:96
KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
Definition api_enums.cpp:35
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
@ ERROR_INSIDE
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
constexpr int ARC_LOW_DEF
Definition base_units.h:128
BITMAPS
A list of all bitmap identifiers.
ZONE_LAYER_OVERRIDE
Conditionally flashed vias and pads that interact with zones of different priority can be very squirr...
Definition board_item.h:67
@ ZLO_NONE
Definition board_item.h:68
@ ZLO_FORCE_FLASHED
Definition board_item.h:69
constexpr BOX2I BOX2ISafe(const BOX2D &aInput)
Definition box2.h:929
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
BASE_SET & set(size_t pos)
Definition base_set.h:116
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
virtual NETCLASS * GetEffectiveNetClass() const
Return the NETCLASS for this item.
BOARD_CONNECTED_ITEM(BOARD_ITEM *aParent, KICAD_T idtype)
void PackNet(kiapi::board::types::Net *aProto) const
const wxString & GetDisplayNetname() const
virtual int GetOwnClearance(PCB_LAYER_ID aLayer, wxString *aSource=nullptr) const
Return an item's "own" clearance in internal units.
void UnpackNet(const kiapi::board::types::Net &aProto)
Assigns a net to this item from an API message.
Container for design settings for a BOARD object.
std::shared_ptr< DRC_ENGINE > m_DRCEngine
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:79
BOARD_ITEM(BOARD_ITEM *aParent, KICAD_T idtype, PCB_LAYER_ID aLayer=F_Cu)
Definition board_item.h:81
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition board_item.h:232
virtual void TransformShapeToPolySet(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc) const
Convert the item shape to a polyset.
Definition board_item.h:425
void SetLocked(bool aLocked) override
Definition board_item.h:323
PCB_LAYER_ID m_layer
Definition board_item.h:453
bool IsLocked() const override
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition board_item.h:280
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
BOARD_ITEM_CONTAINER * GetParent() const
Definition board_item.h:210
virtual int BoardCopperLayerCount() const
Return the total number of copper layers for the board that this item resides on.
virtual wxString layerMaskDescribe() const
Return a string (to be shown to the user) describing a layer mask.
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:322
LENGTH_DELAY_CALCULATION * GetLengthCalculation() const
Returns the track length calculator.
Definition board.h:1359
std::tuple< int, double, double, double, double > GetTrackLength(const PCB_TRACK &aTrack) const
Return data on the length and number of track segments connected to a given track.
Definition board.cpp:2653
const LSET & GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
Definition board.cpp:938
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayer) const
Definition board.cpp:869
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition board.cpp:692
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1041
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:924
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition board.h:538
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:558
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:658
bool IntersectsCircle(const Vec &aCenter, const int aRadius) const
Definition box2.h:504
constexpr coord_type GetLeft() const
Definition box2.h:228
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:168
constexpr coord_type GetRight() const
Definition box2.h:217
constexpr coord_type GetTop() const
Definition box2.h:229
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:311
constexpr coord_type GetBottom() const
Definition box2.h:222
bool IsConnectedOnLayer(const BOARD_CONNECTED_ITEM *aItem, int aLayer, const std::initializer_list< KICAD_T > &aTypes={}) const
wxString GetName() const
Definition drc_rule.h:174
MINOPTMAX< int > & Value()
Definition drc_rule.h:167
MINOPTMAX< int > m_Value
Definition drc_rule.h:208
DRC_CONSTRAINT EvalRules(DRC_CONSTRAINT_T aConstraintType, const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
EDA_ANGLE Normalize()
Definition eda_angle.h:229
EDA_ANGLE Normalize180()
Definition eda_angle.h:268
The base class for create windows for drawing purpose.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
EDA_ITEM & operator=(const EDA_ITEM &aItem)
Assign the members of aItem to another object.
Definition eda_item.cpp:328
const KIID m_Uuid
Definition eda_item.h:516
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
EDA_ITEM_FLAGS m_flags
Definition eda_item.h:527
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:39
ENUM_MAP & Map(T aValue, const wxString &aName)
Definition property.h:727
static ENUM_MAP< T > & Instance()
Definition property.h:721
ENUM_MAP & Undefined(T aValue)
Definition property.h:734
wxPGChoices & Choices()
Definition property.h:770
Class that other classes need to inherit from, in order to be inspectable.
Definition inspectable.h:37
Contains methods for drawing PCB-specific items.
virtual PCB_RENDER_SETTINGS * GetSettings() override
Return a pointer to current settings that are going to be used when drawing items.
PCB specific render settings.
Definition pcb_painter.h:82
PCB_LAYER_ID GetPrimaryHighContrastLayer() const
Return the board layer which is in high-contrast mode.
static double lodScaleForThreshold(const KIGFX::VIEW *aView, int aWhatIu, int aThresholdIu)
Get the scale at which aWhatIu would be drawn at the same size as aThresholdIu on screen.
Definition view_item.cpp:39
static constexpr double LOD_HIDE
Return this constant from ViewGetLOD() to hide the item unconditionally.
Definition view_item.h:180
static constexpr double LOD_SHOW
Return this constant from ViewGetLOD() to show the item unconditionally.
Definition view_item.h:185
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:66
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition view.cpp:530
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition view.h:422
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition view.h:220
Definition kiid.h:49
static bool Contains(int aStart_layer, int aEnd_layer, int aTest_layer)
Class which calculates lengths (and associated routing statistics) in a BOARD context.
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.
LENGTH_DELAY_CALCULATION_ITEM GetLengthCalculationItem(const BOARD_CONNECTED_ITEM *aBoardItem) const
Return a LENGTH_CALCULATION_ITEM constructed from the given BOARD_CONNECTED_ITEM.
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
void RunOnLayers(const std::function< void(PCB_LAYER_ID)> &aFunction) const
Execute a function on each layer of the LSET.
Definition lset.h:252
static const LSET & BackTechMask()
Return a mask holding all technical layers (no CU layer) on back side.
Definition lset.cpp:631
static const LSET & AllLayersMask()
Definition lset.cpp:624
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:591
static const LSET & PhysicalLayersMask()
Return a mask holding all layers which are physically realized.
Definition lset.cpp:680
static wxString Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition lset.cpp:188
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
Definition lset.h:63
static const LSET & FrontTechMask()
Return a mask holding all technical layers (no CU layer) on front side.
Definition lset.cpp:645
T Min() const
Definition minoptmax.h:33
bool HasMin() const
Definition minoptmax.h:37
T Opt() const
Definition minoptmax.h:35
bool HasOpt() const
Definition minoptmax.h:39
A collection of nets and the parameters used to route or test these nets.
Definition netclass.h:45
int GetViaDrill() const
Definition netclass.h:141
int GetuViaDrill() const
Definition netclass.h:157
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition netinfo.h:365
A PADSTACK defines the characteristics of a single or multi-layer pad, in the IPC sense of the word.
Definition padstack.h:125
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
DRILL_PROPS & Drill()
Definition padstack.h:308
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Definition padstack.cpp:414
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition padstack.h:145
virtual VECTOR2I GetPosition() const override
bool IsDegenerated(int aThreshold=5) const
virtual void swapData(BOARD_ITEM *aImage) override
bool IsCCW() const
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition pcb_track.cpp:93
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
EDA_ANGLE GetArcAngleStart() const
void Mirror(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Mirror this object relative to a given horizontal axis the layer is not changed.
virtual bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
EDA_ANGLE GetArcAngleEnd() const
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
void SetMid(const VECTOR2I &aMid)
Definition pcb_track.h:346
double GetRadius() const
EDA_ANGLE GetAngle() const
const VECTOR2I & GetMid() const
Definition pcb_track.h:347
PCB_ARC(BOARD_ITEM *aParent)
Definition pcb_track.h:320
double Similarity(const BOARD_ITEM &aOther) const override
Return a measure of how likely the other object is to represent the same object.
VECTOR2I m_Mid
Arc mid point, halfway between start and end.
Definition pcb_track.h:411
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
bool operator==(const PCB_ARC &aOther) const
void CopyFrom(const BOARD_ITEM *aOther) override
Definition pcb_track.cpp:99
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
virtual void SetLayerSet(const LSET &aLayers) override
int GetSolderMaskExpansion() const
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
void SetEndY(int aY)
Definition pcb_track.h:163
void SetHasSolderMask(bool aVal)
Definition pcb_track.h:177
virtual double GetLength() const
Get the length of the track using the hypotenuse calculation.
double ViewGetLOD(int aLayer, const KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
virtual void swapData(BOARD_ITEM *aImage) override
void SetEnd(const VECTOR2I &aEnd)
Definition pcb_track.h:150
bool HasSolderMask() const
Definition pcb_track.h:178
void SetStart(const VECTOR2I &aStart)
Definition pcb_track.h:153
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
int GetStartY() const
Definition pcb_track.h:160
int GetEndX() const
Definition pcb_track.h:165
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
virtual void Mirror(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Mirror this object relative to a given horizontal axis the layer is not changed.
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
INSPECT_RESULT Visit(INSPECTOR inspector, void *testData, const std::vector< KICAD_T > &aScanTypes) override
May be re-implemented for each derived class in order to handle all the types given by its member dat...
bool ApproxCollinear(const PCB_TRACK &aTrack)
VECTOR2I m_End
Line end point.
Definition pcb_track.h:307
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
Definition pcb_track.h:180
std::optional< int > m_solderMaskMargin
Definition pcb_track.h:310
void CopyFrom(const BOARD_ITEM *aOther) override
Definition pcb_track.cpp:77
std::optional< int > GetLocalSolderMaskMargin() const
Definition pcb_track.h:181
virtual double GetDelay() const
Get the time delay of the track.
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
virtual EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition pcb_track.cpp:71
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Convert the track shape to a closed polygon.
const VECTOR2I & GetStart() const
Definition pcb_track.h:154
virtual bool operator==(const BOARD_ITEM &aOther) const override
VECTOR2I m_Start
Line start point.
Definition pcb_track.h:306
int GetEndY() const
Definition pcb_track.h:166
wxString GetFriendlyName() const override
virtual std::vector< int > ViewGetLayers() const override
Return the all the layers within the VIEW the object is painted on.
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
virtual double Similarity(const BOARD_ITEM &aOther) const override
Return a measure of how likely the other object is to represent the same object.
bool m_hasSolderMask
Definition pcb_track.h:309
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
void SetStartX(int aX)
Definition pcb_track.h:156
const VECTOR2I & GetEnd() const
Definition pcb_track.h:151
PCB_TRACK(BOARD_ITEM *aParent, KICAD_T idtype=PCB_TRACE_T)
Definition pcb_track.cpp:63
void SetStartY(int aY)
Definition pcb_track.h:157
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
virtual MINOPTMAX< int > GetWidthConstraint(wxString *aSource=nullptr) const
void SetEndX(int aX)
Definition pcb_track.h:162
int GetStartX() const
Definition pcb_track.h:159
int m_width
Thickness of track (or arc) – no longer the width of a via.
Definition pcb_track.h:313
EDA_ITEM_FLAGS IsPointOnEnds(const VECTOR2I &point, int min_dist=0) const
Return STARTPOINT if point if near (dist = min_dist) start point, ENDPOINT if point if near (dist = m...
virtual void SetWidth(int aWidth)
Definition pcb_track.h:147
virtual int GetWidth() const
Definition pcb_track.h:148
void GetMsgPanelInfoBase_Common(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) const
PCB_LAYER_ID BottomLayer() const
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
PLUGGING_MODE GetFrontPluggingMode() const
VECTOR2I GetPosition() const override
Definition pcb_track.h:586
bool IsTented(PCB_LAYER_ID aLayer) const override
Checks if the given object is tented (its copper shape is covered by solder mask) on a given side of ...
void CopyFrom(const BOARD_ITEM *aOther) override
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
void SetCappingMode(CAPPING_MODE aMode)
void SetFrontCoveringMode(COVERING_MODE aMode)
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
COVERING_MODE GetBackCoveringMode() const
bool FlashLayer(int aLayer) const
Check to see whether the via should have a pad on the specific layer.
static std::optional< VIA_PARAMETER_ERROR > ValidateViaParameters(std::optional< int > aDiameter, std::optional< int > aDrill, std::optional< PCB_LAYER_ID > aStartLayer=std::nullopt, std::optional< PCB_LAYER_ID > aEndLayer=std::nullopt)
void SetDrillDefault()
Set the drill value for vias to the default value UNDEFINED_DRILL_DIAMETER.
Definition pcb_track.h:721
std::map< PCB_LAYER_ID, ZONE_LAYER_OVERRIDE > m_zoneLayerOverrides
Definition pcb_track.h:770
void ClearZoneLayerOverrides()
CAPPING_MODE GetCappingMode() const
const PADSTACK & Padstack() const
Definition pcb_track.h:463
void SetFrontTentingMode(TENTING_MODE aMode)
bool m_isFree
"Free" vias don't get their nets auto-updated
Definition pcb_track.h:767
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
bool IsBlindVia() const
TENTING_MODE GetFrontTentingMode() const
void SetBottomLayer(PCB_LAYER_ID aLayer)
int GetSolderMaskExpansion() const
void SetDrill(int aDrill)
Set the drill value for vias.
Definition pcb_track.h:699
PLUGGING_MODE GetBackPluggingMode() const
void SetBackPluggingMode(PLUGGING_MODE aMode)
MINOPTMAX< int > GetDrillConstraint(wxString *aSource=nullptr) const
void SetBackTentingMode(TENTING_MODE aMode)
void SetFrontPluggingMode(PLUGGING_MODE aMode)
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
bool operator==(const PCB_VIA &aOther) const
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
std::mutex m_zoneLayerOverridesMutex
Definition pcb_track.h:769
void SetTopLayer(PCB_LAYER_ID aLayer)
FILLING_MODE GetFillingMode() const
bool IsBuriedVia() const
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
int GetFrontWidth() const
Definition pcb_track.h:503
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/.
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
double Similarity(const BOARD_ITEM &aOther) const override
Return a measure of how likely the other object is to represent the same object.
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
bool IsMicroVia() const
virtual void SetLayerSet(const LSET &aLayers) override
Note SetLayerSet() initialize the first and last copper layers connected by the via.
void GetOutermostConnectedLayers(PCB_LAYER_ID *aTopmost, PCB_LAYER_ID *aBottommost) const
Return the top-most and bottom-most connected layers.
void SanitizeLayers()
Check so that the layers are correct depending on the type of via, and so that the top actually is on...
int GetWidth() const override
PCB_VIA & operator=(const PCB_VIA &aOther)
void swapData(BOARD_ITEM *aImage) override
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
void SetFillingMode(FILLING_MODE aMode)
PCB_VIA(BOARD_ITEM *aParent)
wxString layerMaskDescribe() const override
Return a string (to be shown to the user) describing a layer mask.
std::vector< int > ViewGetLayers() const override
Return the all the layers within the VIEW the object is painted on.
void SetViaType(VIATYPE aViaType)
Definition pcb_track.h:456
int GetMinAnnulus(PCB_LAYER_ID aLayer, wxString *aSource) const
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
TENTING_MODE GetBackTentingMode() const
PCB_LAYER_ID TopLayer() const
VIATYPE m_viaType
through, blind/buried or micro
Definition pcb_track.h:763
PADSTACK m_padStack
Definition pcb_track.h:765
COVERING_MODE GetFrontCoveringMode() const
int GetDrillValue() const
Calculate the drill value for vias (m_drill if > 0, or default drill value for the board).
void SetZoneLayerOverride(PCB_LAYER_ID aLayer, ZONE_LAYER_OVERRIDE aOverride)
void SetFrontWidth(int aWidth)
Definition pcb_track.h:502
VIATYPE GetViaType() const
Definition pcb_track.h:455
double ViewGetLOD(int aLayer, const KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
MINOPTMAX< int > GetWidthConstraint(wxString *aSource=nullptr) const override
void SetWidth(int aWidth) override
void SetBackCoveringMode(COVERING_MODE aMode)
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
const ZONE_LAYER_OVERRIDE & GetZoneLayerOverride(PCB_LAYER_ID aLayer) const
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)
bool HasValidLayerPair(int aCopperLayerCount)
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition property.h:262
PROPERTY_BASE & SetValidator(PROPERTY_VALIDATOR_FN &&aValidator)
Definition property.h:349
Provide class metadata.Helper macro to map type hashes to names.
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
void Mask(TYPE_ID aDerived, TYPE_ID aBase, const wxString &aName)
Sets a base class property as masked in a derived class.
static PROPERTY_MANAGER & Instance()
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
PROPERTY_BASE & ReplaceProperty(size_t aBase, const wxString &aName, PROPERTY_BASE *aNew, const wxString &aGroup=wxEmptyString)
Replace an existing property for a specific type.
Definition seg.h:42
VECTOR2I::extended_type ecoord
Definition seg.h:44
bool ApproxCollinear(const SEG &aSeg, int aDistanceThreshold=1) const
Definition seg.cpp:766
const VECTOR2I & GetArcMid() const
Definition shape_arc.h:118
const VECTOR2I & GetP1() const
Definition shape_arc.h:117
bool IsEffectiveLine() const
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...
Represent a set of closed polygons.
double Area()
Return the area of this poly set.
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
wxString MessageTextFromMinOptMax(const MINOPTMAX< int > &aValue, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
constexpr extended_type Cross(const VECTOR2< T > &aVector) const
Compute cross product of self with aVector.
Definition vector2d.h:546
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition vector2d.h:283
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
void TransformArcToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc)
Convert arc to multiple straight segments.
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a oblong shape to a polygon, using multiple segments.
@ ANNULAR_WIDTH_CONSTRAINT
Definition drc_rule.h:61
@ VIA_DIAMETER_CONSTRAINT
Definition drc_rule.h:70
@ TRACK_WIDTH_CONSTRAINT
Definition drc_rule.h:59
@ SOLDER_MASK_EXPANSION_CONSTRAINT
Definition drc_rule.h:66
@ HOLE_SIZE_CONSTRAINT
Definition drc_rule.h:54
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:411
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:417
#define PCB_EDIT_FRAME_NAME
INSPECT_RESULT
Definition eda_item.h:44
const INSPECTOR_FUNC & INSPECTOR
std::function passed to nested users by ref, avoids copying std::function.
Definition eda_item.h:91
#define ENDPOINT
ends. (Used to support dragging.)
std::uint32_t EDA_ITEM_FLAGS
#define STARTPOINT
When a line is selected, these flags indicate which.
a few functions useful in geometry calculations.
bool ClipLine(const BOX2I *aClipBox, int &x1, int &y1, int &x2, int &y2)
Test if any part of a line falls within the bounds of a rectangle.
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition layer_id.cpp:172
bool IsSolderMaskLayer(int aLayer)
Definition layer_ids.h:747
@ LAYER_VIA_NETNAMES
Definition layer_ids.h:203
bool IsCopperLayerLowerThan(PCB_LAYER_ID aLayerA, PCB_LAYER_ID aLayerB)
Return true if copper aLayerA is placed lower than aLayerB, false otherwise.
Definition layer_ids.h:823
constexpr PCB_LAYER_ID PCBNEW_LAYER_ID_START
Definition layer_ids.h:174
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
Definition layer_ids.h:779
FLASHING
Enum used during connectivity building to ensure we do not query connectivity while building the data...
Definition layer_ids.h:184
@ DEFAULT
Flashing follows connectivity.
Definition layer_ids.h:185
@ ALWAYS_FLASHED
Always flashed for connectivity.
Definition layer_ids.h:186
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
Definition layer_ids.h:802
#define MAX_CU_LAYERS
Definition layer_ids.h:176
int GetNetnameLayer(int aLayer)
Return a netname layer corresponding to the given layer.
Definition layer_ids.h:853
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:676
@ LAYER_LOCKED_ITEM_SHADOW
Shadow layer for locked items.
Definition layer_ids.h:307
@ LAYER_VIA_HOLEWALLS
Definition layer_ids.h:298
@ LAYER_VIA_COPPER_START
Virtual layers for via copper on a given copper layer.
Definition layer_ids.h:341
@ LAYER_TRACKS
Definition layer_ids.h:267
@ LAYER_CLEARANCE_START
Virtual layers for pad/via/track clearance outlines for a given copper layer.
Definition layer_ids.h:345
@ LAYER_VIA_HOLES
Draw via holes (pad holes do not use this layer).
Definition layer_ids.h:274
@ LAYER_VIAS
Meta control for all vias opacity/visibility.
Definition layer_ids.h:232
bool IsNetnameLayer(int aLayer)
Test whether a layer is a netname layer.
Definition layer_ids.h:868
bool IsHoleLayer(int aLayer)
Definition layer_ids.h:738
bool IsExternalCopperLayer(int aLayerId)
Test whether a layer is an external (F_Cu or B_Cu) copper layer.
Definition layer_ids.h:687
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ B_Mask
Definition layer_ids.h:98
@ B_Cu
Definition layer_ids.h:65
@ F_Mask
Definition layer_ids.h:97
@ UNDEFINED_LAYER
Definition layer_ids.h:61
@ F_Cu
Definition layer_ids.h:64
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition lset.cpp:737
constexpr void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition mirror.h:45
FLIP_DIRECTION
Definition mirror.h:27
@ LEFT_RIGHT
Flip left to right (around the Y axis)
Definition mirror.h:28
bool ShapeHitTest(const SHAPE_LINE_CHAIN &aHitter, const SHAPE &aHittee, bool aHitteeContained)
Perform a shape-to-shape hit test.
void PackLayerSet(google::protobuf::RepeatedField< int > &aOutput, const LSET &aLayerSet)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
#define _HKI(x)
Definition page_info.cpp:44
static struct TRACK_VIA_DESC _TRACK_VIA_DESC
FILLING_MODE
Definition pcb_track.h:105
#define GEOMETRY_MIN_SIZE
Definition pcb_track.h:114
VIATYPE
Definition pcb_track.h:67
@ THROUGH
Definition pcb_track.h:68
@ NOT_DEFINED
Definition pcb_track.h:73
@ MICROVIA
Definition pcb_track.h:71
TENTING_MODE
Definition pcb_track.h:77
COVERING_MODE
Definition pcb_track.h:84
PLUGGING_MODE
Definition pcb_track.h:91
CAPPING_MODE
Definition pcb_track.h:98
#define TYPE_HASH(x)
Definition property.h:74
#define ENUM_TO_WXANY(type)
Macro to define read-only fields (no setter method available)
Definition property.h:823
@ PT_COORD
Coordinate expressed in distance units (mm/inch)
Definition property.h:65
@ PT_SIZE
Size expressed in distance units (mm/inch)
Definition property.h:63
#define REGISTER_TYPE(x)
std::optional< std::unique_ptr< VALIDATION_ERROR > > VALIDATOR_RESULT
Null optional means validation succeeded.
wxString UnescapeString(const wxString &aSource)
PCB_LAYER_ID start
Definition padstack.h:247
PCB_LAYER_ID end
Definition padstack.h:248
Struct to control which optimisations the length calculation code runs on the given path objects.
bool operator()(const PCB_TRACK *aFirst, const PCB_TRACK *aSecond) const
VECTOR2I center
int radius
VECTOR2I end
int clearance
wxString result
Test unit parsing edge cases and error handling.
bool TestSegmentHit(const VECTOR2I &aRefPoint, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aDist)
Test if aRefPoint is with aDistance on the line defined by aStart and aEnd.
Definition trigo.cpp:175
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
const VECTOR2I CalcArcCenter(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Determine the center of an arc or circle given three points on its circumference.
Definition trigo.cpp:521
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:78
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:97
@ 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_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:96
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694
VECTOR2< int64_t > VECTOR2L
Definition vector2d.h:696