KiCad PCB EDA Suite
gerber_draw_item.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) 1992-2017 <Jean-Pierre Charras>
5  * Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 #include <fctsys.h>
26 #include <gr_basic.h>
27 #include <common.h>
28 #include <trigo.h>
29 #include <bitmaps.h>
30 #include <msgpanel.h>
31 #include <gerbview_frame.h>
33 #include <gerber_draw_item.h>
34 #include <gerber_file_image.h>
35 #include <gerber_file_image_list.h>
36 #include <kicad_string.h>
37 
40 {
41  m_GerberImageFile = aGerberImageFile;
43  m_Flashed = false;
44  m_DCode = 0;
45  m_UnitsMetric = false;
46  m_LayerNegative = false;
47  m_swapAxis = false;
48  m_mirrorA = false;
49  m_mirrorB = false;
50  m_drawScale.x = m_drawScale.y = 1.0;
51  m_lyrRotation = 0;
52 
53  if( m_GerberImageFile )
55 }
56 
57 
59 {
60 }
61 
62 
64 {
65  m_netAttributes = aNetAttributes;
66 
69  m_GerberImageFile->m_ComponentsList.insert( std::make_pair( m_netAttributes.m_Cmpref, 0 ) );
70 
72  m_GerberImageFile->m_NetnamesList.insert( std::make_pair( m_netAttributes.m_Netname, 0 ) );
73 }
74 
75 
77 {
78  // returns the layer this item is on, or 0 if the m_GerberImageFile is NULL.
80 }
81 
82 
83 bool GERBER_DRAW_ITEM::GetTextD_CodePrms( int& aSize, wxPoint& aPos, double& aOrientation )
84 {
85  // calculate the best size and orientation of the D_Code text
86 
87  if( m_DCode <= 0 )
88  return false; // No D_Code for this item
89 
90  if( m_Flashed || m_Shape == GBR_ARC )
91  {
92  aPos = m_Start;
93  }
94  else // it is a line:
95  {
96  aPos = ( m_Start + m_End) / 2;
97  }
98 
99  aPos = GetABPosition( aPos );
100 
101  int size; // the best size for the text
102 
103  if( GetDcodeDescr() )
104  size = GetDcodeDescr()->GetShapeDim( this );
105  else
106  size = std::min( m_Size.x, m_Size.y );
107 
108  aOrientation = TEXT_ANGLE_HORIZ;
109 
110  if( m_Flashed )
111  {
112  // A reasonable size for text is min_dim/3 because most of time this text has 3 chars.
113  aSize = size / 3;
114  }
115  else // this item is a line
116  {
117  wxPoint delta = m_Start - m_End;
118 
119  aOrientation = RAD2DECIDEG( atan2( (double)delta.y, (double)delta.x ) );
120  NORMALIZE_ANGLE_90( aOrientation );
121 
122  // A reasonable size for text is size/2 because text needs margin below and above it.
123  // a margin = size/4 seems good, expecting the line len is large enough to show 3 chars,
124  // that is the case most of time.
125  aSize = size / 2;
126  }
127 
128  return true;
129 }
130 
131 
132 bool GERBER_DRAW_ITEM::GetTextD_CodePrms( double& aSize, VECTOR2D& aPos, double& aOrientation )
133 {
134  // aOrientation is returned in radians
135  int size;
136  wxPoint pos;
137 
138  if( ! GetTextD_CodePrms( size, pos, aOrientation ) )
139  return false;
140 
141  aPos = pos;
142  aSize = (double) size;
143  aOrientation = DECIDEG2RAD( aOrientation );
144 
145  return true;
146 }
147 
148 
149 wxPoint GERBER_DRAW_ITEM::GetABPosition( const wxPoint& aXYPosition ) const
150 {
151  /* Note: RS274Xrevd_e is obscure about the order of transforms:
152  * For instance: Rotation must be made after or before mirroring ?
153  * Note: if something is changed here, GetYXPosition must reflect changes
154  */
155  wxPoint abPos = aXYPosition + m_GerberImageFile->m_ImageJustifyOffset;
156 
157  if( m_swapAxis )
158  std::swap( abPos.x, abPos.y );
159 
161  abPos.x = KiROUND( abPos.x * m_drawScale.x );
162  abPos.y = KiROUND( abPos.y * m_drawScale.y );
163  double rotation = m_lyrRotation * 10 + m_GerberImageFile->m_ImageRotation * 10;
164 
165  if( rotation )
166  RotatePoint( &abPos, -rotation );
167 
168  // Negate A axis if mirrored
169  if( m_mirrorA )
170  abPos.x = -abPos.x;
171 
172  // abPos.y must be negated when no mirror, because draw axis is top to bottom
173  if( !m_mirrorB )
174  abPos.y = -abPos.y;
175  return abPos;
176 }
177 
178 
179 wxPoint GERBER_DRAW_ITEM::GetXYPosition( const wxPoint& aABPosition ) const
180 {
181  // do the inverse transform made by GetABPosition
182  wxPoint xyPos = aABPosition;
183 
184  if( m_mirrorA )
185  xyPos.x = -xyPos.x;
186 
187  if( !m_mirrorB )
188  xyPos.y = -xyPos.y;
189 
190  double rotation = m_lyrRotation * 10 + m_GerberImageFile->m_ImageRotation * 10;
191 
192  if( rotation )
193  RotatePoint( &xyPos, rotation );
194 
195  xyPos.x = KiROUND( xyPos.x / m_drawScale.x );
196  xyPos.y = KiROUND( xyPos.y / m_drawScale.y );
198 
199  if( m_swapAxis )
200  std::swap( xyPos.x, xyPos.y );
201 
202  return xyPos - m_GerberImageFile->m_ImageJustifyOffset;
203 }
204 
205 
207 {
209  m_swapAxis = m_GerberImageFile->m_SwapAxis; // false if A = X, B = Y;
210 
211  // true if A =Y, B = Y
212  m_mirrorA = m_GerberImageFile->m_MirrorA; // true: mirror / axe A
213  m_mirrorB = m_GerberImageFile->m_MirrorB; // true: mirror / axe B
214  m_drawScale = m_GerberImageFile->m_Scale; // A and B scaling factor
215  m_layerOffset = m_GerberImageFile->m_Offset; // Offset from OF command
216 
217  // Rotation from RO command:
220 }
221 
222 
224 {
225  switch( m_Shape )
226  {
227  case GBR_SEGMENT:
228  return _( "Line" );
229 
230  case GBR_ARC:
231  return _( "Arc" );
232 
233  case GBR_CIRCLE:
234  return _( "Circle" );
235 
236  case GBR_SPOT_OVAL:
237  return wxT( "spot_oval" );
238 
239  case GBR_SPOT_CIRCLE:
240  return wxT( "spot_circle" );
241 
242  case GBR_SPOT_RECT:
243  return wxT( "spot_rect" );
244 
245  case GBR_SPOT_POLY:
246  return wxT( "spot_poly" );
247 
248  case GBR_POLYGON:
249  return wxT( "polygon" );
250 
251  case GBR_SPOT_MACRO:
252  {
253  wxString name = wxT( "apt_macro" );
254  D_CODE* dcode = GetDcodeDescr();
255 
256  if( dcode && dcode->GetMacro() )
257  name << wxT(" ") << dcode->GetMacro()->name;
258 
259  return name;
260  }
261 
262  default:
263  return wxT( "??" );
264  }
265 }
266 
267 
269 {
270  if( (m_DCode < FIRST_DCODE) || (m_DCode > LAST_DCODE) )
271  return NULL;
272 
273  if( m_GerberImageFile == NULL )
274  return NULL;
275 
277 }
278 
279 
281 {
282  // return a rectangle which is (pos,dim) in nature. therefore the +1
283  EDA_RECT bbox( m_Start, wxSize( 1, 1 ) );
284  D_CODE* code = GetDcodeDescr();
285 
286  // TODO(JE) GERBER_DRAW_ITEM maybe should actually be a number of subclasses.
287  // Until/unless that is changed, we need to do different things depending on
288  // what is actually being represented by this GERBER_DRAW_ITEM.
289 
290  switch( m_Shape )
291  {
292  case GBR_POLYGON:
293  {
294  auto bb = m_Polygon.BBox();
295  bbox.Inflate( bb.GetWidth() / 2, bb.GetHeight() / 2 );
296  bbox.SetOrigin( bb.GetOrigin().x, bb.GetOrigin().y );
297  break;
298  }
299 
300  case GBR_CIRCLE:
301  {
302  double radius = GetLineLength( m_Start, m_End );
303  bbox.Inflate( radius, radius );
304  break;
305  }
306 
307  case GBR_ARC:
308  {
309  // Note: using a larger-than-necessary BB to simplify computation
310  double radius = GetLineLength( m_Start, m_ArcCentre );
311  bbox.Move( m_ArcCentre - m_Start );
312  bbox.Inflate( radius + m_Size.x, radius + m_Size.x );
313  break;
314  }
315 
316  case GBR_SPOT_CIRCLE:
317  {
318  if( code )
319  {
320  int radius = code->m_Size.x >> 1;
321  bbox.Inflate( radius, radius );
322  }
323  break;
324  }
325 
326  case GBR_SPOT_RECT:
327  {
328  if( code )
329  bbox.Inflate( code->m_Size.x / 2, code->m_Size.y / 2 );
330  break;
331  }
332 
333  case GBR_SPOT_OVAL:
334  {
335  if( code )
336  bbox.Inflate( code->m_Size.x, code->m_Size.y );
337  break;
338  }
339 
340  case GBR_SPOT_POLY:
341  {
342  if( code )
343  {
344  if( code->m_Polygon.OutlineCount() == 0 )
345  code->ConvertShapeToPolygon();
346 
347  bbox.Inflate( code->m_Polygon.BBox().GetWidth() / 2,
348  code->m_Polygon.BBox().GetHeight() / 2 );
349  }
350  break;
351  }
352  case GBR_SPOT_MACRO:
353  {
354  if( code )
355  {
356  // Update the shape drawings and the bounding box coordiantes:
357  code->GetMacro()->GetApertureMacroShape( this, m_Start );
358  // now the bounding box is valid:
359  bbox = code->GetMacro()->GetBoundingBox();
360  }
361  break;
362  }
363 
364  case GBR_SEGMENT:
365  {
366  if( code && code->m_Shape == APT_RECT )
367  {
368  if( m_Polygon.OutlineCount() > 0 )
369  {
370  auto bb = m_Polygon.BBox();
371  bbox.Inflate( bb.GetWidth() / 2, bb.GetHeight() / 2 );
372  bbox.SetOrigin( bb.GetOrigin().x, bb.GetOrigin().y );
373  }
374  }
375  else
376  {
377  int radius = ( m_Size.x + 1 ) / 2;
378 
379  int ymax = std::max( m_Start.y, m_End.y ) + radius;
380  int xmax = std::max( m_Start.x, m_End.x ) + radius;
381 
382  int ymin = std::min( m_Start.y, m_End.y ) - radius;
383  int xmin = std::min( m_Start.x, m_End.x ) - radius;
384 
385  bbox = EDA_RECT( wxPoint( xmin, ymin ), wxSize( xmax - xmin + 1, ymax - ymin + 1 ) );
386  }
387 
388  break;
389  }
390  default:
391  wxASSERT_MSG( false, wxT( "GERBER_DRAW_ITEM shape is unknown!" ) );
392  break;
393  }
394 
395  // calculate the corners coordinates in current gerber axis orientations
396  wxPoint org = GetABPosition( bbox.GetOrigin() );
397  wxPoint end = GetABPosition( bbox.GetEnd() );
398 
399  // Set the corners position:
400  bbox.SetOrigin( org );
401  bbox.SetEnd( end );
402  bbox.Normalize();
403 
404  return bbox;
405 }
406 
407 
408 void GERBER_DRAW_ITEM::MoveAB( const wxPoint& aMoveVector )
409 {
410  wxPoint xymove = GetXYPosition( aMoveVector );
411 
412  m_Start += xymove;
413  m_End += xymove;
414  m_ArcCentre += xymove;
415 
416  if( m_Polygon.OutlineCount() > 0 )
417  {
418  for( auto it = m_Polygon.Iterate( 0 ); it; ++it )
419  *it += xymove;
420  }
421 }
422 
423 
424 void GERBER_DRAW_ITEM::MoveXY( const wxPoint& aMoveVector )
425 {
426  m_Start += aMoveVector;
427  m_End += aMoveVector;
428  m_ArcCentre += aMoveVector;
429 
430  if( m_Polygon.OutlineCount() > 0 )
431  {
432  for( auto it = m_Polygon.Iterate( 0 ); it; ++it )
433  *it += aMoveVector;
434  }
435 }
436 
437 
439 {
441 
442  // if isClear is true, this item has negative shape
443  return isClear;
444 }
445 
446 
447 void GERBER_DRAW_ITEM::Print( wxDC* aDC, const wxPoint& aOffset, GBR_DISPLAY_OPTIONS* aOptions )
448 {
449  // used when a D_CODE is not found. default D_CODE to draw a flashed item
450  static D_CODE dummyD_CODE( 0 );
451  bool isFilled;
452  int radius;
453  int halfPenWidth;
454  static bool show_err;
455  D_CODE* d_codeDescr = GetDcodeDescr();
456 
457  if( d_codeDescr == NULL )
458  d_codeDescr = &dummyD_CODE;
459 
461 
462  /* isDark is true if flash is positive and should use a drawing
463  * color other than the background color, else use the background color
464  * when drawing so that an erasure happens.
465  */
467 
468  if( !isDark )
469  {
470  // draw in background color ("negative" color)
471  color = aOptions->m_NegativeDrawColor;
472  }
473 
474  isFilled = aOptions->m_DisplayLinesFill;
475 
476  switch( m_Shape )
477  {
478  case GBR_POLYGON:
479  isFilled = aOptions->m_DisplayPolygonsFill;
480 
481  if( !isDark )
482  isFilled = true;
483 
484  PrintGerberPoly( aDC, color, aOffset, isFilled );
485  break;
486 
487  case GBR_CIRCLE:
488  radius = KiROUND( GetLineLength( m_Start, m_End ) );
489 
490  halfPenWidth = m_Size.x >> 1;
491 
492  if( !isFilled )
493  {
494  // draw the border of the pen's path using two circles, each as narrow as possible
495  GRCircle( nullptr, aDC, GetABPosition( m_Start ), radius - halfPenWidth, 0, color );
496  GRCircle( nullptr, aDC, GetABPosition( m_Start ), radius + halfPenWidth, 0, color );
497  }
498  else // Filled mode
499  {
500  GRCircle( nullptr, aDC, GetABPosition( m_Start ), radius, m_Size.x, color );
501  }
502  break;
503 
504  case GBR_ARC:
505  // Currently, arcs plotted with a rectangular aperture are not supported.
506  // a round pen only is expected.
507  if( !isFilled )
508  {
509  GRArc1( nullptr, aDC, GetABPosition( m_Start ), GetABPosition( m_End ),
511  }
512  else
513  {
514  GRArc1( nullptr, aDC, GetABPosition( m_Start ), GetABPosition( m_End ),
516  }
517 
518  break;
519 
520  case GBR_SPOT_CIRCLE:
521  case GBR_SPOT_RECT:
522  case GBR_SPOT_OVAL:
523  case GBR_SPOT_POLY:
524  case GBR_SPOT_MACRO:
525  isFilled = aOptions->m_DisplayFlashedItemsFill;
526  d_codeDescr->DrawFlashedShape( this, nullptr, aDC, color, m_Start, isFilled );
527  break;
528 
529  case GBR_SEGMENT:
530  /* Plot a line from m_Start to m_End.
531  * Usually, a round pen is used, but some gerber files use a rectangular pen
532  * In fact, any aperture can be used to plot a line.
533  * currently: only a square pen is handled (I believe using a polygon gives a strange plot).
534  */
535  if( d_codeDescr->m_Shape == APT_RECT )
536  {
537  if( m_Polygon.OutlineCount() == 0 )
539 
540  PrintGerberPoly( aDC, color, aOffset, isFilled );
541  }
542  else
543  {
544  if( !isFilled )
545  {
546  GRCSegm( nullptr, aDC, GetABPosition( m_Start ), GetABPosition( m_End ),
547  m_Size.x, color );
548  }
549  else
550  {
552  m_Size.x, color );
553  }
554  }
555 
556  break;
557 
558  default:
559  if( !show_err )
560  {
561  wxMessageBox( wxT( "Trace_Segment() type error" ) );
562  show_err = true;
563  }
564 
565  break;
566  }
567 }
568 
569 
571 {
574 
575  wxPoint start = m_Start;
576  wxPoint end = m_End;
577 
578  // make calculations more easy if ensure start.x < end.x
579  // (only 2 quadrants to consider)
580  if( start.x > end.x )
581  std::swap( start, end );
582 
583  // calculate values relative to start point:
584  wxPoint delta = end - start;
585 
586  // calculate corners for the first quadrant only (delta.x and delta.y > 0 )
587  // currently, delta.x already is > 0.
588  // make delta.y > 0
589  bool change = delta.y < 0;
590 
591  if( change )
592  delta.y = -delta.y;
593 
594  // Now create the full polygon.
595  // Due to previous changes, the shape is always something like
596  // 3 4
597  // 2 5
598  // 1 6
599  wxPoint corner;
600  corner.x -= m_Size.x/2;
601  corner.y -= m_Size.y/2;
602  wxPoint close = corner;
603  m_Polygon.Append( VECTOR2I( corner ) ); // Lower left corner, start point (1)
604  corner.y += m_Size.y;
605  m_Polygon.Append( VECTOR2I( corner ) ); // upper left corner, start point (2)
606 
607  if( delta.x || delta.y)
608  {
609  corner += delta;
610  m_Polygon.Append( VECTOR2I( corner ) ); // upper left corner, end point (3)
611  }
612 
613  corner.x += m_Size.x;
614  m_Polygon.Append( VECTOR2I( corner ) ); // upper right corner, end point (4)
615  corner.y -= m_Size.y;
616  m_Polygon.Append( VECTOR2I( corner ) ); // lower right corner, end point (5)
617 
618  if( delta.x || delta.y )
619  {
620  corner -= delta;
621  m_Polygon.Append( VECTOR2I( corner ) ); // lower left corner, start point (6)
622  }
623 
624  m_Polygon.Append( VECTOR2I( close ) ); // close the shape
625 
626  // Create final polygon:
627  for( auto it = m_Polygon.Iterate( 0 ); it; ++it )
628  {
629  if( change )
630  ( *it ).y = -( *it ).y;
631 
632  *it += start;
633  }
634 }
635 
636 
637 void GERBER_DRAW_ITEM::PrintGerberPoly( wxDC* aDC, COLOR4D aColor, const wxPoint& aOffset,
638  bool aFilledShape )
639 {
640  std::vector<wxPoint> points;
641  SHAPE_LINE_CHAIN& poly = m_Polygon.Outline( 0 );
642  int pointCount = poly.PointCount() - 1;
643 
644  points.reserve( pointCount );
645 
646  for( int ii = 0; ii < pointCount; ii++ )
647  {
648  wxPoint p( poly.Point( ii ).x, poly.Point( ii ).y );
649  points[ii] = p + aOffset;
650  points[ii] = GetABPosition( points[ii] );
651  }
652 
653  GRClosedPoly( nullptr, aDC, pointCount, &points[0], aFilledShape, aColor, aColor );
654 }
655 
656 
657 void GERBER_DRAW_ITEM::GetMsgPanelInfo( EDA_UNITS_T aUnits, std::vector< MSG_PANEL_ITEM >& aList )
658 {
659  wxString msg;
660  wxString text;
661 
662  msg = ShowGBRShape();
663  aList.push_back( MSG_PANEL_ITEM( _( "Type" ), msg, DARKCYAN ) );
664 
665  // Display D_Code value with its attributes:
666  msg.Printf( _( "D Code %d" ), m_DCode );
667  D_CODE* apertDescr = GetDcodeDescr();
668 
669  if( !apertDescr || apertDescr->m_AperFunction.IsEmpty() )
670  text = _( "No attribute" );
671  else
672  text = apertDescr->m_AperFunction;
673 
674  aList.push_back( MSG_PANEL_ITEM( msg, text, RED ) );
675 
676  // Display graphic layer name
678  aList.push_back( MSG_PANEL_ITEM( _( "Graphic Layer" ), msg, DARKGREEN ) );
679 
680  // Display item rotation
681  // The full rotation is Image rotation + m_lyrRotation
682  // but m_lyrRotation is specific to this object
683  // so we display only this parameter
684  msg.Printf( wxT( "%f" ), m_lyrRotation );
685  aList.push_back( MSG_PANEL_ITEM( _( "Rotation" ), msg, BLUE ) );
686 
687  // Display item polarity (item specific)
688  msg = m_LayerNegative ? _("Clear") : _("Dark");
689  aList.push_back( MSG_PANEL_ITEM( _( "Polarity" ), msg, BLUE ) );
690 
691  // Display mirroring (item specific)
692  msg.Printf( wxT( "A:%s B:%s" ),
693  m_mirrorA ? _("Yes") : _("No"),
694  m_mirrorB ? _("Yes") : _("No"));
695  aList.push_back( MSG_PANEL_ITEM( _( "Mirror" ), msg, DARKRED ) );
696 
697  // Display AB axis swap (item specific)
698  msg = m_swapAxis ? wxT( "A=Y B=X" ) : wxT( "A=X B=Y" );
699  aList.push_back( MSG_PANEL_ITEM( _( "AB axis" ), msg, DARKRED ) );
700 
701  // Display net info, if exists
703  return;
704 
705  // Build full net info:
706  wxString net_msg;
707  wxString cmp_pad_msg;
708 
710  {
711  net_msg = _( "Net:" );
712  net_msg << " ";
713 
714  if( m_netAttributes.m_Netname.IsEmpty() )
715  net_msg << "<no net>";
716  else
718  }
719 
721  {
722  cmp_pad_msg.Printf( _( "Cmp: %s; Pad: %s" ),
725  }
726 
728  {
729  cmp_pad_msg = _( "Cmp:" );
730  cmp_pad_msg << " " << m_netAttributes.m_Cmpref;
731  }
732 
733  aList.push_back( MSG_PANEL_ITEM( net_msg, cmp_pad_msg, DARKCYAN ) );
734 }
735 
736 
738 {
739  if( m_Flashed )
740  return pad_xpm;
741 
742  switch( m_Shape )
743  {
744  case GBR_SEGMENT:
745  case GBR_ARC:
746  case GBR_CIRCLE:
747  return add_line_xpm;
748 
749  case GBR_SPOT_OVAL:
750  case GBR_SPOT_CIRCLE:
751  case GBR_SPOT_RECT:
752  case GBR_SPOT_POLY:
753  case GBR_SPOT_MACRO:
754  // should be handles by m_Flashed == true
755  return pad_xpm;
756 
757  case GBR_POLYGON:
758  return add_graphical_polygon_xpm;
759  }
760 
761  return info_xpm;
762 }
763 
764 
765 bool GERBER_DRAW_ITEM::HitTest( const wxPoint& aRefPos, int aAccuracy ) const
766 {
767  // In case the item has a very tiny width defined, allow it to be selected
768  const int MIN_HIT_TEST_RADIUS = Millimeter2iu( 0.01 );
769 
770  // calculate aRefPos in XY gerber axis:
771  wxPoint ref_pos = GetXYPosition( aRefPos );
772 
773  SHAPE_POLY_SET poly;
774 
775  switch( m_Shape )
776  {
777  case GBR_POLYGON:
778  poly = m_Polygon;
779  return poly.Contains( VECTOR2I( ref_pos ), 0, aAccuracy );
780 
781  case GBR_SPOT_POLY:
782  poly = GetDcodeDescr()->m_Polygon;
783  poly.Move( m_Start );
784  return poly.Contains( VECTOR2I( ref_pos ), 0, aAccuracy );
785 
786  case GBR_SPOT_RECT:
787  return GetBoundingBox().Contains( aRefPos );
788 
789  case GBR_ARC:
790  {
791  double radius = GetLineLength( m_Start, m_ArcCentre );
792  VECTOR2D test_radius = VECTOR2D( ref_pos ) - VECTOR2D( m_ArcCentre );
793 
794  int size = ( ( m_Size.x < MIN_HIT_TEST_RADIUS ) ? MIN_HIT_TEST_RADIUS
795  : m_Size.x );
796 
797  // Are we close enough to the radius?
798  bool radius_hit = ( std::fabs( test_radius.EuclideanNorm() - radius) < size );
799 
800  if( radius_hit )
801  {
802  // Now check that we are within the arc angle
803 
804  VECTOR2D start = VECTOR2D( m_Start ) - VECTOR2D( m_ArcCentre );
806 
807  double start_angle = NormalizeAngleRadiansPos( start.Angle() );
808  double end_angle = NormalizeAngleRadiansPos( end.Angle() );
809 
810  if( m_Start == m_End )
811  {
812  start_angle = 0;
813  end_angle = 2 * M_PI;
814  }
815  else if( end_angle < start_angle )
816  {
817  end_angle += 2 * M_PI;
818  }
819 
820  double test_angle = NormalizeAngleRadiansPos( test_radius.Angle() );
821 
822  return ( test_angle > start_angle && test_angle < end_angle );
823  }
824 
825  return false;
826  }
827 
828  case GBR_SPOT_MACRO:
829  // Aperture macro polygons are already in absolute coordinates
830  auto p = GetDcodeDescr()->GetMacro()->GetApertureMacroShape( this, m_Start );
831  return p->Contains( VECTOR2I( aRefPos ), -1, aAccuracy );
832  }
833 
834  // TODO: a better analyze of the shape (perhaps create a D_CODE::HitTest for flashed items)
835  int radius = std::min( m_Size.x, m_Size.y ) >> 1;
836 
837  if( radius < MIN_HIT_TEST_RADIUS )
838  radius = MIN_HIT_TEST_RADIUS;
839 
840  if( m_Flashed )
841  return HitTestPoints( m_Start, ref_pos, radius );
842  else
843  return TestSegmentHit( ref_pos, m_Start, m_End, radius );
844 }
845 
846 
847 bool GERBER_DRAW_ITEM::HitTest( const EDA_RECT& aRefArea, bool aContained, int aAccuracy ) const
848 {
849  wxPoint pos = GetABPosition( m_Start );
850 
851  if( aRefArea.Contains( pos ) )
852  return true;
853 
854  pos = GetABPosition( m_End );
855 
856  if( aRefArea.Contains( pos ) )
857  return true;
858 
859  return false;
860 }
861 
862 
863 #if defined(DEBUG)
864 
865 void GERBER_DRAW_ITEM::Show( int nestLevel, std::ostream& os ) const
866 {
867  NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() <<
868 
869  " shape=\"" << m_Shape << '"' <<
870  " addr=\"" << std::hex << this << std::dec << '"' <<
871  " layer=\"" << GetLayer() << '"' <<
872  " size=\"" << m_Size << '"' <<
873  " flags=\"" << m_Flags << '"' <<
874  " status=\"" << GetStatus() << '"' <<
875  "<start" << m_Start << "/>" <<
876  "<end" << m_End << "/>";
877 
878  os << "</" << GetClass().Lower().mb_str() << ">\n";
879 }
880 
881 #endif
882 
883 
884 void GERBER_DRAW_ITEM::ViewGetLayers( int aLayers[], int& aCount ) const
885 {
886  aCount = 2;
887 
888  aLayers[0] = GERBER_DRAW_LAYER( GetLayer() );
889  aLayers[1] = GERBER_DCODE_LAYER( aLayers[0] );
890 }
891 
892 
894 {
895  EDA_RECT bbox = GetBoundingBox();
896  return BOX2I( VECTOR2I( bbox.GetOrigin() ),
897  VECTOR2I( bbox.GetSize() ) );
898 }
899 
900 
901 unsigned int GERBER_DRAW_ITEM::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
902 {
903  // DCodes will be shown only if zoom is appropriate:
904  // Returns the level of detail of the item.
905  // A level of detail (LOD) is the minimal VIEW scale that
906  // is sufficient for an item to be shown on a given layer.
907  if( IsDCodeLayer( aLayer ) )
908  {
909  int size = 0;
910 
911  switch( m_Shape )
912  {
913  case GBR_SPOT_MACRO:
915  break;
916 
917  case GBR_ARC:
918  size = GetLineLength( m_Start, m_ArcCentre );
919  break;
920 
921  default:
922  size = m_Size.x;
923  }
924 
925  // the level of details is chosen experimentally, to show
926  // only a readable text:
927  const int level = Millimeter2iu( 4 );
928  return ( level / ( size + 1 ) );
929  }
930 
931  // Other layers are shown without any conditions
932  return 0;
933 }
934 
935 
936 SEARCH_RESULT GERBER_DRAW_ITEM::Visit( INSPECTOR inspector, void* testData, const KICAD_T scanTypes[] )
937 {
938  KICAD_T stype = *scanTypes;
939 
940  // If caller wants to inspect my type
941  if( stype == Type() )
942  {
943  if( SEARCH_QUIT == inspector( this, testData ) )
944  return SEARCH_QUIT;
945  }
946 
947  return SEARCH_CONTINUE;
948 }
949 
950 
952 {
953  wxString layerName;
954 
956 
957  return wxString::Format( _( "%s (D%d) on layer %d: %s" ),
958  ShowGBRShape(),
959  m_DCode,
960  GetLayer() + 1,
961  layerName );
962 }
Definition: colors.h:57
#define TEXT_ANGLE_HORIZ
void SetLayerParameters()
Function SetLayerParameters Initialize parameters from Image and Layer parameters found in the gerber...
bool m_DisplayPolygonsFill
Option to draw polygons (filled/sketch)
STATUS_FLAGS GetStatus() const
Definition: base_struct.h:249
BOX2< VECTOR2I > BOX2I
Definition: box2.h:520
void Move(const wxPoint &aMoveVector)
Function Move moves the rectangle by the aMoveVector.
D_CODE * GetDcodeDescr() const
Function GetDcodeDescr returns the GetDcodeDescr of this object, or NULL.
virtual unsigned int ViewGetLOD(int aLayer, KIGFX::VIEW *aView) const override
bool IsDCodeLayer(int aLayer)
wxString name
The name of the aperture macro.
Definition: am_primitive.h:165
int OutlineCount() const
Returns the number of outlines in the set
wxString GetClass() const override
Function GetClass returns the class name.
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:202
BITMAP_DEF GetMenuImage() const override
void MoveAB(const wxPoint &aMoveVector)
Function MoveAB move this object.
static int KiROUND(double v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:118
print info associated to a component (TO.C attribute)
wxSize m_Size
Horizontal and vertical dimensions.
Definition: dcode.h:94
const wxString GetDisplayName(int aIdx, bool aNameOnly=false)
bool HasNegativeItems()
Function HasNegativeItems.
APERTURE_T m_Shape
shape ( Line, rectangle, circle , oval .. )
Definition: dcode.h:95
int color
Definition: DXF_plotter.cpp:62
virtual const BOX2I ViewBBox() const override
int GetLayer() const
Function GetLayer returns the layer this item is on.
D_CODE * GetDCODE(int aDCODE) const
Function GetDCODE returns a pointer to the D_CODE within this GERBER for the given aDCODE.
Class GERBER_FILE_IMAGE holds the Image data and parameters for one gerber file and layer parameters ...
int GetWidth() const
Definition: eda_rect.h:117
COLOR4D GetPositiveDrawColor() const
double RAD2DECIDEG(double rad)
Definition: trigo.h:215
GERBER_DRAW_ITEM(GERBER_FILE_IMAGE *aGerberparams)
wxString m_Cmpref
the component reference parent of the data
void SetOrigin(const wxPoint &pos)
Definition: eda_rect.h:124
void Print(wxDC *aDC, const wxPoint &aOffset, GBR_DISPLAY_OPTIONS *aOptions)
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:312
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
bool HitTest(const wxPoint &aRefPos, int aAccuracy=0) const override
Function HitTest tests if the given wxPoint is within the bounds of this object.
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Returns true if a given subpolygon contains the point aP.
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:229
void SetNetAttributes(const GBR_NETLIST_METADATA &aNetAttributes)
ITERATOR Iterate(int aFirst, int aLast, bool aIterateHoles=false)
Function Iterate returns an object to iterate through the points of the polygons between aFirst and a...
this class handle info which can be added in a gerber file as attribute of an obtect the GBR_INFO_TYP...
double NormalizeAngleRadiansPos(double Angle)
Definition: trigo.h:276
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...
VECTOR2< int > VECTOR2I
Definition: vector2d.h:587
int PointCount() const
Function PointCount()
SHAPE_POLY_SET m_Polygon
virtual void ViewGetLayers(int aLayers[], int &aCount) const override
SEARCH_RESULT Visit(INSPECTOR inspector, void *testData, const KICAD_T scanTypes[]) override
void NORMALIZE_ANGLE_90(T &Angle)
Definition: trigo.h:331
bool Contains(const wxPoint &aPoint) const
Function Contains.
void GRClosedPoly(EDA_RECT *ClipBox, wxDC *DC, int n, wxPoint Points[], bool Fill, COLOR4D Color, COLOR4D BgColor)
Function GRClosedPoly draws a closed polygon onto the drawing context aDC and optionally fills and/or...
Definition: gr_basic.cpp:556
Definition: dcode.h:52
KICAD_T
Enum KICAD_T is the set of class identification values, stored in EDA_ITEM::m_StructType.
Definition: typeinfo.h:78
Definition: colors.h:54
bool m_DisplayLinesFill
Option to draw line items (filled/sketch)
#define LAST_DCODE
Definition: dcode.h:72
#define GERBER_DCODE_LAYER(x)
const INSPECTOR_FUNC & INSPECTOR
Definition: base_struct.h:95
const wxPoint GetEnd() const
Definition: eda_rect.h:114
COLOR4D m_NegativeDrawColor
The color used to draw negative objects, usually the background color, but not always,...
wxString m_Padname
for a flashed pad: the pad name ((TO.P attribute)
wxPoint GetABPosition(const wxPoint &aXYPosition) const
Function GetABPosition returns the image position of aPosition for this object.
SHAPE_POLY_SET * GetApertureMacroShape(const GERBER_DRAW_ITEM *aParent, wxPoint aShapePos)
Function GetApertureMacroShape Calculate the primitive shape for flashed items.
VECTOR2< double > VECTOR2D
Definition: vector2d.h:586
void Move(const VECTOR2I &aVector) override
EDA_RECT GetBoundingBox() const
Returns the bounding box of the shape.
Definition: am_primitive.h:231
#define FIRST_DCODE
Definition: dcode.h:71
Class SHAPE_POLY_SET.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Returns the reference to aIndex-th outline in the set
const wxPoint GetOrigin() const
Definition: eda_rect.h:112
void SetEnd(int x, int y)
Definition: eda_rect.h:134
coord_type GetWidth() const
Definition: box2.h:195
bool m_DisplayFlashedItemsFill
Option to draw flashed items (filled/sketch)
static GERBER_FILE_IMAGE_LIST & GetImagesList()
GBR_NETLIST_METADATA m_netAttributes
the string given by a TO attribute set in aperture (dcode).
bool GetTextD_CodePrms(int &aSize, wxPoint &aPos, double &aOrientation)
Returns the best size and orientation to display the D_Code on screen.
wxString m_Netname
for items associated to a net: the netname
Definition: colors.h:60
double Angle() const
Function Angle computes the angle of the vector.
Definition: vector2d.h:306
int NewOutline()
Creates a new empty polygon in the set and returns its index
#define _(s)
void ConvertSegmentToPolygon()
Function ConvertSegmentToPolygon convert a line to an equivalent polygon.
std::map< wxString, int > m_NetnamesList
wxString m_AperFunction
the aperture attribute (created by a TA.AperFunction command) attached to the D_CODE
Definition: dcode.h:105
virtual wxString GetSelectMenuText(EDA_UNITS_T aUnits) const override
void Normalize()
Function Normalize ensures that the height ant width are positive.
void PrintGerberPoly(wxDC *aDC, COLOR4D aColor, const wxPoint &aOffset, bool aFilledShape)
Function PrintGerberPoly a helper function used to print the polygon stored in m_PolyCorners.
Class D_CODE holds a gerber DCODE (also called Aperture) definition.
Definition: dcode.h:82
const char * name
Definition: DXF_plotter.cpp:61
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
void DrawFlashedShape(GERBER_DRAW_ITEM *aParent, EDA_RECT *aClipBox, wxDC *aDC, COLOR4D aColor, wxPoint aShapePos, bool aFilledShape)
Function DrawFlashedShape Draw the dcode shape for flashed items.
Definition: dcode.cpp:152
Class SHAPE_LINE_CHAIN.
wxString UnescapeString(const wxString &aSource)
Definition: string.cpp:123
void GRFilledSegment(EDA_RECT *aClipBox, wxDC *aDC, wxPoint aStart, wxPoint aEnd, int aWidth, COLOR4D aColor)
Definition: gr_basic.cpp:423
void GRCircle(EDA_RECT *ClipBox, wxDC *DC, int xc, int yc, int r, int width, COLOR4D Color)
Definition: gr_basic.cpp:600
bool HitTestPoints(const wxPoint &pointA, const wxPoint &pointB, double threshold)
Test, if two points are near each other.
Definition: trigo.h:161
STATUS_FLAGS m_Flags
Flag bits for editing and other uses.
Definition: base_struct.h:174
void RemoveAllContours()
Removes all outlines & holes (clears) the polygon set.
Class EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
double DECIDEG2RAD(double deg)
Definition: trigo.h:214
SHAPE_POLY_SET m_Polygon
Definition: dcode.h:107
Class EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boa...
Definition: base_struct.h:150
The common library.
coord_type GetHeight() const
Definition: box2.h:196
APERTURE_MACRO * GetMacro() const
Definition: dcode.h:157
print info associated to a flashed pad (TO.P attribute)
VECTOR2I & Point(int aIndex)
Function Point()
T EuclideanNorm() const
Destructor.
Definition: vector2d.h:292
wxPoint GetXYPosition(const wxPoint &aABPosition) const
Function GetXYPosition returns the image position of aPosition for this object.
#define GERBER_DRAW_LAYER(x)
void ConvertShapeToPolygon()
Function ConvertShapeToPolygon convert a shape to an equivalent polygon.
Definition: dcode.cpp:301
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:126
SEARCH_RESULT
Definition: base_struct.h:59
void MoveXY(const wxPoint &aMoveVector)
Function MoveXY move this object.
Message panel definition file.
print info associated to a net (TO.N attribute)
const BOX2I BBox(int aClearance=0) const override
Function BBox()
int GetShapeDim(GERBER_DRAW_ITEM *aParent)
Function GetShapeDim calculates a value that can be used to evaluate the size of text when displaying...
Definition: dcode.cpp:121
GERBER_FILE_IMAGE * m_GerberImageFile
std::map< wxString, int > m_ComponentsList
EDA_UNITS_T
Definition: common.h:157
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
GERBER_LAYER & GetLayerParams()
Function GetLayerParams.
const wxSize GetSize() const
Definition: eda_rect.h:101
KICAD_T Type() const
Function Type()
Definition: base_struct.h:197
#define min(a, b)
Definition: auxiliary.h:85
int m_NetAttribType
the type of net info (used to define the gerber string to create)
wxString ShowGBRShape() const
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
void GRArc1(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int xc, int yc, COLOR4D Color)
Definition: gr_basic.cpp:644
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39
wxRealPoint m_drawScale