KiCad PCB EDA Suite
class_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, jean-pierre.charras@ujf-grenoble.fr
5  * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
6  * Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
7  * Copyright (C) 1992-2016 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 
33 #include <fctsys.h>
34 #include <gr_basic.h>
35 #include <common.h>
36 #include <trigo.h>
37 #include <macros.h>
38 #include <class_drawpanel.h>
39 #include <pcb_screen.h>
40 #include <draw_graphic_text.h>
41 #include <pcb_base_frame.h>
42 #include <class_board.h>
43 #include <class_track.h>
44 #include <pcbnew.h>
45 #include <base_units.h>
46 #include <msgpanel.h>
47 #include <bitmaps.h>
48 #include <view/view.h>
49 
55 static bool ShowClearance( PCB_DISPLAY_OPTIONS* aDisplOpts, const TRACK* aTrack )
56 {
57  // maybe return true for tracks and vias, not for zone segments
58  return IsCopperLayer( aTrack->GetLayer() )
59  && ( aTrack->Type() == PCB_TRACE_T || aTrack->Type() == PCB_VIA_T )
61  && ( aTrack->IsDragging() || aTrack->IsMoving() || aTrack->IsNew() ) )
63  );
64 
65 }
66 
67 
68 TRACK* GetTrack( TRACK* aStartTrace, const TRACK* aEndTrace,
69  const wxPoint& aPosition, LSET aLayerMask )
70 {
71  for( TRACK* seg = aStartTrace; seg; seg = seg->Next() )
72  {
73  if( seg->GetState( IS_DELETED | BUSY ) == 0 )
74  {
75  if( aPosition == seg->GetStart() )
76  {
77  if( ( aLayerMask & seg->GetLayerSet() ).any() )
78  return seg;
79  }
80 
81  if( aPosition == seg->GetEnd() )
82  {
83  if( ( aLayerMask & seg->GetLayerSet() ).any() )
84  return seg;
85  }
86  }
87 
88  if( seg == aEndTrace )
89  break;
90  }
91 
92  return NULL;
93 }
94 
95 
96 TRACK::TRACK( BOARD_ITEM* aParent, KICAD_T idtype ) :
97  BOARD_CONNECTED_ITEM( aParent, idtype )
98 {
99  m_Width = Millimeter2iu( 0.2 );
100  start = end = NULL;
101  m_Param = 0;
102 }
103 
104 
106 {
107  return new TRACK( *this );
108 }
109 
110 
111 VIA::VIA( BOARD_ITEM* aParent ) :
112  TRACK( aParent, PCB_VIA_T )
113 {
116  SetDrillDefault();
117 }
118 
119 
121 {
122  return new VIA( *this );
123 }
124 
125 
126 wxString VIA::GetSelectMenuText( EDA_UNITS_T aUnits ) const
127 {
128  wxString format;
129  BOARD* board = GetBoard();
130 
131  switch( GetViaType() )
132  {
133  case VIA_BLIND_BURIED:
134  format = _( "Blind/Buried Via %s %s on %s - %s" );
135  break;
136  case VIA_MICROVIA:
137  format = _( "Micro Via %s %s on %s - %s" );
138  break;
139  // else say nothing about normal (through) vias
140  default:
141  format = _( "Via %s %s on %s - %s" );
142  break;
143  }
144 
145  if( board )
146  {
147  // say which layers, only two for now
148  PCB_LAYER_ID topLayer;
149  PCB_LAYER_ID botLayer;
150  LayerPair( &topLayer, &botLayer );
151  return wxString::Format( format.GetData(),
152  MessageTextFromValue( aUnits, m_Width ),
153  GetNetnameMsg(),
154  board->GetLayerName( topLayer ),
155  board->GetLayerName( botLayer ) );
156 
157  }
158  else
159  {
160  return wxString::Format( format.GetData(),
161  MessageTextFromValue( aUnits, m_Width ),
162  GetNetnameMsg(),
163  wxT( "??" ),
164  wxT( "??" ) );
165  }
166 }
167 
168 
169 BITMAP_DEF VIA::GetMenuImage() const
170 {
171  return via_xpm;
172 }
173 
174 
176 {
177  // Currently tracks have no specific clearance parameter on a per track or per
178  // segment basis. The NETCLASS clearance is used.
179  return BOARD_CONNECTED_ITEM::GetClearance( aItem );
180 }
181 
182 
184 {
185  if( m_Drill > 0 ) // Use the specific value.
186  return m_Drill;
187 
188  // Use the default value from the Netclass
189  NETCLASSPTR netclass = GetNetClass();
190 
191  if( GetViaType() == VIA_MICROVIA )
192  return netclass->GetuViaDrill();
193 
194  return netclass->GetViaDrill();
195 }
196 
197 
199 {
200  if( ( Type() != PCB_VIA_T ) && ( m_Start == m_End ) )
201  return true;
202  else
203  return false;
204 }
205 
206 
207 STATUS_FLAGS TRACK::IsPointOnEnds( const wxPoint& point, int min_dist )
208 {
209  STATUS_FLAGS result = 0;
210 
211  if( min_dist < 0 )
212  min_dist = m_Width / 2;
213 
214  if( min_dist == 0 )
215  {
216  if( m_Start == point )
217  result |= STARTPOINT;
218 
219  if( m_End == point )
220  result |= ENDPOINT;
221  }
222  else
223  {
224  double dist = GetLineLength( m_Start, point );
225 
226  if( min_dist >= KiROUND( dist ) )
227  result |= STARTPOINT;
228 
229  dist = GetLineLength( m_End, point );
230 
231  if( min_dist >= KiROUND( dist ) )
232  result |= ENDPOINT;
233  }
234 
235  return result;
236 }
237 
238 
240 {
241  // end of track is round, this is its radius, rounded up
242  int radius = ( m_Width + 1 ) / 2;
243  int ymax, xmax, ymin, xmin;
244 
245  if( Type() == PCB_VIA_T )
246  {
247  ymax = m_Start.y;
248  xmax = m_Start.x;
249 
250  ymin = m_Start.y;
251  xmin = m_Start.x;
252  }
253  else
254  {
255  ymax = std::max( m_Start.y, m_End.y );
256  xmax = std::max( m_Start.x, m_End.x );
257 
258  ymin = std::min( m_Start.y, m_End.y );
259  xmin = std::min( m_Start.x, m_End.x );
260  }
261 
262  ymax += radius;
263  xmax += radius;
264 
265  ymin -= radius;
266  xmin -= radius;
267 
268  // return a rectangle which is [pos,dim) in nature. therefore the +1
269  EDA_RECT ret( wxPoint( xmin, ymin ), wxSize( xmax - xmin + 1, ymax - ymin + 1 ) );
270 
271  return ret;
272 }
273 
274 
275 void TRACK::Rotate( const wxPoint& aRotCentre, double aAngle )
276 {
277  RotatePoint( &m_Start, aRotCentre, aAngle );
278  RotatePoint( &m_End, aRotCentre, aAngle );
279 }
280 
281 
282 void TRACK::Flip( const wxPoint& aCentre )
283 {
284  m_Start.y = aCentre.y - (m_Start.y - aCentre.y);
285  m_End.y = aCentre.y - (m_End.y - aCentre.y);
286  int copperLayerCount = GetBoard()->GetCopperLayerCount();
287  SetLayer( FlipLayer( GetLayer(), copperLayerCount ) );
288 }
289 
290 
291 void VIA::Flip( const wxPoint& aCentre )
292 {
293  m_Start.y = aCentre.y - (m_Start.y - aCentre.y);
294  m_End.y = aCentre.y - (m_End.y - aCentre.y);
295 
296  if( GetViaType() != VIA_THROUGH )
297  {
298  int copperLayerCount = GetBoard()->GetCopperLayerCount();
299  PCB_LAYER_ID top_layer;
300  PCB_LAYER_ID bottom_layer;
301  LayerPair( &top_layer, &bottom_layer );
302  top_layer = FlipLayer( top_layer, copperLayerCount );
303  bottom_layer = FlipLayer( bottom_layer, copperLayerCount );
304  SetLayerPair( top_layer, bottom_layer );
305  }
306 }
307 
308 
309 // see class_track.h
310 SEARCH_RESULT TRACK::Visit( INSPECTOR inspector, void* testData, const KICAD_T scanTypes[] )
311 {
312  KICAD_T stype = *scanTypes;
313 
314  // If caller wants to inspect my type
315  if( stype == Type() )
316  {
317  if( SEARCH_QUIT == inspector( this, testData ) )
318  return SEARCH_QUIT;
319  }
320 
321  return SEARCH_CONTINUE;
322 }
323 
324 
325 bool VIA::IsOnLayer( PCB_LAYER_ID layer_number ) const
326 {
327  PCB_LAYER_ID bottom_layer, top_layer;
328 
329  LayerPair( &top_layer, &bottom_layer );
330 
331  wxASSERT( top_layer <= bottom_layer );
332 
333  if( top_layer <= layer_number && layer_number <= bottom_layer )
334  return true;
335  else
336  return false;
337 }
338 
339 
341 {
342  if( GetViaType() == VIA_THROUGH )
343  return LSET::AllCuMask();
344 
345  // VIA_BLIND_BURIED or VIA_MICRVIA:
346 
347  LSET layermask;
348 
349  wxASSERT( m_Layer <= m_BottomLayer );
350 
351  // PCB_LAYER_IDs are numbered from front to back, this is top to bottom.
352  for( LAYER_NUM id = m_Layer; id <= m_BottomLayer; ++id )
353  {
354  layermask.set( id );
355  }
356 
357  return layermask;
358 }
359 
360 
361 void VIA::SetLayerPair( PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer )
362 {
363 
364  m_Layer = aTopLayer;
365  m_BottomLayer = aBottomLayer;
366  SanitizeLayers();
367 }
368 
369 
371 {
372  m_Layer = aLayer;
373 }
374 
375 
377 {
378  m_BottomLayer = aLayer;
379 }
380 
381 
382 void VIA::LayerPair( PCB_LAYER_ID* top_layer, PCB_LAYER_ID* bottom_layer ) const
383 {
384  PCB_LAYER_ID t_layer = F_Cu;
385  PCB_LAYER_ID b_layer = B_Cu;
386 
387  if( GetViaType() != VIA_THROUGH )
388  {
389  b_layer = m_BottomLayer;
390  t_layer = m_Layer;
391 
392  if( b_layer < t_layer )
393  std::swap( b_layer, t_layer );
394  }
395 
396  if( top_layer )
397  *top_layer = t_layer;
398 
399  if( bottom_layer )
400  *bottom_layer = b_layer;
401 }
402 
403 
405 {
406  return m_Layer;
407 }
408 
409 
411 {
412  return m_BottomLayer;
413 }
414 
415 
417 {
418  if( GetViaType() == VIA_THROUGH )
419  {
420  m_Layer = F_Cu;
422  }
423 
424  if( m_BottomLayer < m_Layer )
425  std::swap( m_BottomLayer, m_Layer );
426 }
427 
428 
430 {
431  // When reading from a file most of the items will already be in the correct order.
432  // Searching from the back therefore takes us from n^2 to essentially 0.
433 
434  for( TRACK* track = aPcb->m_Track.GetLast(); track; track = track->Back() )
435  {
436  if( GetNetCode() >= track->GetNetCode() )
437  return track->Next();
438  }
439 
440  return aPcb->m_Track.GetFirst();
441 }
442 
443 
445 {
446  TRACK* Track = this;
447  int ii = 0;
448 
449  if( NetCode == -1 )
450  NetCode = GetNetCode();
451 
452  while( Track != NULL )
453  {
454  if( Track->GetNetCode() > NetCode )
455  break;
456 
457  if( Track->GetNetCode() == NetCode )
458  {
459  ii++;
460  break;
461  }
462 
463  Track = (TRACK*) Track->Pnext;
464  }
465 
466  if( ii )
467  return Track;
468  else
469  return NULL;
470 }
471 
472 
474 {
475  TRACK* NextS, * Track = this;
476  int ii = 0;
477 
478  if( Track == NULL )
479  return NULL;
480 
481  if( NetCode == -1 )
482  NetCode = GetNetCode();
483 
484  while( Track != NULL )
485  {
486  NextS = (TRACK*) Track->Pnext;
487 
488  if( Track->GetNetCode() == NetCode )
489  ii++;
490 
491  if( NextS == NULL )
492  break;
493 
494  if( NextS->GetNetCode() > NetCode )
495  break;
496 
497  Track = NextS;
498  }
499 
500  if( ii )
501  return Track;
502  else
503  return NULL;
504 }
505 
507  wxDC* aDC, GR_DRAWMODE aDrawMode, COLOR4D aBgColor )
508 {
509  if( ! panel )
510  return;
511 
512  /* we must filter tracks, to avoid a lot of texts.
513  * - only tracks with a length > 10 * thickness are eligible
514  * and, of course, if we are not printing the board
515  */
516  auto displ_opts = (PCB_DISPLAY_OPTIONS*)( panel->GetDisplayOptions() );
517 
518  if( displ_opts->m_DisplayNetNamesMode == 0 || displ_opts->m_DisplayNetNamesMode == 1 )
519  return;
520 
521  #define THRESHOLD 10
522 
523  int len = KiROUND( GetLineLength( m_Start, m_End ) );
524 
525  if( len < THRESHOLD * m_Width )
526  return;
527 
528  // no room to display a text inside track
529  if( aDC->LogicalToDeviceXRel( m_Width ) < MIN_TEXT_SIZE )
530  return;
531 
533  return;
534 
535  NETINFO_ITEM* net = GetNet();
536 
537  if( net == NULL )
538  return;
539 
540  wxString text = UnescapeString( net->GetShortNetname() );
541  int textlen = text.Len();
542 
543  if( textlen > 0 )
544  {
545  // calculate a good size for the text
546  int tsize = std::min( m_Width, len / textlen );
547  int dx = m_End.x - m_Start.x ;
548  int dy = m_End.y - m_Start.y ;
549  wxPoint tpos = m_Start + m_End;
550  tpos.x /= 2;
551  tpos.y /= 2;
552 
553  // Calculate angle: if the track segment is vertical, angle = 90 degrees
554  // If horizontal 0 degrees, otherwise compute it
555  double angle; // angle is in 0.1 degree
556 
557  if( dy == 0 ) // Horizontal segment
558  {
559  angle = 0;
560  }
561  else
562  {
563  if( dx == 0 ) // Vertical segment
564  {
565  angle = 900;
566  }
567  else
568  {
569  /* atan2 is *not* the solution here, since it can give upside
570  down text. We want to work only in the first and fourth quadrant */
571  angle = RAD2DECIDEG( -atan( double( dy ) / double( dx ) ) );
572  }
573  }
574 
575  PCB_LAYER_ID curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer;
576 
577  if( ( aDC->LogicalToDeviceXRel( tsize ) >= MIN_TEXT_SIZE )
578  && ( !(!IsOnLayer( curr_layer )&& displ_opts->m_ContrastModeDisplay) ) )
579  {
580  if( (aDrawMode & GR_XOR) == 0 )
581  GRSetDrawMode( aDC, GR_COPY );
582 
583  tsize = (tsize * 7) / 10; // small reduction to give a better look
584  DrawGraphicHaloText( panel->GetClipBox(), aDC, tpos,
585  aBgColor, BLACK, WHITE,
586  text, angle, wxSize( tsize, tsize ),
588  tsize / 7, false, false );
589  }
590  }
591 }
592 
593 
594 void TRACK::Draw( EDA_DRAW_PANEL* panel, wxDC* aDC, GR_DRAWMODE aDrawMode,
595  const wxPoint& aOffset )
596 {
597  BOARD* brd = GetBoard();
598 
599  auto frame = static_cast<PCB_BASE_FRAME*> ( panel->GetParent() );
600  auto color = frame->Settings().Colors().GetLayerColor( m_Layer );
601 
602  if( ( !brd->IsLayerVisible( m_Layer ) || !brd->IsElementVisible( LAYER_TRACKS ) )
603  && !( aDrawMode & GR_HIGHLIGHT ) )
604  return;
605 
606 #ifdef USE_WX_OVERLAY
607  // If dragged not draw in OnPaint otherwise remains impressed in wxOverlay
608  if( (m_Flags & IS_DRAGGED) && aDC->IsKindOf(wxCLASSINFO(wxPaintDC)))
609  return;
610 #endif
611 
612  auto displ_opts = (PCB_DISPLAY_OPTIONS*)( panel->GetDisplayOptions() );
613 
614  if( ( aDrawMode & GR_ALLOW_HIGHCONTRAST ) && displ_opts->m_ContrastModeDisplay )
615  {
616  PCB_LAYER_ID curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer;
617 
618  if( !IsOnLayer( curr_layer ) )
620  }
621 
622  if( ( aDrawMode & GR_HIGHLIGHT ) && !( aDrawMode & GR_AND ) )
623  color.SetToLegacyHighlightColor();
624 
625  color.a = 0.588;
626 
627  GRSetDrawMode( aDC, aDrawMode );
628 
629  // Draw track as line if width <= 1pixel:
630  if( aDC->LogicalToDeviceXRel( m_Width ) <= 1 )
631  {
632  GRLine( panel->GetClipBox(), aDC, m_Start + aOffset, m_End + aOffset, m_Width, color );
633  return;
634  }
635 
636  if( !displ_opts->m_DisplayPcbTrackFill || GetState( FORCE_SKETCH ) )
637  {
638  GRCSegm( panel->GetClipBox(), aDC, m_Start + aOffset, m_End + aOffset, m_Width, color );
639  }
640  else
641  {
642  GRFillCSegm( panel->GetClipBox(), aDC, m_Start.x + aOffset.x,
643  m_Start.y + aOffset.y,
644  m_End.x + aOffset.x, m_End.y + aOffset.y, m_Width, color );
645  }
646 
647  if( panel->GetScreen()->m_IsPrinting )
648  return;
649 
650  // Show clearance for tracks, not for zone segments
651  if( ShowClearance( displ_opts, this ) )
652  {
653  GRCSegm( panel->GetClipBox(), aDC, m_Start + aOffset, m_End + aOffset,
654  m_Width + (GetClearance() * 2), color );
655  }
656 
657  DrawShortNetname( panel, aDC, aDrawMode, color );
658 }
659 
660 
661 void TRACK::ViewGetLayers( int aLayers[], int& aCount ) const
662 {
663  // Show the track and its netname on different layers
664  aLayers[0] = GetLayer();
665  aLayers[1] = GetNetnameLayer( aLayers[0] );
666  aCount = 2;
667 }
668 
669 
670 unsigned int TRACK::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
671 {
672  const int HIDE = std::numeric_limits<unsigned int>::max();
673 
674  if( !aView->IsLayerVisible( LAYER_TRACKS ) )
675  return HIDE;
676 
677  // Netnames will be shown only if zoom is appropriate
678  if( IsNetnameLayer( aLayer ) )
679  {
680  return ( Millimeter2iu( 4 ) / ( m_Width + 1 ) );
681  }
682 
683  // Other layers are shown without any conditions
684  return 0;
685 }
686 
687 
688 const BOX2I TRACK::ViewBBox() const
689 {
690  BOX2I bbox = GetBoundingBox();
691  bbox.Inflate( 2 * GetClearance() );
692  return bbox;
693 }
694 
695 
696 void VIA::Draw( EDA_DRAW_PANEL* panel, wxDC* aDC, GR_DRAWMODE aDrawMode, const wxPoint& aOffset )
697 {
698  wxCHECK_RET( panel != NULL, wxT( "VIA::Draw panel cannot be NULL." ) );
699 
700  int radius;
701  PCB_LAYER_ID curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer;
702 
703  int fillvia = 0;
704  PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) panel->GetParent();
705  PCB_SCREEN* screen = frame->GetScreen();
706  auto displ_opts = (PCB_DISPLAY_OPTIONS*)( frame->GetDisplayOptions() );
707 
708  if( displ_opts->m_DisplayViaFill == FILLED )
709  fillvia = 1;
710 
711  GRSetDrawMode( aDC, aDrawMode );
712 
713  BOARD * brd = GetBoard();
715 
716  if( brd->IsElementVisible( LAYER_VIAS + GetViaType() ) == false
717  && !( aDrawMode & GR_HIGHLIGHT ) )
718  return;
719 
720  // Only draw the via if at least one of the layers it crosses is being displayed
721  if( !( brd->GetVisibleLayers() & GetLayerSet() ).any() )
722  return;
723 
724  if( displ_opts->m_ContrastModeDisplay )
725  {
726  if( !IsOnLayer( curr_layer ) )
728  }
729 
730  if( ( aDrawMode & GR_HIGHLIGHT ) && !( aDrawMode & GR_AND ) )
731  color.SetToLegacyHighlightColor();
732 
733  color.a = 0.588;
734 
735 
736  radius = m_Width >> 1;
737  // for small via size on screen (radius < 4 pixels) draw a simplified shape
738 
739  int radius_in_pixels = aDC->LogicalToDeviceXRel( radius );
740 
741  bool fast_draw = false;
742 
743  // Vias are drawn as a filled circle or a double circle. The hole will be drawn later
744  int drill_radius = GetDrillValue() / 2;
745 
746  int inner_radius = radius - aDC->DeviceToLogicalXRel( 2 );
747 
748  if( radius_in_pixels < MIN_VIA_DRAW_SIZE )
749  {
750  fast_draw = true;
751  fillvia = false;
752  }
753 
754  if( fillvia )
755  {
756  GRFilledCircle( panel->GetClipBox(), aDC, m_Start + aOffset, radius, color );
757  }
758  else
759  {
760  GRCircle( panel->GetClipBox(), aDC, m_Start + aOffset, radius, 0, color );
761 
762  if ( fast_draw )
763  return;
764 
765  GRCircle( panel->GetClipBox(), aDC, m_Start + aOffset, inner_radius, 0, color );
766  }
767 
768  if( fillvia )
769  {
770  bool blackpenstate = false;
771 
772  if( screen->m_IsPrinting )
773  {
774  blackpenstate = GetGRForceBlackPenState();
775  GRForceBlackPen( false );
776  color = WHITE;
777  }
778  else
779  {
780  color = BLACK; // or DARKGRAY;
781  }
782 
783  if( (aDrawMode & GR_XOR) == 0)
784  GRSetDrawMode( aDC, GR_COPY );
785 
786  // Draw hole if the radius is > 1pixel.
787  if( aDC->LogicalToDeviceXRel( drill_radius ) > 1 )
788  GRFilledCircle( panel->GetClipBox(), aDC, m_Start.x + aOffset.x,
789  m_Start.y + aOffset.y, drill_radius, 0, color, color );
790 
791  if( screen->m_IsPrinting )
792  GRForceBlackPen( blackpenstate );
793  }
794  else
795  {
796  if( drill_radius < inner_radius ) // We can show the via hole
797  GRCircle( panel->GetClipBox(), aDC, m_Start + aOffset, drill_radius, 0, color );
798  }
799 
800  if( ShowClearance( displ_opts, this ) )
801  {
802  GRCircle( panel->GetClipBox(), aDC, m_Start + aOffset, radius + GetClearance(), 0, color );
803  }
804 
805  // for Micro Vias, draw a partial cross : X on component layer, or + on copper layer
806  // (so we can see 2 superimposed microvias ):
807  if( GetViaType() == VIA_MICROVIA )
808  {
809  int ax, ay, bx, by;
810 
811  if( IsOnLayer( B_Cu ) )
812  {
813  ax = radius; ay = 0;
814  bx = drill_radius; by = 0;
815  }
816  else
817  {
818  ax = ay = (radius * 707) / 1000;
819  bx = by = (drill_radius * 707) / 1000;
820  }
821 
822  // lines '|' or '\'
823  GRLine( panel->GetClipBox(), aDC, m_Start.x + aOffset.x - ax,
824  m_Start.y + aOffset.y - ay,
825  m_Start.x + aOffset.x - bx,
826  m_Start.y + aOffset.y - by, 0, color );
827  GRLine( panel->GetClipBox(), aDC, m_Start.x + aOffset.x + bx,
828  m_Start.y + aOffset.y + by,
829  m_Start.x + aOffset.x + ax,
830  m_Start.y + aOffset.y + ay, 0, color );
831 
832  // lines - or '/'
833  GRLine( panel->GetClipBox(), aDC, m_Start.x + aOffset.x + ay,
834  m_Start.y + aOffset.y - ax,
835  m_Start.x + aOffset.x + by,
836  m_Start.y + aOffset.y - bx, 0, color );
837  GRLine( panel->GetClipBox(), aDC, m_Start.x + aOffset.x - by,
838  m_Start.y + aOffset.y + bx,
839  m_Start.x + aOffset.x - ay,
840  m_Start.y + aOffset.y + ax, 0, color );
841  }
842 
843  // for Buried Vias, draw a partial line : orient depending on layer pair
844  // (so we can see superimposed buried vias ):
845  if( GetViaType() == VIA_BLIND_BURIED )
846  {
847  int ax = 0, ay = radius, bx = 0, by = drill_radius;
848  PCB_LAYER_ID layer_top, layer_bottom;
849 
850  LayerPair( &layer_top, &layer_bottom );
851 
852  // lines for the top layer
853  RotatePoint( &ax, &ay, layer_top * 3600.0 / brd->GetCopperLayerCount( ) );
854  RotatePoint( &bx, &by, layer_top * 3600.0 / brd->GetCopperLayerCount( ) );
855  GRLine( panel->GetClipBox(), aDC, m_Start.x + aOffset.x - ax,
856  m_Start.y + aOffset.y - ay,
857  m_Start.x + aOffset.x - bx,
858  m_Start.y + aOffset.y - by, 0, color );
859 
860  // lines for the bottom layer
861  ax = 0; ay = radius; bx = 0; by = drill_radius;
862  RotatePoint( &ax, &ay, layer_bottom * 3600.0 / brd->GetCopperLayerCount( ) );
863  RotatePoint( &bx, &by, layer_bottom * 3600.0 / brd->GetCopperLayerCount( ) );
864  GRLine( panel->GetClipBox(), aDC, m_Start.x + aOffset.x - ax,
865  m_Start.y + aOffset.y - ay,
866  m_Start.x + aOffset.x - bx,
867  m_Start.y + aOffset.y - by, 0, color );
868  }
869 
870  // Display the short netname:
872  return;
873 
874  if( displ_opts->m_DisplayNetNamesMode == 0 || displ_opts->m_DisplayNetNamesMode == 1 )
875  return;
876 
877  NETINFO_ITEM* net = GetNet();
878 
879  if( net == NULL )
880  return;
881 
882  wxString text = UnescapeString( net->GetShortNetname() );
883  int len = text.Len();
884 
885  if( len > 0 )
886  {
887  // calculate a good size for the text
888  int tsize = m_Width / len;
889 
890  if( aDC->LogicalToDeviceXRel( tsize ) >= MIN_TEXT_SIZE )
891  {
892  tsize = (tsize * 7) / 10; // small reduction to give a better look, inside via
893 
894  if( (aDrawMode & GR_XOR) == 0 )
895  GRSetDrawMode( aDC, GR_COPY );
896 
897  EDA_RECT* clipbox = panel->GetClipBox();
898  DrawGraphicHaloText( clipbox, aDC, m_Start,
899  color, WHITE, BLACK,
900  text, 0, wxSize( tsize, tsize ),
902  tsize / 7, false, false );
903  }
904  }
905 }
906 
907 
908 void VIA::ViewGetLayers( int aLayers[], int& aCount ) const
909 {
910  aLayers[0] = LAYER_VIAS_HOLES;
911  aLayers[1] = LAYER_VIAS_NETNAMES;
912  aCount = 3;
913 
914  // Just show it on common via & via holes layers
915  switch( GetViaType() )
916  {
917  case VIA_THROUGH:
918  aLayers[2] = LAYER_VIA_THROUGH;
919  break;
920 
921  case VIA_BLIND_BURIED:
922  aLayers[2] = LAYER_VIA_BBLIND;
923  aLayers[3] = m_Layer;
924  aLayers[4] = m_BottomLayer;
925  aCount += 2;
926  break;
927 
928  case VIA_MICROVIA:
929  aLayers[2] = LAYER_VIA_MICROVIA;
930  break;
931 
932  default:
933  aLayers[2] = LAYER_GP_OVERLAY;
934  wxASSERT( false );
935  break;
936  }
937 }
938 
939 
940 unsigned int VIA::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
941 {
942  constexpr unsigned int HIDE = std::numeric_limits<unsigned int>::max();
943 
944  // Netnames will be shown only if zoom is appropriate
945  if( IsNetnameLayer( aLayer ) )
946  return m_Width == 0 ? HIDE : ( Millimeter2iu( 10 ) / m_Width );
947 
948 
949  BOARD* board = GetBoard();
950 
951  // Only draw the via if at least one of the layers it crosses is being displayed
952  if( board && ( board->GetVisibleLayers() & GetLayerSet() ).any() )
953  return 0;
954 
955  return HIDE;
956 }
957 
958 
959 // see class_track.h
960 void TRACK::GetMsgPanelInfo( EDA_UNITS_T aUnits, std::vector< MSG_PANEL_ITEM >& aList )
961 {
962  wxString msg;
963  BOARD* board = GetBoard();
964 
965  // Display basic infos
966  GetMsgPanelInfoBase( aUnits, aList );
967 
968  // Display full track length (in Pcbnew)
969  if( board )
970  {
971  double trackLen = 0;
972  double lenPadToDie = 0;
973 
974  // Find the beginning of the track buffer containing this, because it is not
975  // always the track list on board, but can be a "private" list
976  TRACK* track_buffer_start = this;
977 
978  while( track_buffer_start->Back() )
979  track_buffer_start = track_buffer_start->Back();
980 
981  board->MarkTrace( track_buffer_start, this, NULL, &trackLen, &lenPadToDie, false );
982  msg = MessageTextFromValue( aUnits, trackLen );
983  aList.push_back( MSG_PANEL_ITEM( _( "Length" ), msg, DARKCYAN ) );
984 
985  if( lenPadToDie != 0 )
986  {
987  msg = MessageTextFromValue( aUnits, trackLen + lenPadToDie );
988  aList.push_back( MSG_PANEL_ITEM( _( "Full Length" ), msg, DARKCYAN ) );
989 
990  msg = MessageTextFromValue( aUnits, lenPadToDie, true );
991  aList.push_back( MSG_PANEL_ITEM( _( "Pad To Die Length" ), msg, DARKCYAN ) );
992  }
993  }
994 
995  NETCLASSPTR netclass = GetNetClass();
996 
997  if( netclass )
998  {
999  aList.push_back( MSG_PANEL_ITEM( _( "NC Name" ), netclass->GetName(), DARKMAGENTA ) );
1000 
1001  msg = MessageTextFromValue( aUnits, netclass->GetClearance(), true );
1002  aList.push_back( MSG_PANEL_ITEM( _( "NC Clearance" ), msg, DARKMAGENTA ) );
1003 
1004  msg = MessageTextFromValue( aUnits, netclass->GetTrackWidth(), true );
1005  aList.push_back( MSG_PANEL_ITEM( _( "NC Width" ), msg, DARKMAGENTA ) );
1006 
1007  msg = MessageTextFromValue( aUnits, netclass->GetViaDiameter(), true );
1008  aList.push_back( MSG_PANEL_ITEM( _( "NC Via Size" ), msg, DARKMAGENTA ) );
1009 
1010  msg = MessageTextFromValue( aUnits, netclass->GetViaDrill(), true );
1011  aList.push_back( MSG_PANEL_ITEM( _( "NC Via Drill"), msg, DARKMAGENTA ) );
1012  }
1013 }
1014 
1015 void TRACK::GetMsgPanelInfoBase_Common( EDA_UNITS_T aUnits, std::vector< MSG_PANEL_ITEM >& aList )
1016 {
1017  wxString msg;
1018 
1019  // Display Net Name
1020  if( GetBoard() )
1021  {
1022  NETINFO_ITEM* net = GetNet();
1023 
1024  if( net )
1025  msg = UnescapeString( net->GetNetname() );
1026  else
1027  msg = wxT( "<no name>" );
1028 
1029  aList.push_back( MSG_PANEL_ITEM( _( "NetName" ), msg, RED ) );
1030 
1031  // Display net code : (useful in test or debug)
1032  msg.Printf( wxT( "%d" ), GetNetCode() );
1033  aList.push_back( MSG_PANEL_ITEM( _( "NetCode" ), msg, RED ) );
1034  }
1035 
1036 #if defined(DEBUG)
1037 
1038  // Display the flags
1039  msg.Printf( wxT( "0x%08X" ), m_Flags );
1040  aList.push_back( MSG_PANEL_ITEM( wxT( "Flags" ), msg, BLUE ) );
1041 
1042 #if 0
1043  // Display start and end pointers:
1044  msg.Printf( wxT( "%p" ), start );
1045  aList.push_back( MSG_PANEL_ITEM( wxT( "start ptr" ), msg, BLUE ) );
1046  msg.Printf( wxT( "%p" ), end );
1047  aList.push_back( MSG_PANEL_ITEM( wxT( "end ptr" ), msg, BLUE ) );
1048  // Display this ptr
1049  msg.Printf( wxT( "%p" ), this );
1050  aList.push_back( MSG_PANEL_ITEM( wxT( "this" ), msg, BLUE ) );
1051 #endif
1052 
1053 #if 0
1054  // Display start and end positions:
1055  msg.Printf( wxT( "%d %d" ), m_Start.x, m_Start.y );
1056  aList.push_back( MSG_PANEL_ITEM( wxT( "Start pos" ), msg, BLUE ) );
1057  msg.Printf( wxT( "%d %d" ), m_End.x, m_End.y );
1058  aList.push_back( MSG_PANEL_ITEM( wxT( "End pos" ), msg, BLUE ) );
1059 #endif
1060 
1061 #endif // defined(DEBUG)
1062 
1063  // Display the State member
1064  msg = wxT( ". . " );
1065 
1066  if( GetState( TRACK_LOCKED ) )
1067  msg[0] = 'L';
1068 
1069  if( GetState( TRACK_AR ) )
1070  msg[2] = 'A';
1071 
1072  aList.push_back( MSG_PANEL_ITEM( _( "Status" ), msg, MAGENTA ) );
1073 }
1074 
1075 void TRACK::GetMsgPanelInfoBase( EDA_UNITS_T aUnits, std::vector< MSG_PANEL_ITEM >& aList )
1076 {
1077  wxString msg;
1078  BOARD* board = GetBoard();
1079 
1080  aList.push_back( MSG_PANEL_ITEM( _( "Type" ), _( "Track" ), DARKCYAN ) );
1081 
1082  GetMsgPanelInfoBase_Common( aUnits, aList );
1083 
1084  // Display layer
1085  if( board )
1086  msg = board->GetLayerName( m_Layer );
1087  else
1088  msg.Printf(wxT("%d"), m_Layer );
1089 
1090  aList.push_back( MSG_PANEL_ITEM( _( "Layer" ), msg, BROWN ) );
1091 
1092  // Display width
1093  msg = MessageTextFromValue( aUnits, m_Width, true );
1094 
1095  aList.push_back( MSG_PANEL_ITEM( _( "Width" ), msg, DARKCYAN ) );
1096 
1097  // Display segment length
1098  msg = ::MessageTextFromValue( aUnits, GetLength() );
1099  aList.push_back( MSG_PANEL_ITEM( _( "Segment Length" ), msg, DARKCYAN ) );
1100 }
1101 
1102 void VIA::GetMsgPanelInfoBase( EDA_UNITS_T aUnits, std::vector< MSG_PANEL_ITEM >& aList )
1103 {
1104  wxString msg;
1105  BOARD* board = GetBoard();
1106 
1107  switch( GetViaType() )
1108  {
1109  default:
1110  case VIA_NOT_DEFINED:
1111  msg = wxT( "???" ); // Not used yet, does not exist currently
1112  break;
1113 
1114  case VIA_MICROVIA:
1115  msg = _( "Micro Via" ); // from external layer (TOP or BOTTOM) from
1116  // the near neighbor inner layer only
1117  break;
1118 
1119  case VIA_BLIND_BURIED:
1120  msg = _( "Blind/Buried Via" ); // from inner or external to inner
1121  // or external layer (no restriction)
1122  break;
1123 
1124  case VIA_THROUGH:
1125  msg = _( "Through Via" ); // Usual via (from TOP to BOTTOM layer only )
1126  break;
1127  }
1128 
1129  aList.push_back( MSG_PANEL_ITEM( _( "Type" ), msg, DARKCYAN ) );
1130 
1131  GetMsgPanelInfoBase_Common( aUnits, aList );
1132 
1133 
1134  // Display layer pair
1135  PCB_LAYER_ID top_layer, bottom_layer;
1136 
1137  LayerPair( &top_layer, &bottom_layer );
1138 
1139  if( board )
1140  msg = board->GetLayerName( top_layer ) + wxT( "/" )
1141  + board->GetLayerName( bottom_layer );
1142  else
1143  msg.Printf( wxT( "%d/%d" ), top_layer, bottom_layer );
1144 
1145  aList.push_back( MSG_PANEL_ITEM( _( "Layers" ), msg, BROWN ) );
1146 
1147  // Display width
1148  msg = MessageTextFromValue( aUnits, m_Width, true );
1149 
1150  // Display diameter value:
1151  aList.push_back( MSG_PANEL_ITEM( _( "Diameter" ), msg, DARKCYAN ) );
1152 
1153  // Display drill value
1154  msg = MessageTextFromValue( aUnits, GetDrillValue() );
1155 
1156  wxString title = _( "Drill" );
1157  title += wxT( " " );
1158 
1159  bool drl_specific = true;
1160 
1161  if( GetBoard() )
1162  {
1163  NETINFO_ITEM* net = GetNet();
1164  int drill_class_value = 0;
1165 
1166  if( net )
1167  {
1168  if( GetViaType() == VIA_MICROVIA )
1169  drill_class_value = net->GetMicroViaDrillSize();
1170  else
1171  drill_class_value = net->GetViaDrillSize();
1172  }
1173 
1174  drl_specific = GetDrillValue() != drill_class_value;
1175  }
1176 
1177 
1178  if( drl_specific )
1179  title += _( "(Specific)" );
1180  else
1181  title += _( "(NetClass)" );
1182 
1183  aList.push_back( MSG_PANEL_ITEM( title, msg, RED ) );
1184 }
1185 
1186 
1187 bool TRACK::HitTest( const wxPoint& aPosition, int aAccuracy ) const
1188 {
1189  return TestSegmentHit( aPosition, m_Start, m_End, aAccuracy + ( m_Width / 2 ) );
1190 }
1191 
1192 bool VIA::HitTest( const wxPoint& aPosition, int aAccuracy ) const
1193 {
1194  int max_dist = aAccuracy + ( m_Width / 2 );
1195 
1196  // rel_pos is aPosition relative to m_Start (or the center of the via)
1197  wxPoint rel_pos = aPosition - m_Start;
1198  double dist = (double) rel_pos.x * rel_pos.x + (double) rel_pos.y * rel_pos.y;
1199  return dist <= (double) max_dist * max_dist;
1200 }
1201 
1202 
1203 bool TRACK::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
1204 {
1205  EDA_RECT arect = aRect;
1206  arect.Inflate( aAccuracy );
1207 
1208  if( aContained )
1209  /* Tracks are a special case:
1210  * they are considered inside the rect if one end is inside the rect */
1211  return arect.Contains( GetStart() ) || arect.Contains( GetEnd() );
1212  else
1213  return arect.Intersects( GetStart(), GetEnd() );
1214 }
1215 
1216 bool VIA::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
1217 {
1218  EDA_RECT box;
1219  EDA_RECT arect = aRect;
1220  arect.Inflate( aAccuracy );
1221 
1222  box.SetOrigin( GetStart() );
1223  box.Inflate( GetWidth() / 2 );
1224 
1225  if( aContained )
1226  {
1227  return arect.Contains( box );
1228  }
1229  else
1230  {
1231  return arect.IntersectsCircle( GetStart(), GetWidth() / 2 );
1232  }
1233 }
1234 
1235 
1236 VIA* TRACK::GetVia( const wxPoint& aPosition, PCB_LAYER_ID aLayer)
1237 {
1238  for( VIA* via = GetFirstVia( this ); via; via = GetFirstVia( via->Next() ) )
1239  {
1240  if( via->HitTest( aPosition ) &&
1241  !via->GetState( BUSY | IS_DELETED ) &&
1242  ((aLayer == UNDEFINED_LAYER) || (via->IsOnLayer( aLayer ))) )
1243  return via;
1244  }
1245 
1246  return NULL;
1247 }
1248 
1249 
1250 VIA* TRACK::GetVia( TRACK* aEndTrace, const wxPoint& aPosition, LSET aLayerMask )
1251 {
1252  for( VIA* via = GetFirstVia( this, aEndTrace ); via; via = GetFirstVia( via->Next() ) )
1253  {
1254  if( via->HitTest( aPosition ) &&
1255  !via->GetState( BUSY | IS_DELETED ) &&
1256  ( aLayerMask & via->GetLayerSet() ).any()
1257  )
1258  {
1259  return via;
1260  }
1261  }
1262 
1263  return NULL;
1264 }
1265 
1266 
1267 TRACK* TRACK::GetTrack( TRACK* aStartTrace, TRACK* aEndTrace, ENDPOINT_T aEndPoint,
1268  bool aSameNetOnly, bool aSequential )
1269 {
1270  const wxPoint& position = GetEndPoint( aEndPoint );
1271  LSET refLayers = GetLayerSet();
1272  TRACK* previousSegment;
1273  TRACK* nextSegment;
1274 
1275  if( aSequential )
1276  {
1277  // Simple sequential search: from aStartTrace forward to aEndTrace
1278  previousSegment = NULL;
1279  nextSegment = aStartTrace;
1280  }
1281  else
1282  {
1283  /* Local bidirectional search: from this backward to aStartTrace
1284  * AND forward to aEndTrace. The idea is that nearest segments
1285  * are found (on average) faster in this way. In fact same-net
1286  * segments are almost guaranteed to be found faster, in a global
1287  * search, since they are grouped together in the track list */
1288  previousSegment = this;
1289  nextSegment = this;
1290  }
1291 
1292  while( nextSegment || previousSegment )
1293  {
1294  // Terminate the search in the direction if the netcode mis-matches
1295  if( aSameNetOnly )
1296  {
1297  if( nextSegment && (nextSegment->GetNetCode() != GetNetCode()) )
1298  nextSegment = NULL;
1299  if( previousSegment && (previousSegment->GetNetCode() != GetNetCode()) )
1300  previousSegment = NULL;
1301  }
1302 
1303  if( nextSegment )
1304  {
1305  if ( (nextSegment != this) &&
1306  !nextSegment->GetState( BUSY | IS_DELETED ) &&
1307  ( refLayers & nextSegment->GetLayerSet() ).any() )
1308  {
1309  if( (position == nextSegment->m_Start) ||
1310  (position == nextSegment->m_End) )
1311  return nextSegment;
1312  }
1313 
1314  // Keep looking forward
1315  if( nextSegment == aEndTrace )
1316  nextSegment = NULL;
1317  else
1318  nextSegment = nextSegment->Next();
1319  }
1320 
1321  // Same as above, looking back. During sequential search this branch is inactive
1322  if( previousSegment )
1323  {
1324  if( (previousSegment != this) &&
1325  !previousSegment->GetState( BUSY | IS_DELETED ) &&
1326  ( refLayers & previousSegment->GetLayerSet() ).any()
1327  )
1328  {
1329  if( (position == previousSegment->m_Start) ||
1330  (position == previousSegment->m_End) )
1331  return previousSegment;
1332  }
1333 
1334  if( previousSegment == aStartTrace )
1335  previousSegment = NULL;
1336  else
1337  previousSegment = previousSegment->Back();
1338  }
1339  }
1340 
1341  return NULL;
1342 }
1343 
1344 
1345 int TRACK::GetEndSegments( int aCount, TRACK** aStartTrace, TRACK** aEndTrace )
1346 {
1347  TRACK* Track, * via, * segm, * TrackListEnd;
1348  int NbEnds, ii, ok = 0;
1349  LSET layerMask;
1350 
1351  if( aCount <= 1 )
1352  {
1353  *aStartTrace = *aEndTrace = this;
1354  return 1;
1355  }
1356 
1357  // Calculation of the limit analysis.
1358  *aStartTrace = *aEndTrace = NULL;
1359  TrackListEnd = Track = this;
1360  ii = 0;
1361 
1362  for( ; ( Track != NULL ) && ( ii < aCount ); ii++, Track = Track->Next() )
1363  {
1364  TrackListEnd = Track;
1365  Track->m_Param = 0;
1366  }
1367 
1368  // Calculate the extremes.
1369  NbEnds = 0;
1370  Track = this;
1371  ii = 0;
1372 
1373  for( ; ( Track != NULL ) && ( ii < aCount ); ii++, Track = Track->Next() )
1374  {
1375  if( Track->Type() == PCB_VIA_T )
1376  continue;
1377 
1378  layerMask = Track->GetLayerSet();
1379  via = GetVia( TrackListEnd, Track->m_Start, layerMask );
1380 
1381  if( via )
1382  {
1383  layerMask |= via->GetLayerSet();
1384  via->SetState( BUSY, true );
1385  }
1386 
1387  Track->SetState( BUSY, true );
1388  segm = ::GetTrack( this, TrackListEnd, Track->m_Start, layerMask );
1389  Track->SetState( BUSY, false );
1390 
1391  if( via )
1392  via->SetState( BUSY, false );
1393 
1394  if( segm == NULL )
1395  {
1396  switch( NbEnds )
1397  {
1398  case 0:
1399  *aStartTrace = Track; NbEnds++;
1400  break;
1401 
1402  case 1:
1403  int BeginPad, EndPad;
1404  *aEndTrace = Track;
1405 
1406  // Swap ox, oy with fx, fy
1407  BeginPad = Track->GetState( BEGIN_ONPAD );
1408  EndPad = Track->GetState( END_ONPAD );
1409 
1410  Track->SetState( BEGIN_ONPAD | END_ONPAD, false );
1411 
1412  if( BeginPad )
1413  Track->SetState( END_ONPAD, true );
1414 
1415  if( EndPad )
1416  Track->SetState( BEGIN_ONPAD, true );
1417 
1418  std::swap( Track->m_Start, Track->m_End );
1419  std::swap( Track->start, Track->end );
1420  ok = 1;
1421  return ok;
1422  }
1423  }
1424 
1425  layerMask = Track->GetLayerSet();
1426  via = GetVia( TrackListEnd, Track->m_End, layerMask );
1427 
1428  if( via )
1429  {
1430  layerMask |= via->GetLayerSet();
1431  via->SetState( BUSY, true );
1432  }
1433 
1434  Track->SetState( BUSY, true );
1435  segm = ::GetTrack( this, TrackListEnd, Track->m_End, layerMask );
1436  Track->SetState( BUSY, false );
1437 
1438  if( via )
1439  via->SetState( BUSY, false );
1440 
1441  if( segm == NULL )
1442  {
1443  switch( NbEnds )
1444  {
1445  case 0:
1446  int BeginPad, EndPad;
1447  *aStartTrace = Track;
1448  NbEnds++;
1449 
1450  // Swap ox, oy with fx, fy
1451  BeginPad = Track->GetState( BEGIN_ONPAD );
1452  EndPad = Track->GetState( END_ONPAD );
1453 
1454  Track->SetState( BEGIN_ONPAD | END_ONPAD, false );
1455 
1456  if( BeginPad )
1457  Track->SetState( END_ONPAD, true );
1458 
1459  if( EndPad )
1460  Track->SetState( BEGIN_ONPAD, true );
1461 
1462  std::swap( Track->m_Start, Track->m_End );
1463  std::swap( Track->start, Track->end );
1464  break;
1465 
1466  case 1:
1467  *aEndTrace = Track;
1468  ok = 1;
1469  return ok;
1470  }
1471  }
1472  }
1473 
1474  return ok;
1475 }
1476 
1477 
1478 wxString TRACK::GetSelectMenuText( EDA_UNITS_T aUnits ) const
1479 {
1480  return wxString::Format( _("Track %s %s on %s, length: %s" ),
1481  MessageTextFromValue( aUnits, m_Width ),
1482  GetNetnameMsg(),
1483  GetLayerName(),
1484  MessageTextFromValue( aUnits, GetLength() ) );
1485 }
1486 
1487 
1488 BITMAP_DEF TRACK::GetMenuImage() const
1489 {
1490  return add_tracks_xpm;
1491 }
1492 
1494 {
1495  assert( aImage->Type() == PCB_TRACE_T );
1496 
1497  std::swap( *((TRACK*) this), *((TRACK*) aImage) );
1498 }
1499 
1500 void VIA::SwapData( BOARD_ITEM* aImage )
1501 {
1502  assert( aImage->Type() == PCB_VIA_T );
1503 
1504  std::swap( *((VIA*) this), *((VIA*) aImage) );
1505 }
1506 
1507 #if defined(DEBUG)
1508 
1509 wxString TRACK::ShowState( int stateBits )
1510 {
1511  wxString ret;
1512 
1513  if( stateBits & IS_LINKED )
1514  ret << wxT( " | IS_LINKED" );
1515 
1516  if( stateBits & TRACK_AR )
1517  ret << wxT( " | TRACK_AR" );
1518 
1519  if( stateBits & TRACK_LOCKED )
1520  ret << wxT( " | TRACK_LOCKED" );
1521 
1522  if( stateBits & IN_EDIT )
1523  ret << wxT( " | IN_EDIT" );
1524 
1525  if( stateBits & IS_DRAGGED )
1526  ret << wxT( " | IS_DRAGGED" );
1527 
1528  if( stateBits & DO_NOT_DRAW )
1529  ret << wxT( " | DO_NOT_DRAW" );
1530 
1531  if( stateBits & IS_DELETED )
1532  ret << wxT( " | IS_DELETED" );
1533 
1534  if( stateBits & BUSY )
1535  ret << wxT( " | BUSY" );
1536 
1537  if( stateBits & END_ONPAD )
1538  ret << wxT( " | END_ONPAD" );
1539 
1540  if( stateBits & BEGIN_ONPAD )
1541  ret << wxT( " | BEGIN_ONPAD" );
1542 
1543  if( stateBits & FLAG0 )
1544  ret << wxT( " | FLAG0" );
1545 
1546  if( stateBits & FLAG1 )
1547  ret << wxT( " | FLAG1" );
1548 
1549  return ret;
1550 }
1551 
1552 #endif
virtual BASE_SCREEN * GetScreen()=0
#define MIN_VIA_DRAW_SIZE
Definition: class_track.h:68
Definition: colors.h:57
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Function AllCuMask returns a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:676
#define IS_LINKED
Used in calculation to mark linked items (temporary use)
Definition: base_struct.h:111
#define FLAG1
Pcbnew: flag used in local computations.
Definition: base_struct.h:130
void GetMsgPanelInfoBase_Common(EDA_UNITS_T aUnits, std::vector< MSG_PANEL_ITEM > &aList)
Helper function for the common panel info.
void LayerPair(PCB_LAYER_ID *top_layer, PCB_LAYER_ID *bottom_layer) const
Function LayerPair Return the 2 layers used by the via (the via actually uses all layers between thes...
to draw blind/buried vias
TRACK * GetTrack(TRACK *aStartTrace, TRACK *aEndTrace, ENDPOINT_T aEndPoint, bool aSameNetOnly, bool aSequential)
Function GetTrack returns the trace segment connected to the segment at aEndPoint from aStartTrace to...
bool IsNull()
Function IsNull returns true if segment length is zero.
TRACK * GetTrack(TRACK *aStartTrace, const TRACK *aEndTrace, const wxPoint &aPosition, LSET aLayerMask)
Function GetTrack is a helper function to locate a trace segment having an end point at aPosition on ...
Definition: class_track.cpp:68
#define IN_EDIT
Item currently edited.
Definition: base_struct.h:112
int GetNetCode() const
Function GetNetCode.
wxPoint m_Start
Line start point.
Definition: class_track.h:349
double GetLineLength(const wxPoint &aPointA, const wxPoint &aPointB)
Function GetLineLength returns the length of a line segment defined by aPointA and aPointB.
Definition: trigo.h:200
virtual void SwapData(BOARD_ITEM *aImage) override
Swap data between aItem and aImage.
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Function GetLayerName returns the name of a layer given by aLayer.
static const int dist[10][10]
Definition: ar_matrix.cpp:320
#define END_ONPAD
Pcbnew: flag set for track segment ending on a pad.
Definition: base_struct.h:133
void GRSetDrawMode(wxDC *DC, GR_DRAWMODE draw_mode)
Definition: gr_basic.cpp:223
virtual LSET GetLayerSet() const override
Function GetLayerSet returns a "layer mask", which is a bitmap of all layers on which the TRACK segme...
void SetViaType(VIATYPE_T aViaType)
Definition: class_track.h:438
static int KiROUND(double v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:118
int GetNetnameLayer(int aLayer)
Returns a netname layer corresponding to the given layer.
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
Implementation of conversion functions that require both schematic and board internal units.
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
T * GetLast() const
Function GetLast returns the last T* in the list without removing it, or NULL if the list is empty.
Definition: dlist.h:170
NETINFO_ITEM * GetNet() const
Function GetNet Returns NET_INFO object for a given item.
const wxPoint & GetStart() const
Definition: class_track.h:133
virtual void Flip(const wxPoint &aCentre) override
Function Flip Flip this object, i.e.
void GetMsgPanelInfo(EDA_UNITS_T aUnits, std::vector< MSG_PANEL_ITEM > &aList) override
Function GetMsgPanelInfo populates aList of MSG_PANEL_ITEM objects with it's internal state for displ...
Class BOARD to handle a board.
Definition: colors.h:61
STATUS_FLAGS IsPointOnEnds(const wxPoint &point, int min_dist=0)
Function IsPointOnEnds returns STARTPOINT if point if near (dist = min_dist) start point,...
bool IsMoving() const
Definition: base_struct.h:224
int color
Definition: DXF_plotter.cpp:62
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Function FlippedLayerNumber.
Definition: lset.cpp:475
bool HitTest(const wxPoint &aPosition, int aAccuracy=0) const override
Function HitTest tests if aPosition is contained within or on the bounding box of an item.
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
virtual void ViewGetLayers(int aLayers[], int &aCount) const override
Function ViewGetLayers() Returns the all the layers within the VIEW the object is painted on.
virtual EDA_ITEM * Clone() const override
Function Clone creates a duplicate of this item with linked list members set to NULL.
to draw via holes (pad holes do not use this layer)
LSET GetVisibleLayers() const
Function GetVisibleLayers is a proxy function that calls the correspondent function in m_BoardSetting...
double RAD2DECIDEG(double rad)
Definition: trigo.h:213
bool IntersectsCircle(const wxPoint &aCenter, const int aRadius) const
Function IntersectsCircle tests for a common area between a circle and this rectangle.
void SetOrigin(const wxPoint &pos)
Definition: eda_rect.h:124
void GRCSegm(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, int aPenSize, COLOR4D Color)
Definition: gr_basic.cpp:415
int GetEndSegments(int NbSegm, TRACK **StartTrack, TRACK **EndTrack)
Function GetEndSegments get the segments connected to the end point of the track.
static bool ShowClearance(PCB_DISPLAY_OPTIONS *aDisplOpts, const TRACK *aTrack)
Function ShowClearance tests to see if the clearance border is drawn on the given track.
Definition: class_track.cpp:55
#define BUSY
Pcbnew: flag indicating that the structure has.
Definition: base_struct.h:134
virtual EDA_RECT * GetClipBox()
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:216
VIA(BOARD_ITEM *aParent)
virtual void Rotate(const wxPoint &aRotCentre, double aAngle) override
Function Rotate Rotate this object.
void GRFilledCircle(EDA_RECT *ClipBox, wxDC *DC, int x, int y, int r, int width, COLOR4D Color, COLOR4D BgColor)
Definition: gr_basic.cpp:778
void DrawGraphicHaloText(EDA_RECT *aClipBox, wxDC *aDC, const wxPoint &aPos, const COLOR4D aBgColor, COLOR4D aColor1, COLOR4D aColor2, const wxString &aText, double aOrient, const wxSize &aSize, enum EDA_TEXT_HJUSTIFY_T aH_justify, enum EDA_TEXT_VJUSTIFY_T aV_justify, int aWidth, bool aItalic, bool aBold, void(*aCallback)(int x0, int y0, int xf, int yf, void *aData), void *aCallbackData, PLOTTER *aPlotter)
Draw graphic text with a border, so that it can be read on different backgrounds.
#define BEGIN_ONPAD
Pcbnew: flag set for track segment starting on a pad.
Definition: base_struct.h:132
Class BOARD_CONNECTED_ITEM is a base class derived from BOARD_ITEM for items that can be connected an...
bool Contains(const wxPoint &aPoint) const
Function Contains.
const wxString & GetShortNetname() const
Function GetShortNetname.
Definition: netinfo.h:241
KICAD_T
Enum KICAD_T is the set of class identification values, stored in EDA_ITEM::m_StructType.
Definition: typeinfo.h:78
bool IsDragging() const
Definition: base_struct.h:225
Functions relatives to tracks, vias and segments used to fill zones.
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:95
void * GetDisplayOptions() override
Function GetDisplayOptions returns the display options current in use Display options are relative to...
#define MIN_TEXT_SIZE
double m_Param
Definition: class_track.h:104
double GetLength() const
Function GetLength returns the length of the track using the hypotenuse calculation.
Definition: class_track.h:186
TRACE_CLEARANCE_DISPLAY_MODE_T m_ShowTrackClearanceMode
How trace clearances are displayed.
int m_Width
Thickness of track, or via diameter.
Definition: class_track.h:348
This file contains miscellaneous commonly used macros and functions.
bool IsNew() const
Definition: base_struct.h:222
Classes used in Pcbnew, CvPcb and GerbView.
COLOR4D GetItemColor(int aItemIdx) const
Function GetItemColor.
virtual unsigned int ViewGetLOD(int aLayer, KIGFX::VIEW *aView) const override
Function ViewGetLOD() Returns the level of detail (LOD) of the item.
#define THRESHOLD
wxString MessageTextFromValue(EDA_UNITS_T aUnits, int aValue, bool aUseMils)
Definition: base_units.cpp:125
virtual EDA_DRAW_FRAME * GetParent() const =0
const INSPECTOR_FUNC & INSPECTOR
Definition: base_struct.h:102
#define IS_DRAGGED
Item being dragged.
Definition: base_struct.h:116
PCB_LAYER_ID m_Layer
VIA * GetVia(const wxPoint &aPosition, PCB_LAYER_ID aLayer=UNDEFINED_LAYER)
Function GetVia finds the first VIA object at aPosition on aLayer starting at the trace.
Class PCB_DISPLAY_OPTIONS handles display options like enable/disable some optional drawings.
PCB_LAYER_ID
A quick note on layer IDs:
BITMAP_DEF GetMenuImage() const override
Function GetMenuImage returns a pointer to an image to be used in menus.
Class LSET is a set of PCB_LAYER_IDs.
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Function IsOnLayer tests to see if this object is on the given layer.
int GetDrillValue() const
Function GetDrillValue "calculates" the drill value for vias (m-Drill if > 0, or default drill value ...
void GRForceBlackPen(bool flagforce)
Function GRForceBlackPen.
Definition: gr_basic.cpp:204
GR_DRAWMODE
Drawmode. Compositing mode plus a flag or two.
Definition: gr_basic.h:37
void GRFillCSegm(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, COLOR4D Color)
Definition: gr_basic.cpp:518
#define IS_DELETED
Definition: base_struct.h:117
PCB_GENERAL_SETTINGS & Settings()
virtual void Flip(const wxPoint &aCentre) override
Function Flip Flip this object, i.e.
wxPoint m_End
Line end point.
Definition: class_track.h:350
to draw usual through hole vias
int m_Drill
Definition: class_track.h:485
void DrawShortNetname(EDA_DRAW_PANEL *panel, wxDC *aDC, GR_DRAWMODE aDrawMode, COLOR4D aBgColor)
Helper for drawing the short netname in tracks.
virtual BOARD * GetBoard() const
Function GetBoard returns the BOARD in which this BOARD_ITEM resides, or NULL if none.
const wxString & GetNetname() const
Function GetNetname.
Definition: netinfo.h:235
unsigned STATUS_FLAGS
Definition: base_struct.h:150
VIATYPE_T GetViaType() const
Definition: class_track.h:437
ENDPOINT_T
Definition: class_track.h:50
SEARCH_RESULT Visit(INSPECTOR inspector, void *testData, const KICAD_T scanTypes[]) override
Function Visit may be re-implemented for each derived class in order to handle all the types given by...
PCB_LAYER_ID m_BottomLayer
The bottom layer of the via (the top layer is in m_Layer)
Definition: class_track.h:481
virtual unsigned int ViewGetLOD(int aLayer, KIGFX::VIEW *aView) const override
Function ViewGetLOD() Returns the level of detail (LOD) of the item.
TRACK * GetEndNetCode(int NetCode)
#define TRACK_LOCKED
Pcbnew: track locked: protected from global deletion.
Definition: base_struct.h:128
Definition: colors.h:60
void SetLayerPair(PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer)
Function SetLayerPair For a via m_Layer contains the top layer, the other layer is in m_BottomLayer.
wxString GetSelectMenuText(EDA_UNITS_T aUnits) const override
Function GetSelectMenuText returns the text to display to be used in the selection clarification cont...
const BOX2I ViewBBox() const override
Function ViewBBox() returns the bounding box of the item covering all its layers.
virtual int GetClearance(BOARD_CONNECTED_ITEM *aItem=NULL) const override
Function GetClearance returns the clearance in internal units.
T * GetFirst() const
Function GetFirst returns the first T* in the list without removing it, or NULL if the list is empty.
Definition: dlist.h:163
void GRLine(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, COLOR4D Color, wxPenStyle aStyle)
Definition: gr_basic.cpp:285
virtual void SwapData(BOARD_ITEM *aImage) override
Swap data between aItem and aImage.
bool m_IsPrinting
Definition: base_screen.h:220
#define FLAG0
Pcbnew: flag used in local computations.
Definition: base_struct.h:131
void Draw(EDA_DRAW_PANEL *panel, wxDC *DC, GR_DRAWMODE aDrawMode, const wxPoint &aOffset=ZeroOffset) override
Function Draw BOARD_ITEMs have their own color information.
void SetDrillDefault()
Function SetDrillDefault sets the drill value for vias to the default value UNDEFINED_DRILL_DIAMETER.
Definition: class_track.h:466
COLORS_DESIGN_SETTINGS & Colors()
#define TRACK_AR
Pcbnew: autorouted track.
Definition: base_struct.h:129
int LAYER_NUM
Type LAYER_NUM can be replaced with int and removed.
wxString GetNetnameMsg() const
Function GetNetnameMsg.
virtual void GetMsgPanelInfoBase(EDA_UNITS_T aUnits, std::vector< MSG_PANEL_ITEM > &aList)
Function GetMsgPanelInfoBase Display info about the track segment only, and does not calculate the fu...
bool IsElementVisible(GAL_LAYER_ID aLayer) const
Function IsElementVisible tests whether a given element category is visible.
void Draw(EDA_DRAW_PANEL *panel, wxDC *DC, GR_DRAWMODE aDrawMode, const wxPoint &aOffset=ZeroOffset) override
Function Draw BOARD_ITEMs have their own color information.
virtual void ViewGetLayers(int aLayers[], int &aCount) const override
Function ViewGetLayers() Returns the all the layers within the VIEW the object is painted on.
Class NETINFO_ITEM handles the data for a net.
Definition: netinfo.h:65
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:300
bool IsLayerVisible(PCB_LAYER_ID aLayer) const
Function IsLayerVisible is a proxy function that calls the correspondent function in m_BoardSettings ...
Definition: class_board.h:453
TRACK * GetBestInsertPoint(BOARD *aPcb)
Function GetBestInsertPoint searches the "best" insertion point within the track linked list.
BITMAP_DEF GetMenuImage() const override
Function GetMenuImage returns a pointer to an image to be used in menus.
void SetState(int type, int state)
Definition: base_struct.h:248
int GetWidth() const
Definition: class_track.h:127
TRACK * Next() const
Definition: class_track.h:110
TRACK * GetStartNetCode(int NetCode)
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
#define max(a, b)
Definition: auxiliary.h:86
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:170
virtual int GetClearance(BOARD_CONNECTED_ITEM *aItem=NULL) const
Function GetClearance returns the clearance in internal units.
void SetTopLayer(PCB_LAYER_ID aLayer)
std::shared_ptr< NETCLASS > GetNetClass() const
Function GetNetClass returns the NETCLASS for this item.
wxString UnescapeString(const wxString &aSource)
Definition: string.cpp:123
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
void GRCircle(EDA_RECT *ClipBox, wxDC *DC, int xc, int yc, int r, int width, COLOR4D Color)
Definition: gr_basic.cpp:755
STATUS_FLAGS m_Flags
Flag bits for editing and other uses.
Definition: base_struct.h:181
int GetCopperLayerCount() const
Function GetCopperLayerCount.
#define ENDPOINT
ends. (Used to support dragging.)
Definition: base_struct.h:120
Class EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
void GetMsgPanelInfoBase(EDA_UNITS_T aUnits, std::vector< MSG_PANEL_ITEM > &aList) override
Function GetMsgPanelInfoBase Display info about the track segment only, and does not calculate the fu...
Class EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boa...
Definition: base_struct.h:157
The common library.
PCB_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
PCB_LAYER_ID TopLayer() const
const wxPoint & GetEnd() const
Definition: class_track.h:130
Definition: colors.h:49
bool Intersects(const EDA_RECT &aRect) const
Function Intersects tests for a common area between rectangles.
int GetMicroViaDrillSize()
Function GetViaDrillSize returns the size of via drills used to route this net.
Definition: netinfo.h:182
void SetBottomLayer(PCB_LAYER_ID aLayer)
bool IsCopperLayer(LAYER_NUM aLayerId)
Function IsCopperLayer tests whether a layer is a copper layer.
virtual wxString GetSelectMenuText(EDA_UNITS_T aUnits) const override
Function GetSelectMenuText returns the text to display to be used in the selection clarification cont...
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
TRACK(BOARD_ITEM *aParent, KICAD_T idtype=PCB_TRACE_T)
Definition: class_track.cpp:96
DLIST< TRACK > m_Track
Definition: class_board.h:249
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Function IsOnLayer tests to see if this object is on the given layer.
Definition: colors.h:45
virtual void * GetDisplayOptions()
Function GetDisplayOptions A way to pass info to draw functions.
Class EDA_MSG_ITEM is used EDA_MSG_PANEL as the item type for displaying messages.
Definition: msgpanel.h:53
Class VIEW.
Definition: view.h:61
bool TestSegmentHit(const wxPoint &aRefPoint, wxPoint aStart, wxPoint aEnd, int aDist)
Function TestSegmentHit test for hit on line segment i.e.
Definition: trigo.cpp:122
SEARCH_RESULT
Definition: base_struct.h:66
bool GetGRForceBlackPenState(void)
Function GetGRForceBlackPenState.
Definition: gr_basic.cpp:214
void SanitizeLayers()
Function SanitizeLayers Check so that the layers are correct dependin on the type of via,...
TRACK * MarkTrace(TRACK *aTrackList, TRACK *aTrace, int *aCount, double *aTraceLength, double *aInPackageLength, bool aReorder)
Function MarkTrace marks a chain of trace segments, connected to aTrace.
int GetViaDrillSize()
Function GetViaDrillSize returns the size of via drills used to route this net.
Definition: netinfo.h:172
bool HitTest(const wxPoint &aPosition, int aAccuracy=0) const override
Function HitTest tests if aPosition is contained within or on the bounding box of an item.
Message panel definition file.
const wxPoint & GetEndPoint(ENDPOINT_T aEndPoint) const
Return the selected endpoint (start or end)
Definition: class_track.h:137
wxString GetLayerName() const
Function GetLayerName returns the name of the PCB layer on which the item resides.
#define FORCE_SKETCH
Definition: pcbnew.h:67
BOARD_CONNECTED_ITEM * end
Definition: class_track.h:102
PCB_LAYER_ID BottomLayer() const
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition: netinfo.h:465
int GetState(int type) const
Definition: base_struct.h:243
BOARD_CONNECTED_ITEM * start
Definition: class_track.h:101
EDA_ITEM * Pnext
next in linked list
Definition: base_struct.h:170
class PCB_BASE_FRAME basic PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
EDA_UNITS_T
Definition: common.h:157
#define DO_NOT_DRAW
Used to disable draw function.
Definition: base_struct.h:126
virtual LSET GetLayerSet() const
Function GetLayerSet returns a "layer mask", which is a bitmap of all layers on which the TRACK segme...
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
EDA_ITEM * Clone() const override
Function Clone creates a duplicate of this item with linked list members set to NULL.
bool IsNetnameLayer(LAYER_NUM aLayer)
Function IsNetnameLayer tests whether a layer is a netname layer.
KICAD_T Type() const
Function Type()
Definition: base_struct.h:204
#define min(a, b)
Definition: auxiliary.h:85
TRACK * Back() const
Definition: class_track.h:111
#define STARTPOINT
When a line is selected, these flags indicate which.
Definition: base_struct.h:119
bool IsLayerVisible(int aLayer) const
Function IsLayerVisible() Returns information about visibility of a particular layer.
Definition: view.h:427
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39
Definition: colors.h:62
VIA * GetFirstVia(TRACK *aTrk, const TRACK *aStopPoint=NULL)
Scan a track list for the first VIA o NULL if not found (or NULL passed)
Definition: class_track.h:490