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 <dick@softplc.com>
6  * Copyright (C) 2012 Wayne Stambaugh <stambaughw@gmail.com>
7  * Copyright (C) 1992-2021 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_base_frame.h>
28 #include <connectivity/connectivity_data.h>
29 #include <board.h>
30 #include <board_design_settings.h>
31 #include <convert_basic_shapes_to_polygon.h>
32 #include <pcb_track.h>
33 #include <base_units.h>
34 #include <bitmaps.h>
35 #include <string_utils.h>
36 #include <view/view.h>
37 #include <settings/color_settings.h>
38 #include <settings/settings_manager.h>
39 #include <i18n_utility.h>
40 #include <geometry/seg.h>
41 #include <geometry/shape_segment.h>
42 #include <geometry/shape_circle.h>
43 #include <geometry/shape_arc.h>
44 #include <drc/drc_engine.h>
45 #include <pcb_painter.h>
46 #include <trigo.h>
47 
48 using KIGFX::PCB_PAINTER;
49 using KIGFX::PCB_RENDER_SETTINGS;
50 
PCB_TRACK(BOARD_ITEM * aParent,KICAD_T idtype)51 PCB_TRACK::PCB_TRACK( BOARD_ITEM* aParent, KICAD_T idtype ) :
52     BOARD_CONNECTED_ITEM( aParent, idtype )
53 {
54     m_Width = Millimeter2iu( 0.2 );     // Gives a reasonable default width
55 }
56 
57 
Clone() const58 EDA_ITEM* PCB_TRACK::Clone() const
59 {
60     return new PCB_TRACK( *this );
61 }
62 
63 
PCB_ARC(BOARD_ITEM * aParent,const SHAPE_ARC * aArc)64 PCB_ARC::PCB_ARC( BOARD_ITEM* aParent, const SHAPE_ARC* aArc ) :
65     PCB_TRACK( aParent, PCB_ARC_T )
66 {
67     m_Start = wxPoint( aArc->GetP0() );
68     m_End = wxPoint( aArc->GetP1() );
69     m_Mid = wxPoint( aArc->GetArcMid() );
70 }
71 
72 
Clone() const73 EDA_ITEM* PCB_ARC::Clone() const
74 {
75     return new PCB_ARC( *this );
76 }
77 
78 
PCB_VIA(BOARD_ITEM * aParent)79 PCB_VIA::PCB_VIA( BOARD_ITEM* aParent ) :
80         PCB_TRACK( aParent, PCB_VIA_T )
81 {
82     SetViaType( VIATYPE::THROUGH );
83     m_bottomLayer = B_Cu;
84     SetDrillDefault();
85     m_removeUnconnectedLayer = false;
86     m_keepTopBottomLayer = true;
87     m_isFree = false;
88 }
89 
90 
Clone() const91 EDA_ITEM* PCB_VIA::Clone() const
92 {
93     return new PCB_VIA( *this );
94 }
95 
96 
GetSelectMenuText(EDA_UNITS aUnits) const97 wxString PCB_VIA::GetSelectMenuText( EDA_UNITS aUnits ) const
98 {
99     wxString formatStr;
100 
101     switch( GetViaType() )
102     {
103     case VIATYPE::BLIND_BURIED: formatStr = _( "Blind/Buried Via %s on %s" ); break;
104     case VIATYPE::MICROVIA:     formatStr = _( "Micro Via %s on %s" );        break;
105     default:                    formatStr = _( "Via %s on %s" );              break;
106     }
107 
108     return wxString::Format( formatStr,
109                              GetNetnameMsg(),
110                              layerMaskDescribe() );
111 }
112 
113 
GetMenuImage() const114 BITMAPS PCB_VIA::GetMenuImage() const
115 {
116     return BITMAPS::via;
117 }
118 
119 
ApproxCollinear(const PCB_TRACK & aTrack)120 bool PCB_TRACK::ApproxCollinear( const PCB_TRACK& aTrack )
121 {
122     SEG a( m_Start, m_End );
123     SEG b( aTrack.GetStart(), aTrack.GetEnd() );
124     return a.ApproxCollinear( b );
125 }
126 
127 
GetLocalClearance(wxString * aSource) const128 int PCB_TRACK::GetLocalClearance( wxString* aSource ) const
129 {
130     // Not currently implemented
131     return 0;
132 }
133 
134 
GetMinAnnulus(PCB_LAYER_ID aLayer,wxString * aSource) const135 int PCB_VIA::GetMinAnnulus( PCB_LAYER_ID aLayer, wxString* aSource ) const
136 {
137     if( !FlashLayer( aLayer ) )
138     {
139         if( aSource )
140             *aSource = _( "removed annular ring" );
141 
142         return 0;
143     }
144 
145     DRC_CONSTRAINT constraint;
146 
147     if( GetBoard() && GetBoard()->GetDesignSettings().m_DRCEngine )
148     {
149         BOARD_DESIGN_SETTINGS& bds = GetBoard()->GetDesignSettings();
150 
151         constraint = bds.m_DRCEngine->EvalRules( ANNULAR_WIDTH_CONSTRAINT, this, nullptr, aLayer );
152     }
153 
154     if( constraint.Value().HasMin() )
155     {
156         if( aSource )
157             *aSource = constraint.GetName();
158 
159         return constraint.Value().Min();
160     }
161 
162     return 0;
163 }
164 
165 
GetDrillValue() const166 int PCB_VIA::GetDrillValue() const
167 {
168     if( m_drill > 0 ) // Use the specific value.
169         return m_drill;
170 
171     // Use the default value from the Netclass
172     NETCLASS* netclass = GetNetClass();
173 
174     if( GetViaType() == VIATYPE::MICROVIA )
175         return netclass->GetuViaDrill();
176 
177     return netclass->GetViaDrill();
178 }
179 
180 
IsPointOnEnds(const wxPoint & point,int min_dist) const181 EDA_ITEM_FLAGS PCB_TRACK::IsPointOnEnds( const wxPoint& point, int min_dist ) const
182 {
183     EDA_ITEM_FLAGS result = 0;
184 
185     if( min_dist < 0 )
186         min_dist = m_Width / 2;
187 
188     if( min_dist == 0 )
189     {
190         if( m_Start == point  )
191             result |= STARTPOINT;
192 
193         if( m_End == point )
194             result |= ENDPOINT;
195     }
196     else
197     {
198         double dist = GetLineLength( m_Start, point );
199 
200         if( min_dist >= KiROUND( dist ) )
201             result |= STARTPOINT;
202 
203         dist = GetLineLength( m_End, point );
204 
205         if( min_dist >= KiROUND( dist ) )
206             result |= ENDPOINT;
207     }
208 
209     return result;
210 }
211 
212 
GetBoundingBox() const213 const EDA_RECT PCB_TRACK::GetBoundingBox() const
214 {
215     // end of track is round, this is its radius, rounded up
216     int radius = ( m_Width + 1 ) / 2;
217     int ymax, xmax, ymin, xmin;
218 
219     if( Type() == PCB_VIA_T )
220     {
221         ymax = m_Start.y;
222         xmax = m_Start.x;
223 
224         ymin = m_Start.y;
225         xmin = m_Start.x;
226     }
227     else if( Type() == PCB_ARC_T )
228     {
229         std::shared_ptr<SHAPE> arc = GetEffectiveShape();
230         auto bbox = arc->BBox();
231 
232         xmin = bbox.GetLeft();
233         xmax = bbox.GetRight();
234         ymin = bbox.GetTop();
235         ymax = bbox.GetBottom();
236     }
237     else
238     {
239         ymax = std::max( m_Start.y, m_End.y );
240         xmax = std::max( m_Start.x, m_End.x );
241 
242         ymin = std::min( m_Start.y, m_End.y );
243         xmin = std::min( m_Start.x, m_End.x );
244     }
245 
246     ymax += radius;
247     xmax += radius;
248 
249     ymin -= radius;
250     xmin -= radius;
251 
252     // return a rectangle which is [pos,dim) in nature.  therefore the +1
253     EDA_RECT ret( wxPoint( xmin, ymin ), wxSize( xmax - xmin + 1, ymax - ymin + 1 ) );
254 
255     return ret;
256 }
257 
258 
GetLength() const259 double PCB_TRACK::GetLength() const
260 {
261     return GetLineLength( m_Start, m_End );
262 }
263 
264 
Rotate(const wxPoint & aRotCentre,double aAngle)265 void PCB_TRACK::Rotate( const wxPoint& aRotCentre, double aAngle )
266 {
267     RotatePoint( &m_Start, aRotCentre, aAngle );
268     RotatePoint( &m_End, aRotCentre, aAngle );
269 }
270 
271 
Rotate(const wxPoint & aRotCentre,double aAngle)272 void PCB_ARC::Rotate( const wxPoint& aRotCentre, double aAngle )
273 {
274     RotatePoint( &m_Start, aRotCentre, aAngle );
275     RotatePoint( &m_End, aRotCentre, aAngle );
276     RotatePoint( &m_Mid, aRotCentre, aAngle );
277 }
278 
279 
Flip(const wxPoint & aCentre,bool aFlipLeftRight)280 void PCB_TRACK::Flip( const wxPoint& aCentre, bool aFlipLeftRight )
281 {
282     if( aFlipLeftRight )
283     {
284         m_Start.x = aCentre.x - ( m_Start.x - aCentre.x );
285         m_End.x   = aCentre.x - ( m_End.x - aCentre.x );
286     }
287     else
288     {
289         m_Start.y = aCentre.y - ( m_Start.y - aCentre.y );
290         m_End.y   = aCentre.y - ( m_End.y - aCentre.y );
291     }
292 
293     int copperLayerCount = GetBoard()->GetCopperLayerCount();
294     SetLayer( FlipLayer( GetLayer(), copperLayerCount ) );
295 }
296 
297 
Flip(const wxPoint & aCentre,bool aFlipLeftRight)298 void PCB_ARC::Flip( const wxPoint& aCentre, bool aFlipLeftRight )
299 {
300     if( aFlipLeftRight )
301     {
302         m_Start.x = aCentre.x - ( m_Start.x - aCentre.x );
303         m_End.x   = aCentre.x - ( m_End.x - aCentre.x );
304         m_Mid.x = aCentre.x - ( m_Mid.x - aCentre.x );
305     }
306     else
307     {
308         m_Start.y = aCentre.y - ( m_Start.y - aCentre.y );
309         m_End.y   = aCentre.y - ( m_End.y - aCentre.y );
310         m_Mid.y = aCentre.y - ( m_Mid.y - aCentre.y );
311     }
312 
313     int copperLayerCount = GetBoard()->GetCopperLayerCount();
314     SetLayer( FlipLayer( GetLayer(), copperLayerCount ) );
315 }
316 
317 
Flip(const wxPoint & aCentre,bool aFlipLeftRight)318 void PCB_VIA::Flip( const wxPoint& aCentre, bool aFlipLeftRight )
319 {
320     if( aFlipLeftRight )
321     {
322         m_Start.x = aCentre.x - ( m_Start.x - aCentre.x );
323         m_End.x   = aCentre.x - ( m_End.x - aCentre.x );
324     }
325     else
326     {
327         m_Start.y = aCentre.y - ( m_Start.y - aCentre.y );
328         m_End.y   = aCentre.y - ( m_End.y - aCentre.y );
329     }
330 
331     if( GetViaType() != VIATYPE::THROUGH )
332     {
333         int          copperLayerCount = GetBoard()->GetCopperLayerCount();
334         PCB_LAYER_ID top_layer;
335         PCB_LAYER_ID bottom_layer;
336         LayerPair( &top_layer, &bottom_layer );
337         top_layer    = FlipLayer( top_layer, copperLayerCount );
338         bottom_layer = FlipLayer( bottom_layer, copperLayerCount );
339         SetLayerPair( top_layer, bottom_layer );
340     }
341 }
342 
343 
344 // see class_track.h
Visit(INSPECTOR inspector,void * testData,const KICAD_T scanTypes[])345 SEARCH_RESULT PCB_TRACK::Visit( INSPECTOR inspector, void* testData, const KICAD_T scanTypes[] )
346 {
347     KICAD_T stype = *scanTypes;
348 
349     // If caller wants to inspect my type
350     if( stype == Type() )
351     {
352         if( SEARCH_RESULT::QUIT == inspector( this, testData ) )
353             return SEARCH_RESULT::QUIT;
354     }
355 
356     return SEARCH_RESULT::CONTINUE;
357 }
358 
359 
IsOnLayer(PCB_LAYER_ID layer_number) const360 bool PCB_VIA::IsOnLayer( PCB_LAYER_ID layer_number ) const
361 {
362     PCB_LAYER_ID bottom_layer, top_layer;
363 
364     LayerPair( &top_layer, &bottom_layer );
365 
366     wxASSERT( top_layer <= bottom_layer );
367 
368     if( top_layer <= layer_number && layer_number <= bottom_layer )
369         return true;
370     else
371         return false;
372 }
373 
374 
GetLayerSet() const375 LSET PCB_VIA::GetLayerSet() const
376 {
377     if( GetViaType() == VIATYPE::THROUGH )
378         return LSET::AllCuMask();
379 
380     // VIA_BLIND_BURIED or VIA_MICRVIA:
381 
382     LSET layermask;
383 
384     wxASSERT( m_layer <= m_bottomLayer );
385 
386     // PCB_LAYER_IDs are numbered from front to back, this is top to bottom.
387     for( LAYER_NUM id = m_layer; id <= m_bottomLayer; ++id )
388     {
389         layermask.set( id );
390     }
391 
392     return layermask;
393 }
394 
395 
SetLayerSet(LSET aLayerSet)396 void PCB_VIA::SetLayerSet( LSET aLayerSet )
397 {
398     bool first = true;
399 
400     for( PCB_LAYER_ID layer : aLayerSet.Seq() )
401     {
402         if( first )
403         {
404             m_layer = layer;
405             first = false;
406         }
407 
408         m_bottomLayer = layer;
409     }
410 }
411 
412 
SetLayerPair(PCB_LAYER_ID aTopLayer,PCB_LAYER_ID aBottomLayer)413 void PCB_VIA::SetLayerPair( PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer )
414 {
415 
416     m_layer = aTopLayer;
417     m_bottomLayer = aBottomLayer;
418     SanitizeLayers();
419 }
420 
421 
SetTopLayer(PCB_LAYER_ID aLayer)422 void PCB_VIA::SetTopLayer( PCB_LAYER_ID aLayer )
423 {
424     m_layer = aLayer;
425 }
426 
427 
SetBottomLayer(PCB_LAYER_ID aLayer)428 void PCB_VIA::SetBottomLayer( PCB_LAYER_ID aLayer )
429 {
430     m_bottomLayer = aLayer;
431 }
432 
433 
LayerPair(PCB_LAYER_ID * top_layer,PCB_LAYER_ID * bottom_layer) const434 void PCB_VIA::LayerPair( PCB_LAYER_ID* top_layer, PCB_LAYER_ID* bottom_layer ) const
435 {
436     PCB_LAYER_ID t_layer = F_Cu;
437     PCB_LAYER_ID b_layer = B_Cu;
438 
439     if( GetViaType() != VIATYPE::THROUGH )
440     {
441         b_layer = m_bottomLayer;
442         t_layer = m_layer;
443 
444         if( b_layer < t_layer )
445             std::swap( b_layer, t_layer );
446     }
447 
448     if( top_layer )
449         *top_layer = t_layer;
450 
451     if( bottom_layer )
452         *bottom_layer = b_layer;
453 }
454 
455 
TopLayer() const456 PCB_LAYER_ID PCB_VIA::TopLayer() const
457 {
458     return m_layer;
459 }
460 
461 
BottomLayer() const462 PCB_LAYER_ID PCB_VIA::BottomLayer() const
463 {
464     return m_bottomLayer;
465 }
466 
467 
SanitizeLayers()468 void PCB_VIA::SanitizeLayers()
469 {
470     if( GetViaType() == VIATYPE::THROUGH )
471     {
472         m_layer       = F_Cu;
473         m_bottomLayer = B_Cu;
474     }
475 
476     if( m_bottomLayer < m_layer )
477         std::swap( m_bottomLayer, m_layer );
478 }
479 
480 
FlashLayer(LSET aLayers) const481 bool PCB_VIA::FlashLayer( LSET aLayers ) const
482 {
483     for( auto layer : aLayers.Seq() )
484     {
485         if( FlashLayer( layer ) )
486             return true;
487     }
488 
489     return false;
490 }
491 
492 
FlashLayer(int aLayer) const493 bool PCB_VIA::FlashLayer( int aLayer ) const
494 {
495     std::vector<KICAD_T> types
496     { PCB_TRACE_T, PCB_ARC_T, PCB_PAD_T, PCB_ZONE_T, PCB_FP_ZONE_T };
497 
498     // Return the "normal" shape if the caller doesn't specify a particular layer
499     if( aLayer == UNDEFINED_LAYER )
500         return true;
501 
502     const BOARD* board = GetBoard();
503 
504     if( !board )
505         return false;
506 
507     if( !IsOnLayer( static_cast<PCB_LAYER_ID>( aLayer ) ) )
508         return false;
509 
510     if( !m_removeUnconnectedLayer )
511         return true;
512 
513     if( m_keepTopBottomLayer && ( aLayer == m_layer || aLayer == m_bottomLayer ) )
514         return true;
515 
516     return board->GetConnectivity()->IsConnectedOnLayer( this, static_cast<int>( aLayer ), types );
517 }
518 
519 
ViewGetLayers(int aLayers[],int & aCount) const520 void PCB_TRACK::ViewGetLayers( int aLayers[], int& aCount ) const
521 {
522     // Show the track and its netname on different layers
523     aLayers[0] = GetLayer();
524     aLayers[1] = GetNetnameLayer( aLayers[0] );
525     aCount = 2;
526 }
527 
528 
ViewGetLOD(int aLayer,KIGFX::VIEW * aView) const529 double PCB_TRACK::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
530 {
531     constexpr double HIDE = std::numeric_limits<double>::max();
532 
533     PCB_PAINTER*         painter = static_cast<PCB_PAINTER*>( aView->GetPainter() );
534     PCB_RENDER_SETTINGS* renderSettings = painter->GetSettings();
535 
536     if( !aView->IsLayerVisible( LAYER_TRACKS ) )
537         return HIDE;
538 
539     if( IsNetnameLayer( aLayer ) )
540     {
541         // Hide netnames on dimmed tracks
542         if( renderSettings->GetHighContrast() )
543         {
544             if( m_layer != renderSettings->GetPrimaryHighContrastLayer() )
545                 return HIDE;
546         }
547 
548         // Netnames will be shown only if zoom is appropriate
549         return ( double ) Millimeter2iu( 4 ) / ( m_Width + 1 );
550     }
551 
552     // Other layers are shown without any conditions
553     return 0.0;
554 }
555 
556 
ViewBBox() const557 const BOX2I PCB_TRACK::ViewBBox() const
558 {
559     BOX2I        bbox = GetBoundingBox();
560     const BOARD* board = GetBoard();
561 
562     if( board )
563         bbox.Inflate( 2 * board->GetDesignSettings().GetBiggestClearanceValue() );
564     else
565         bbox.Inflate( GetWidth() );     // Add a bit extra for safety
566 
567     return bbox;
568 }
569 
570 
ViewGetLayers(int aLayers[],int & aCount) const571 void PCB_VIA::ViewGetLayers( int aLayers[], int& aCount ) const
572 {
573     aLayers[0] = LAYER_VIA_HOLES;
574     aLayers[1] = LAYER_VIA_HOLEWALLS;
575     aLayers[2] = LAYER_VIA_NETNAMES;
576 
577     // Just show it on common via & via holes layers
578     switch( GetViaType() )
579     {
580     case VIATYPE::THROUGH:      aLayers[3] = LAYER_VIA_THROUGH;  break;
581     case VIATYPE::BLIND_BURIED: aLayers[3] = LAYER_VIA_BBLIND;   break;
582     case VIATYPE::MICROVIA:     aLayers[3] = LAYER_VIA_MICROVIA; break;
583     default:                    aLayers[3] = LAYER_GP_OVERLAY;   break;
584     }
585 
586     aCount = 4;
587 }
588 
589 
ViewGetLOD(int aLayer,KIGFX::VIEW * aView) const590 double PCB_VIA::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
591 {
592     constexpr double HIDE = (double)std::numeric_limits<double>::max();
593 
594     PCB_PAINTER*         painter = static_cast<PCB_PAINTER*>( aView->GetPainter() );
595     PCB_RENDER_SETTINGS* renderSettings = painter->GetSettings();
596     const BOARD*         board = GetBoard();
597     LSET                 visible = LSET::AllLayersMask();
598 
599     // Meta control for hiding all vias
600     if( !aView->IsLayerVisible( LAYER_VIAS ) )
601         return HIDE;
602 
603     // Handle board visibility
604     if( board )
605         visible = board->GetVisibleLayers() & board->GetEnabledLayers();
606 
607     if( IsViaPadLayer( aLayer ) )
608     {
609         if( !FlashLayer( visible ) )
610             return HIDE;
611     }
612     else if( IsHoleLayer( aLayer ) )
613     {
614         if( m_viaType == VIATYPE::BLIND_BURIED || m_viaType == VIATYPE::MICROVIA )
615         {
616             // Show a blind or micro via's hole if it crosses a visible layer
617             if( !( visible & GetLayerSet() ).any() )
618                 return HIDE;
619         }
620         else
621         {
622             // Show a through via's hole if any physical layer is shown
623             if( !( visible & LSET::PhysicalLayersMask() ).any() )
624                 return HIDE;
625         }
626     }
627     else if( IsNetnameLayer( aLayer ) )
628     {
629         if( renderSettings->GetHighContrast() )
630         {
631             // Hide netnames unless via is flashed to a high-contrast layer
632             if( !FlashLayer( renderSettings->GetPrimaryHighContrastLayer() ) )
633                 return HIDE;
634         }
635         else
636         {
637             // Hide netnames unless pad is flashed to a visible layer
638             if( !FlashLayer( visible ) )
639                 return HIDE;
640         }
641 
642         // Netnames will be shown only if zoom is appropriate
643         return m_Width == 0 ? HIDE : ( (double)Millimeter2iu( 10 ) / m_Width );
644     }
645 
646     // Passed all tests; show.
647     return 0.0;
648 }
649 
650 
651 // see class_track.h
GetMsgPanelInfo(EDA_DRAW_FRAME * aFrame,std::vector<MSG_PANEL_ITEM> & aList)652 void PCB_TRACK::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
653 {
654     EDA_UNITS units = aFrame->GetUserUnits();
655     wxString  msg;
656     BOARD*    board = GetBoard();
657 
658     aList.emplace_back( _( "Type" ),
659                         Type() == PCB_ARC_T ? ( "Track (arc)" ) : _( "Track" ) );
660 
661 
662     GetMsgPanelInfoBase_Common( aFrame, aList );
663 
664     aList.emplace_back( _( "Layer" ), layerMaskDescribe() );
665 
666     aList.emplace_back( _( "Width" ), MessageTextFromValue( units, m_Width ) );
667 
668     if( Type() == PCB_ARC_T )
669     {
670         double radius = static_cast<PCB_ARC*>( this )->GetRadius();
671         aList.emplace_back( _( "Radius" ), MessageTextFromValue( units, radius ) );
672     }
673 
674     aList.emplace_back( _( "Segment Length" ), MessageTextFromValue( units, GetLength() ) );
675 
676     // Display full track length (in Pcbnew)
677     if( board && GetNetCode() > 0 )
678     {
679         int    count;
680         double trackLen;
681         double lenPadToDie;
682 
683         std::tie( count, trackLen, lenPadToDie ) = board->GetTrackLength( *this );
684 
685         aList.emplace_back( _( "Routed Length" ), MessageTextFromValue( units, trackLen ) );
686 
687         if( lenPadToDie != 0 )
688         {
689             msg = MessageTextFromValue( units, lenPadToDie );
690             aList.emplace_back( _( "Pad To Die Length" ), msg );
691 
692             msg = MessageTextFromValue( units, trackLen + lenPadToDie );
693             aList.emplace_back( _( "Full Length" ), msg );
694         }
695     }
696 
697     wxString source;
698     int clearance = GetOwnClearance( GetLayer(), &source );
699 
700     aList.emplace_back( wxString::Format( _( "Min Clearance: %s" ),
701                                           MessageTextFromValue( units, clearance ) ),
702                         wxString::Format( _( "(from %s)" ), source ) );
703 }
704 
705 
GetMsgPanelInfo(EDA_DRAW_FRAME * aFrame,std::vector<MSG_PANEL_ITEM> & aList)706 void PCB_VIA::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
707 {
708     EDA_UNITS units = aFrame->GetUserUnits();
709     wxString  msg;
710 
711     switch( GetViaType() )
712     {
713     case VIATYPE::MICROVIA:     msg = _( "Micro Via" );        break;
714     case VIATYPE::BLIND_BURIED: msg = _( "Blind/Buried Via" ); break;
715     case VIATYPE::THROUGH:      msg = _( "Through Via" );      break;
716     default:                    msg = _( "Via" );              break;
717     }
718 
719     aList.emplace_back( _( "Type" ), msg );
720 
721     GetMsgPanelInfoBase_Common( aFrame, aList );
722 
723     aList.emplace_back( _( "Layer" ), layerMaskDescribe() );
724 
725     msg = MessageTextFromValue( aFrame->GetUserUnits(), m_Width );
726 
727     aList.emplace_back( _( "Diameter" ), msg );
728 
729     msg = MessageTextFromValue( aFrame->GetUserUnits(), GetDrillValue() );
730 
731     aList.emplace_back( _( "Drill" ), msg );
732 
733     wxString  source;
734     int clearance = GetOwnClearance( GetLayer(), &source );
735 
736     aList.emplace_back( wxString::Format( _( "Min Clearance: %s" ),
737                                           MessageTextFromValue( units, clearance ) ),
738                         wxString::Format( _( "(from %s)" ), source ) );
739 
740     int minAnnulus = GetMinAnnulus( GetLayer(), &source );
741 
742     aList.emplace_back( wxString::Format( _( "Min Annular Width: %s" ),
743                                           MessageTextFromValue( units, minAnnulus ) ),
744                         wxString::Format( _( "(from %s)" ), source ) );
745 }
746 
747 
GetMsgPanelInfoBase_Common(EDA_DRAW_FRAME * aFrame,std::vector<MSG_PANEL_ITEM> & aList) const748 void PCB_TRACK::GetMsgPanelInfoBase_Common( EDA_DRAW_FRAME* aFrame,
749                                             std::vector<MSG_PANEL_ITEM>& aList ) const
750 {
751     wxString msg;
752 
753     aList.emplace_back( _( "Net" ), UnescapeString( GetNetname() ) );
754 
755     aList.emplace_back( _( "Net Class" ), UnescapeString( GetNetClass()->GetName() ) );
756 
757 #if 0   // Enable for debugging
758     if( GetBoard() )
759         aList.emplace_back( _( "NetCode" ), wxString::Format( wxT( "%d" ), GetNetCode() ) );
760 
761     aList.emplace_back( wxT( "Flags" ), wxString::Format( wxT( "0x%08X" ), m_flags ) );
762 
763     aList.emplace_back( wxT( "Start pos" ), wxString::Format( wxT( "%d %d" ),
764                                                               m_Start.x,
765                                                               m_Start.y ) );
766     aList.emplace_back( wxT( "End pos" ), wxString::Format( wxT( "%d %d" ),
767                                                             m_End.x,
768                                                             m_End.y ) );
769 #endif
770 
771     if( aFrame->GetName() == PCB_EDIT_FRAME_NAME && IsLocked() )
772         aList.emplace_back( _( "Status" ), _( "Locked" ) );
773 }
774 
775 
layerMaskDescribe() const776 wxString PCB_VIA::layerMaskDescribe() const
777 {
778     const BOARD* board = GetBoard();
779     PCB_LAYER_ID top_layer;
780     PCB_LAYER_ID bottom_layer;
781 
782     LayerPair( &top_layer, &bottom_layer );
783 
784     return board->GetLayerName( top_layer ) + wxT( " - " ) + board->GetLayerName( bottom_layer );
785 }
786 
787 
HitTest(const wxPoint & aPosition,int aAccuracy) const788 bool PCB_TRACK::HitTest( const wxPoint& aPosition, int aAccuracy ) const
789 {
790     return TestSegmentHit( aPosition, m_Start, m_End, aAccuracy + ( m_Width / 2 ) );
791 }
792 
793 
HitTest(const wxPoint & aPosition,int aAccuracy) const794 bool PCB_ARC::HitTest( const wxPoint& aPosition, int aAccuracy ) const
795 {
796     int max_dist = aAccuracy + ( m_Width / 2 );
797 
798     // Short-circuit common cases where the arc is connected to a track or via at an endpoint
799     if( EuclideanNorm( GetStart() - aPosition ) <= max_dist ||
800             EuclideanNorm( GetEnd() - aPosition ) <= max_dist )
801     {
802         return true;
803     }
804 
805     wxPoint center = GetPosition();
806     wxPoint relpos = aPosition - center;
807     double dist = EuclideanNorm( relpos );
808     double radius = GetRadius();
809 
810     if( std::abs( dist - radius ) > max_dist )
811         return false;
812 
813     double arc_angle_start = GetArcAngleStart();    // Always 0.0 ... 360 deg, in 0.1 deg
814     double arc_hittest = ArcTangente( relpos.y, relpos.x );
815 
816     // Calculate relative angle between the starting point of the arc, and the test point
817     arc_hittest -= arc_angle_start;
818 
819     // Normalise arc_hittest between 0 ... 360 deg
820     NORMALIZE_ANGLE_POS( arc_hittest );
821     double arc_angle = GetAngle();
822 
823     if( arc_angle < 0 )
824         return arc_hittest >= 3600 + arc_angle;
825 
826     return  arc_hittest <= arc_angle;
827 }
828 
829 
HitTest(const wxPoint & aPosition,int aAccuracy) const830 bool PCB_VIA::HitTest( const wxPoint& aPosition, int aAccuracy ) const
831 {
832     int max_dist = aAccuracy + ( m_Width / 2 );
833 
834     // rel_pos is aPosition relative to m_Start (or the center of the via)
835     wxPoint rel_pos = aPosition - m_Start;
836     double dist = (double) rel_pos.x * rel_pos.x + (double) rel_pos.y * rel_pos.y;
837     return  dist <= (double) max_dist * max_dist;
838 }
839 
840 
HitTest(const EDA_RECT & aRect,bool aContained,int aAccuracy) const841 bool PCB_TRACK::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
842 {
843     EDA_RECT arect = aRect;
844     arect.Inflate( aAccuracy );
845 
846     if( aContained )
847         return arect.Contains( GetStart() ) && arect.Contains( GetEnd() );
848     else
849         return arect.Intersects( GetStart(), GetEnd() );
850 }
851 
852 
HitTest(const EDA_RECT & aRect,bool aContained,int aAccuracy) const853 bool PCB_ARC::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
854 {
855     EDA_RECT box;
856     EDA_RECT arect = aRect;
857     arect.Inflate( aAccuracy );
858 
859     box.SetOrigin( GetStart() );
860     box.Merge( GetMid() );
861     box.Merge( GetEnd() );
862 
863     box.Inflate( GetWidth() / 2 );
864 
865     if( aContained )
866         return arect.Contains( box );
867     else
868         return arect.Intersects( box );
869 }
870 
871 
HitTest(const EDA_RECT & aRect,bool aContained,int aAccuracy) const872 bool PCB_VIA::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
873 {
874     EDA_RECT box;
875     EDA_RECT arect = aRect;
876     arect.Inflate( aAccuracy );
877 
878     box.SetOrigin( GetStart() );
879     box.Inflate( GetWidth() / 2 );
880 
881     if( aContained )
882         return arect.Contains( box );
883     else
884         return arect.IntersectsCircle( GetStart(), GetWidth() / 2 );
885 }
886 
887 
GetSelectMenuText(EDA_UNITS aUnits) const888 wxString PCB_TRACK::GetSelectMenuText( EDA_UNITS aUnits ) const
889 {
890     return wxString::Format( Type() == PCB_ARC_T ? _("Track (arc) %s on %s, length %s" )
891                                                  : _("Track %s on %s, length %s" ),
892                              GetNetnameMsg(),
893                              GetLayerName(),
894                              MessageTextFromValue( aUnits, GetLength() ) );
895 }
896 
897 
GetMenuImage() const898 BITMAPS PCB_TRACK::GetMenuImage() const
899 {
900     return BITMAPS::add_tracks;
901 }
902 
SwapData(BOARD_ITEM * aImage)903 void PCB_TRACK::SwapData( BOARD_ITEM* aImage )
904 {
905     assert( aImage->Type() == PCB_TRACE_T );
906 
907     std::swap( *((PCB_TRACK*) this), *((PCB_TRACK*) aImage) );
908 }
909 
SwapData(BOARD_ITEM * aImage)910 void PCB_ARC::SwapData( BOARD_ITEM* aImage )
911 {
912     assert( aImage->Type() == PCB_ARC_T );
913 
914     std::swap( *this, *static_cast<PCB_ARC*>( aImage ) );
915 }
916 
SwapData(BOARD_ITEM * aImage)917 void PCB_VIA::SwapData( BOARD_ITEM* aImage )
918 {
919     assert( aImage->Type() == PCB_VIA_T );
920 
921     std::swap( *((PCB_VIA*) this), *((PCB_VIA*) aImage) );
922 }
923 
924 
GetPosition() const925 wxPoint PCB_ARC::GetPosition() const
926 {
927     auto center = CalcArcCenter( VECTOR2I( m_Start ), VECTOR2I( m_Mid ), VECTOR2I( m_End ));
928     return wxPoint( center.x, center.y );
929 }
930 
GetRadius() const931 double PCB_ARC::GetRadius() const
932 {
933     auto center = CalcArcCenter( VECTOR2I( m_Start ), VECTOR2I( m_Mid ), VECTOR2I( m_End ));
934     return GetLineLength( wxPoint( center ), m_Start );
935 }
936 
GetAngle() const937 double PCB_ARC::GetAngle() const
938 {
939     wxPoint center = GetPosition();
940     wxPoint p0 = m_Start - center;
941     wxPoint p1 = m_Mid - center;
942     wxPoint p2 = m_End - center;
943     double angle1 = ArcTangente( p1.y, p1.x ) - ArcTangente( p0.y, p0.x );
944     double angle2 = ArcTangente( p2.y, p2.x ) - ArcTangente( p1.y, p1.x );
945 
946     return NormalizeAngle180( angle1 ) + NormalizeAngle180( angle2 );
947 }
948 
GetArcAngleStart() const949 double PCB_ARC::GetArcAngleStart() const
950 {
951     wxPoint center = GetPosition();
952 
953     double angleStart = ArcTangente( m_Start.y - center.y,
954                                      m_Start.x - center.x );
955     return NormalizeAnglePos( angleStart );
956 }
957 
GetArcAngleEnd() const958 double PCB_ARC::GetArcAngleEnd() const
959 {
960     wxPoint center = GetPosition();
961 
962     double angleEnd = ArcTangente( m_End.y - center.y,
963                                    m_End.x - center.x );
964     return NormalizeAnglePos( angleEnd );
965 }
966 
967 
operator ()(const PCB_TRACK * a,const PCB_TRACK * b) const968 bool PCB_TRACK::cmp_tracks::operator() ( const PCB_TRACK* a, const PCB_TRACK* b ) const
969 {
970     if( a->GetNetCode() != b->GetNetCode() )
971         return a->GetNetCode() < b->GetNetCode();
972 
973     if( a->GetLayer() != b->GetLayer() )
974         return a->GetLayer() < b->GetLayer();
975 
976     if( a->Type() != b->Type() )
977         return a->Type() < b->Type();
978 
979     if( a->m_Uuid != b->m_Uuid )
980         return a->m_Uuid < b->m_Uuid;
981 
982     return a < b;
983 }
984 
985 
GetEffectiveShape(PCB_LAYER_ID aLayer) const986 std::shared_ptr<SHAPE> PCB_TRACK::GetEffectiveShape( PCB_LAYER_ID aLayer ) const
987 {
988     return std::make_shared<SHAPE_SEGMENT>( m_Start, m_End, m_Width );
989 }
990 
991 
GetEffectiveShape(PCB_LAYER_ID aLayer) const992 std::shared_ptr<SHAPE> PCB_VIA::GetEffectiveShape( PCB_LAYER_ID aLayer ) const
993 {
994     if( FlashLayer( aLayer ) )
995     {
996         return std::make_shared<SHAPE_CIRCLE>( m_Start, m_Width / 2 );
997     }
998     else
999     {
1000         int radius = GetDrillValue() / 2;
1001 
1002         if( GetBoard() )
1003             radius += GetBoard()->GetDesignSettings().GetHolePlatingThickness();
1004 
1005         return std::make_shared<SHAPE_CIRCLE>( m_Start, radius );
1006     }
1007 }
1008 
1009 
GetEffectiveShape(PCB_LAYER_ID aLayer) const1010 std::shared_ptr<SHAPE> PCB_ARC::GetEffectiveShape( PCB_LAYER_ID aLayer ) const
1011 {
1012     return std::make_shared<SHAPE_ARC>( GetStart(), GetMid(), GetEnd(), GetWidth() );
1013 }
1014 
1015 
TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET & aCornerBuffer,PCB_LAYER_ID aLayer,int aClearanceValue,int aError,ERROR_LOC aErrorLoc,bool ignoreLineWidth) const1016 void PCB_TRACK::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
1017                                                       PCB_LAYER_ID aLayer, int aClearanceValue,
1018                                                       int aError, ERROR_LOC aErrorLoc,
1019                                                       bool ignoreLineWidth ) const
1020 {
1021     wxASSERT_MSG( !ignoreLineWidth, "IgnoreLineWidth has no meaning for tracks." );
1022 
1023 
1024     switch( Type() )
1025     {
1026     case PCB_VIA_T:
1027     {
1028         int radius = ( m_Width / 2 ) + aClearanceValue;
1029         TransformCircleToPolygon( aCornerBuffer, m_Start, radius, aError, aErrorLoc );
1030         break;
1031     }
1032 
1033     case PCB_ARC_T:
1034     {
1035         const PCB_ARC* arc = static_cast<const PCB_ARC*>( this );
1036         int            width = m_Width + ( 2 * aClearanceValue );
1037 
1038         TransformArcToPolygon( aCornerBuffer, arc->GetStart(), arc->GetMid(),
1039                                arc->GetEnd(), width, aError, aErrorLoc );
1040         break;
1041     }
1042 
1043     default:
1044     {
1045         int width = m_Width + ( 2 * aClearanceValue );
1046 
1047         TransformOvalToPolygon( aCornerBuffer, m_Start, m_End, width, aError, aErrorLoc );
1048         break;
1049     }
1050     }
1051 }
1052 
1053 
1054 #if defined(DEBUG)
1055 
ShowState(int stateBits)1056 wxString PCB_TRACK::ShowState( int stateBits )
1057 {
1058     wxString ret;
1059 
1060     if( stateBits & IS_LINKED )
1061         ret << wxT( " | IS_LINKED" );
1062 
1063     if( stateBits & LOCKED )
1064         ret << wxT( " | LOCKED" );
1065 
1066     if( stateBits & IN_EDIT )
1067         ret << wxT( " | IN_EDIT" );
1068 
1069     if( stateBits & IS_DRAGGING )
1070         ret << wxT( " | IS_DRAGGING" );
1071 
1072     if( stateBits & DO_NOT_DRAW )
1073         ret << wxT( " | DO_NOT_DRAW" );
1074 
1075     if( stateBits & IS_DELETED )
1076         ret << wxT( " | IS_DELETED" );
1077 
1078     if( stateBits & END_ONPAD )
1079         ret << wxT( " | END_ONPAD" );
1080 
1081     if( stateBits & BEGIN_ONPAD )
1082         ret << wxT( " | BEGIN_ONPAD" );
1083 
1084     return ret;
1085 }
1086 
1087 #endif
1088 
1089 
1090 static struct TRACK_VIA_DESC
1091 {
TRACK_VIA_DESCTRACK_VIA_DESC1092     TRACK_VIA_DESC()
1093     {
1094         ENUM_MAP<VIATYPE>::Instance()
1095             .Undefined( VIATYPE::NOT_DEFINED )
1096             .Map( VIATYPE::THROUGH,      _HKI( "Through" ) )
1097             .Map( VIATYPE::BLIND_BURIED, _HKI( "Blind/buried" ) )
1098             .Map( VIATYPE::MICROVIA,     _HKI( "Micro" ) );
1099 
1100         ENUM_MAP<PCB_LAYER_ID>& layerEnum = ENUM_MAP<PCB_LAYER_ID>::Instance();
1101 
1102         if( layerEnum.Choices().GetCount() == 0 )
1103         {
1104             layerEnum.Undefined( UNDEFINED_LAYER );
1105 
1106             for( LSEQ seq = LSET::AllLayersMask().Seq(); seq; ++seq )
1107                 layerEnum.Map( *seq, LSET::Name( *seq ) );
1108         }
1109 
1110         PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
1111 
1112         // Track
1113         REGISTER_TYPE( PCB_TRACK );
1114         propMgr.InheritsAfter( TYPE_HASH( PCB_TRACK ), TYPE_HASH( BOARD_CONNECTED_ITEM ) );
1115 
1116         propMgr.AddProperty( new PROPERTY<PCB_TRACK, int>( _HKI( "Width" ),
1117             &PCB_TRACK::SetWidth, &PCB_TRACK::GetWidth, PROPERTY_DISPLAY::DISTANCE ) );
1118         propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Position X" ),
1119             new PROPERTY<PCB_TRACK, int, BOARD_ITEM>( _HKI( "Origin X" ),
1120             &PCB_TRACK::SetX, &PCB_TRACK::GetX, PROPERTY_DISPLAY::DISTANCE ) );
1121         propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Position Y" ),
1122             new PROPERTY<PCB_TRACK, int, BOARD_ITEM>( _HKI( "Origin Y" ),
1123             &PCB_TRACK::SetY, &PCB_TRACK::GetY, PROPERTY_DISPLAY::DISTANCE ) );
1124         propMgr.AddProperty( new PROPERTY<PCB_TRACK, int>( _HKI( "End X" ),
1125             &PCB_TRACK::SetEndX, &PCB_TRACK::GetEndX, PROPERTY_DISPLAY::DISTANCE ) );
1126         propMgr.AddProperty( new PROPERTY<PCB_TRACK, int>( _HKI( "End Y" ),
1127             &PCB_TRACK::SetEndY, &PCB_TRACK::GetEndY, PROPERTY_DISPLAY::DISTANCE ) );
1128 
1129         // Arc
1130         REGISTER_TYPE( PCB_ARC );
1131         propMgr.InheritsAfter( TYPE_HASH( PCB_ARC ), TYPE_HASH( BOARD_CONNECTED_ITEM ) );
1132 
1133         propMgr.AddProperty( new PROPERTY<PCB_TRACK, int>( _HKI( "Width" ),
1134             &PCB_ARC::SetWidth, &PCB_ARC::GetWidth, PROPERTY_DISPLAY::DISTANCE ) );
1135         propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Position X" ),
1136             new PROPERTY<PCB_ARC, int, BOARD_ITEM>( _HKI( "Origin X" ),
1137             &PCB_TRACK::SetX, &PCB_ARC::GetX, PROPERTY_DISPLAY::DISTANCE ) );
1138         propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Position Y" ),
1139             new PROPERTY<PCB_ARC, int, BOARD_ITEM>( _HKI( "Origin Y" ),
1140             &PCB_TRACK::SetY, &PCB_ARC::GetY, PROPERTY_DISPLAY::DISTANCE ) );
1141         propMgr.AddProperty( new PROPERTY<PCB_TRACK, int>( _HKI( "End X" ),
1142             &PCB_TRACK::SetEndX, &PCB_ARC::GetEndX, PROPERTY_DISPLAY::DISTANCE ) );
1143         propMgr.AddProperty( new PROPERTY<PCB_TRACK, int>( _HKI( "End Y" ),
1144             &PCB_TRACK::SetEndY, &PCB_ARC::GetEndY, PROPERTY_DISPLAY::DISTANCE ) );
1145 
1146         // Via
1147         REGISTER_TYPE( PCB_VIA );
1148         propMgr.InheritsAfter( TYPE_HASH( PCB_VIA ), TYPE_HASH( BOARD_CONNECTED_ITEM ) );
1149 
1150         // TODO layerset for vias?
1151         // TODO test drill, use getdrillvalue?
1152         propMgr.ReplaceProperty( TYPE_HASH( PCB_TRACK ), _HKI( "Width" ),
1153             new PROPERTY<PCB_VIA, int, PCB_TRACK>( _HKI( "Diameter" ),
1154             &PCB_VIA::SetWidth, &PCB_VIA::GetWidth, PROPERTY_DISPLAY::DISTANCE ) );
1155         propMgr.AddProperty( new PROPERTY<PCB_VIA, int>( _HKI( "Drill" ),
1156             &PCB_VIA::SetDrill, &PCB_VIA::GetDrillValue, PROPERTY_DISPLAY::DISTANCE ) );
1157         propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Layer" ),
1158             new PROPERTY_ENUM<PCB_VIA, PCB_LAYER_ID, BOARD_ITEM>( _HKI( "Layer Top" ),
1159             &PCB_VIA::SetLayer, &PCB_VIA::GetLayer ) );
1160         propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, PCB_LAYER_ID>( _HKI( "Layer Bottom" ),
1161             &PCB_VIA::SetBottomLayer, &PCB_VIA::BottomLayer ) );
1162         propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, VIATYPE>( _HKI( "Via Type" ),
1163             &PCB_VIA::SetViaType, &PCB_VIA::GetViaType ) );
1164     }
1165 } _TRACK_VIA_DESC;
1166 
1167 ENUM_TO_WXANY( VIATYPE );
1168