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-2021 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 <trigo.h>
26 #include <bitmaps.h>
27 #include <eda_text.h>
28 #include <gerbview_frame.h>
30 #include <gerber_draw_item.h>
31 #include <gerber_file_image.h>
32 #include <gerber_file_image_list.h>
33 #include <string_utils.h>
34 #include <geometry/shape_arc.h>
35 #include <math/util.h> // for KiROUND
36 #include <widgets/msgpanel.h>
37 
38 #include <wx/msgdlg.h>
39 
41  EDA_ITEM( nullptr, GERBER_DRAW_ITEM_T )
42 {
43  m_GerberImageFile = aGerberImageFile;
45  m_Flashed = false;
46  m_DCode = 0;
47  m_UnitsMetric = false;
48  m_LayerNegative = false;
49  m_swapAxis = false;
50  m_mirrorA = false;
51  m_mirrorB = false;
52  m_drawScale.x = m_drawScale.y = 1.0;
53  m_lyrRotation = 0;
54 
55  if( m_GerberImageFile )
57 }
58 
59 
61 {
62 }
63 
64 
66 {
67  m_netAttributes = aNetAttributes;
68 
71  m_GerberImageFile->m_ComponentsList.insert( std::make_pair( m_netAttributes.m_Cmpref, 0 ) );
72 
74  m_GerberImageFile->m_NetnamesList.insert( std::make_pair( m_netAttributes.m_Netname, 0 ) );
75 }
76 
77 
79 {
80  // Return the layer this item is on, or 0 if the m_GerberImageFile is null.
82 }
83 
84 
85 bool GERBER_DRAW_ITEM::GetTextD_CodePrms( int& aSize, wxPoint& aPos, double& aOrientation )
86 {
87  // calculate the best size and orientation of the D_Code text
88 
89  if( m_DCode <= 0 )
90  return false; // No D_Code for this item
91 
92  if( m_Flashed || m_Shape == GBR_ARC )
93  {
94  aPos = m_Start;
95  }
96  else // it is a line:
97  {
98  aPos = ( m_Start + m_End) / 2;
99  }
100 
101  aPos = GetABPosition( aPos );
102 
103  int size; // the best size for the text
104 
105  if( GetDcodeDescr() )
106  size = GetDcodeDescr()->GetShapeDim( this );
107  else
108  size = std::min( m_Size.x, m_Size.y );
109 
110  aOrientation = TEXT_ANGLE_HORIZ;
111 
112  if( m_Flashed )
113  {
114  // A reasonable size for text is min_dim/3 because most of time this text has 3 chars.
115  aSize = size / 3;
116  }
117  else // this item is a line
118  {
119  wxPoint delta = m_Start - m_End;
120 
121  aOrientation = RAD2DECIDEG( atan2( (double)delta.y, (double)delta.x ) );
122  NORMALIZE_ANGLE_90( aOrientation );
123 
124  // A reasonable size for text is size/2 because text needs margin below and above it.
125  // a margin = size/4 seems good, expecting the line len is large enough to show 3 chars,
126  // that is the case most of time.
127  aSize = size / 2;
128  }
129 
130  return true;
131 }
132 
133 
134 bool GERBER_DRAW_ITEM::GetTextD_CodePrms( double& aSize, VECTOR2D& aPos, double& aOrientation )
135 {
136  // aOrientation is returned in radians
137  int size;
138  wxPoint pos;
139 
140  if( ! GetTextD_CodePrms( size, pos, aOrientation ) )
141  return false;
142 
143  aPos = pos;
144  aSize = (double) size;
145  aOrientation = DECIDEG2RAD( aOrientation );
146 
147  return true;
148 }
149 
150 
151 wxPoint GERBER_DRAW_ITEM::GetABPosition( const wxPoint& aXYPosition ) const
152 {
153  /* Note: RS274Xrevd_e is obscure about the order of transforms:
154  * For instance: Rotation must be made after or before mirroring ?
155  * Note: if something is changed here, GetYXPosition must reflect changes
156  */
157  wxPoint abPos = aXYPosition + m_GerberImageFile->m_ImageJustifyOffset;
158 
159  if( m_swapAxis )
160  std::swap( abPos.x, abPos.y );
161 
163  abPos.x = KiROUND( abPos.x * m_drawScale.x );
164  abPos.y = KiROUND( abPos.y * m_drawScale.y );
165  double rotation = m_lyrRotation * 10 + m_GerberImageFile->m_ImageRotation * 10;
166 
167  if( rotation )
168  RotatePoint( &abPos, -rotation );
169 
170  // Negate A axis if mirrored
171  if( m_mirrorA )
172  abPos.x = -abPos.x;
173 
174  // abPos.y must be negated when no mirror, because draw axis is top to bottom
175  if( !m_mirrorB )
176  abPos.y = -abPos.y;
177 
178  return abPos;
179 }
180 
181 
182 wxPoint GERBER_DRAW_ITEM::GetXYPosition( const wxPoint& aABPosition ) const
183 {
184  // do the inverse transform made by GetABPosition
185  wxPoint xyPos = aABPosition;
186 
187  if( m_mirrorA )
188  xyPos.x = -xyPos.x;
189 
190  if( !m_mirrorB )
191  xyPos.y = -xyPos.y;
192 
193  double rotation = m_lyrRotation * 10 + m_GerberImageFile->m_ImageRotation * 10;
194 
195  if( rotation )
196  RotatePoint( &xyPos, rotation );
197 
198  xyPos.x = KiROUND( xyPos.x / m_drawScale.x );
199  xyPos.y = KiROUND( xyPos.y / m_drawScale.y );
201 
202  if( m_swapAxis )
203  std::swap( xyPos.x, xyPos.y );
204 
205  return xyPos - m_GerberImageFile->m_ImageJustifyOffset;
206 }
207 
208 
210 {
212  m_swapAxis = m_GerberImageFile->m_SwapAxis; // false if A = X, B = Y;
213 
214  // true if A =Y, B = Y
215  m_mirrorA = m_GerberImageFile->m_MirrorA; // true: mirror / axe A
216  m_mirrorB = m_GerberImageFile->m_MirrorB; // true: mirror / axe B
217  m_drawScale = m_GerberImageFile->m_Scale; // A and B scaling factor
218  m_layerOffset = m_GerberImageFile->m_Offset; // Offset from OF command
219 
220  // Rotation from RO command:
223 }
224 
225 
227 {
228  switch( m_Shape )
229  {
230  case GBR_SEGMENT:
231  return _( "Line" );
232 
233  case GBR_ARC:
234  return _( "Arc" );
235 
236  case GBR_CIRCLE:
237  return _( "Circle" );
238 
239  case GBR_SPOT_OVAL:
240  return wxT( "spot_oval" );
241 
242  case GBR_SPOT_CIRCLE:
243  return wxT( "spot_circle" );
244 
245  case GBR_SPOT_RECT:
246  return wxT( "spot_rect" );
247 
248  case GBR_SPOT_POLY:
249  return wxT( "spot_poly" );
250 
251  case GBR_POLYGON:
252  return wxT( "polygon" );
253 
254  case GBR_SPOT_MACRO:
255  {
256  wxString name = wxT( "apt_macro" );
257  D_CODE* dcode = GetDcodeDescr();
258 
259  if( dcode && dcode->GetMacro() )
260  name << wxT(" ") << dcode->GetMacro()->name;
261 
262  return name;
263  }
264 
265  default:
266  return wxT( "??" );
267  }
268 }
269 
270 
272 {
273  if( ( m_DCode < FIRST_DCODE ) || ( m_DCode > LAST_DCODE ) )
274  return nullptr;
275 
276  if( m_GerberImageFile == nullptr )
277  return nullptr;
278 
280 }
281 
282 
284 {
285  // return a rectangle which is (pos,dim) in nature. therefore the +1
286  EDA_RECT bbox( m_Start, wxSize( 1, 1 ) );
287  D_CODE* code = GetDcodeDescr();
288 
289  // TODO(JE) GERBER_DRAW_ITEM maybe should actually be a number of subclasses.
290  // Until/unless that is changed, we need to do different things depending on
291  // what is actually being represented by this GERBER_DRAW_ITEM.
292 
293  switch( m_Shape )
294  {
295  case GBR_POLYGON:
296  {
297  auto bb = m_Polygon.BBox();
298  bbox.Inflate( bb.GetWidth() / 2, bb.GetHeight() / 2 );
299  bbox.SetOrigin( bb.GetOrigin().x, bb.GetOrigin().y );
300  break;
301  }
302 
303  case GBR_CIRCLE:
304  {
305  double radius = GetLineLength( m_Start, m_End );
306  bbox.Inflate( radius, radius );
307  break;
308  }
309 
310  case GBR_ARC:
311  {
312  double arc_angle =
313  atan2( double( m_End.y - m_ArcCentre.y ), double( m_End.x - m_ArcCentre.x ) )
314  - atan2( double( m_Start.y - m_ArcCentre.y ), double( m_Start.x - m_ArcCentre.x ) );
315 
316  arc_angle *= 180.0 / M_PI;
317 
318  if( arc_angle < 0.0 )
319  arc_angle += 360.0;
320 
321  if( m_End == m_Start ) // Arc with the end point = start point is expected to be a circle.
322  arc_angle = 360.0;
323 
324  SHAPE_ARC arc( m_ArcCentre, m_Start, arc_angle );
325  BOX2I arc_bbox = arc.BBox( m_Size.x / 2 ); // m_Size.x is the line thickness
326  bbox.SetOrigin( arc_bbox.GetX(), arc_bbox.GetY() );
327  bbox.SetWidth( arc_bbox.GetWidth() );
328  bbox.SetHeight( arc_bbox.GetHeight() );
329  break;
330  }
331 
332  case GBR_SPOT_CIRCLE:
333  {
334  if( code )
335  {
336  int radius = code->m_Size.x >> 1;
337  bbox.Inflate( radius, radius );
338  }
339 
340  break;
341  }
342 
343  case GBR_SPOT_RECT:
344  {
345  if( code )
346  bbox.Inflate( code->m_Size.x / 2, code->m_Size.y / 2 );
347 
348  break;
349  }
350 
351  case GBR_SPOT_OVAL:
352  {
353  if( code )
354  bbox.Inflate( code->m_Size.x /2, code->m_Size.y / 2 );
355 
356  break;
357  }
358 
359  case GBR_SPOT_POLY:
360  {
361  if( code )
362  {
363  if( code->m_Polygon.OutlineCount() == 0 )
364  code->ConvertShapeToPolygon();
365 
366  bbox.Inflate( code->m_Polygon.BBox().GetWidth() / 2,
367  code->m_Polygon.BBox().GetHeight() / 2 );
368  }
369 
370  break;
371  }
372  case GBR_SPOT_MACRO:
373  {
374  if( code )
375  {
376  // Update the shape drawings and the bounding box coordinates:
377  code->GetMacro()->GetApertureMacroShape( this, m_Start );
378 
379  // now the bounding box is valid:
380  bbox = code->GetMacro()->GetBoundingBox();
381  }
382 
383  break;
384  }
385 
386  case GBR_SEGMENT:
387  {
388  if( code && code->m_Shape == APT_RECT )
389  {
390  if( m_Polygon.OutlineCount() == 0 )
391  {
392  // We cannot initialize m_Polygon, because we are in a const function.
393  // So use a temporary polygon
394  SHAPE_POLY_SET poly_shape;
395  ConvertSegmentToPolygon( &poly_shape );
396  BOX2I bb = poly_shape.BBox();
397  bbox.SetSize( bb.GetWidth(), bb.GetHeight() );
398  bbox.SetOrigin( bb.GetOrigin().x, bb.GetOrigin().y );
399  }
400 
401  else
402  {
403  BOX2I bb = m_Polygon.BBox();
404  bbox.SetSize( bb.GetWidth(), bb.GetHeight() );
405  bbox.SetOrigin( bb.GetOrigin().x, bb.GetOrigin().y );
406  }
407  }
408  else
409  {
410  int radius = ( m_Size.x + 1 ) / 2;
411 
412  int ymax = std::max( m_Start.y, m_End.y ) + radius;
413  int xmax = std::max( m_Start.x, m_End.x ) + radius;
414 
415  int ymin = std::min( m_Start.y, m_End.y ) - radius;
416  int xmin = std::min( m_Start.x, m_End.x ) - radius;
417 
418  bbox = EDA_RECT( wxPoint( xmin, ymin ), wxSize( xmax - xmin + 1, ymax - ymin + 1 ) );
419  }
420 
421  break;
422  }
423  default:
424  wxASSERT_MSG( false, wxT( "GERBER_DRAW_ITEM shape is unknown!" ) );
425  break;
426  }
427 
428  // calculate the corners coordinates in current Gerber axis orientations
429  wxPoint org = GetABPosition( bbox.GetOrigin() );
430  wxPoint end = GetABPosition( bbox.GetEnd() );
431 
432  // Set the corners position:
433  bbox.SetOrigin( org );
434  bbox.SetEnd( end );
435  bbox.Normalize();
436 
437  return bbox;
438 }
439 
440 
441 void GERBER_DRAW_ITEM::MoveAB( const wxPoint& aMoveVector )
442 {
443  wxPoint xymove = GetXYPosition( aMoveVector );
444 
445  m_Start += xymove;
446  m_End += xymove;
447  m_ArcCentre += xymove;
448 
449  m_Polygon.Move( VECTOR2I( xymove ) );
450 }
451 
452 
453 void GERBER_DRAW_ITEM::MoveXY( const wxPoint& aMoveVector )
454 {
455  m_Start += aMoveVector;
456  m_End += aMoveVector;
457  m_ArcCentre += aMoveVector;
458 
459  m_Polygon.Move( VECTOR2I( aMoveVector ) );
460 }
461 
462 
464 {
466 
467  // if isClear is true, this item has negative shape
468  return isClear;
469 }
470 
471 
472 void GERBER_DRAW_ITEM::Print( wxDC* aDC, const wxPoint& aOffset, GBR_DISPLAY_OPTIONS* aOptions )
473 {
474  // used when a D_CODE is not found. default D_CODE to draw a flashed item
475  static D_CODE dummyD_CODE( 0 );
476  bool isFilled;
477  int radius;
478  int halfPenWidth;
479  static bool show_err;
480  D_CODE* d_codeDescr = GetDcodeDescr();
481 
482  if( d_codeDescr == nullptr )
483  d_codeDescr = &dummyD_CODE;
484 
486 
487  /* isDark is true if flash is positive and should use a drawing
488  * color other than the background color, else use the background color
489  * when drawing so that an erasure happens.
490  */
492 
493  if( !isDark )
494  {
495  // draw in background color ("negative" color)
496  color = aOptions->m_NegativeDrawColor;
497  }
498 
499  isFilled = aOptions->m_DisplayLinesFill;
500 
501  switch( m_Shape )
502  {
503  case GBR_POLYGON:
504  isFilled = aOptions->m_DisplayPolygonsFill;
505 
506  if( !isDark )
507  isFilled = true;
508 
509  PrintGerberPoly( aDC, color, aOffset, isFilled );
510  break;
511 
512  case GBR_CIRCLE:
513  radius = KiROUND( GetLineLength( m_Start, m_End ) );
514 
515  halfPenWidth = m_Size.x >> 1;
516 
517  if( !isFilled )
518  {
519  // draw the border of the pen's path using two circles, each as narrow as possible
520  GRCircle( nullptr, aDC, GetABPosition( m_Start ), radius - halfPenWidth, 0, color );
521  GRCircle( nullptr, aDC, GetABPosition( m_Start ), radius + halfPenWidth, 0, color );
522  }
523  else // Filled mode
524  {
525  GRCircle( nullptr, aDC, GetABPosition( m_Start ), radius, m_Size.x, color );
526  }
527 
528  break;
529 
530  case GBR_ARC:
531  // Currently, arcs plotted with a rectangular aperture are not supported.
532  // a round pen only is expected.
533  if( !isFilled )
534  {
535  GRArc1( nullptr, aDC, GetABPosition( m_Start ), GetABPosition( m_End ),
537  }
538  else
539  {
540  GRArc1( nullptr, aDC, GetABPosition( m_Start ), GetABPosition( m_End ),
542  }
543 
544  break;
545 
546  case GBR_SPOT_CIRCLE:
547  case GBR_SPOT_RECT:
548  case GBR_SPOT_OVAL:
549  case GBR_SPOT_POLY:
550  case GBR_SPOT_MACRO:
551  isFilled = aOptions->m_DisplayFlashedItemsFill;
552  d_codeDescr->DrawFlashedShape( this, nullptr, aDC, color, m_Start, isFilled );
553  break;
554 
555  case GBR_SEGMENT:
556  /* Plot a line from m_Start to m_End.
557  * Usually, a round pen is used, but some Gerber files use a rectangular pen
558  * In fact, any aperture can be used to plot a line.
559  * currently: only a square pen is handled (I believe using a polygon gives a strange plot).
560  */
561  if( d_codeDescr->m_Shape == APT_RECT )
562  {
563  if( m_Polygon.OutlineCount() == 0 )
565 
566  PrintGerberPoly( aDC, color, aOffset, isFilled );
567  }
568  else
569  {
570  if( !isFilled )
571  {
572  GRCSegm( nullptr, aDC, GetABPosition( m_Start ), GetABPosition( m_End ),
573  m_Size.x, color );
574  }
575  else
576  {
578  m_Size.x, color );
579  }
580  }
581 
582  break;
583 
584  default:
585  if( !show_err )
586  {
587  wxMessageBox( wxT( "Trace_Segment() type error" ) );
588  show_err = true;
589  }
590 
591  break;
592  }
593 }
594 
595 
597 {
598  aPolygon->RemoveAllContours();
599  aPolygon->NewOutline();
600 
601  wxPoint start = m_Start;
602  wxPoint end = m_End;
603 
604  // make calculations more easy if ensure start.x < end.x
605  // (only 2 quadrants to consider)
606  if( start.x > end.x )
607  std::swap( start, end );
608 
609  // calculate values relative to start point:
610  wxPoint delta = end - start;
611 
612  // calculate corners for the first quadrant only (delta.x and delta.y > 0 )
613  // currently, delta.x already is > 0.
614  // make delta.y > 0
615  bool change = delta.y < 0;
616 
617  if( change )
618  delta.y = -delta.y;
619 
620  // Now create the full polygon.
621  // Due to previous changes, the shape is always something like
622  // 3 4
623  // 2 5
624  // 1 6
625  wxPoint corner;
626  corner.x -= m_Size.x/2;
627  corner.y -= m_Size.y/2;
628  wxPoint close = corner;
629  aPolygon->Append( VECTOR2I( corner ) ); // Lower left corner, start point (1)
630  corner.y += m_Size.y;
631  aPolygon->Append( VECTOR2I( corner ) ); // upper left corner, start point (2)
632 
633  if( delta.x || delta.y )
634  {
635  corner += delta;
636  aPolygon->Append( VECTOR2I( corner ) ); // upper left corner, end point (3)
637  }
638 
639  corner.x += m_Size.x;
640  aPolygon->Append( VECTOR2I( corner ) ); // upper right corner, end point (4)
641  corner.y -= m_Size.y;
642  aPolygon->Append( VECTOR2I( corner ) ); // lower right corner, end point (5)
643 
644  if( delta.x || delta.y )
645  {
646  corner -= delta;
647  aPolygon->Append( VECTOR2I( corner ) ); // lower left corner, start point (6)
648  }
649 
650  aPolygon->Append( VECTOR2I( close ) ); // close the shape
651 
652  // Create final polygon:
653  if( change )
654  aPolygon->Mirror( false, true );
655 
656  aPolygon->Move( VECTOR2I( start ) );
657 }
658 
659 
661 {
663 }
664 
665 
666 void GERBER_DRAW_ITEM::PrintGerberPoly( wxDC* aDC, const COLOR4D& aColor, const wxPoint& aOffset,
667  bool aFilledShape )
668 {
669  std::vector<wxPoint> points;
670  SHAPE_LINE_CHAIN& poly = m_Polygon.Outline( 0 );
671  int pointCount = poly.PointCount() - 1;
672 
673  points.reserve( pointCount );
674 
675  for( int ii = 0; ii < pointCount; ii++ )
676  {
677  wxPoint p( poly.CPoint( ii ).x, poly.CPoint( ii ).y );
678  points[ii] = p + aOffset;
679  points[ii] = GetABPosition( points[ii] );
680  }
681 
682  GRClosedPoly( nullptr, aDC, pointCount, &points[0], aFilledShape, aColor, aColor );
683 }
684 
685 
686 void GERBER_DRAW_ITEM::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
687 {
688  wxString msg;
689  wxString text;
690 
691  msg = ShowGBRShape();
692  aList.emplace_back( _( "Type" ), msg );
693 
694  // Display D_Code value with its attributes for items using a DCode:
695  if( m_Shape == GBR_POLYGON ) // Has no DCode, but can have an attribute
696  {
697  msg = _( "Attribute" );
698 
699  if( m_AperFunction.IsEmpty() )
700  text = _( "No attribute" );
701  else
703  }
704  else
705  {
706  msg.Printf( _( "D Code %d" ), m_DCode );
707  D_CODE* apertDescr = GetDcodeDescr();
708 
709  if( !apertDescr || apertDescr->m_AperFunction.IsEmpty() )
710  text = _( "No attribute" );
711  else
712  text = apertDescr->m_AperFunction;
713  }
714 
715  aList.emplace_back( msg, text );
716 
717  // Display graphic layer name
719  aList.emplace_back( _( "Graphic Layer" ), msg );
720 
721  // Display item rotation
722  // The full rotation is Image rotation + m_lyrRotation
723  // but m_lyrRotation is specific to this object
724  // so we display only this parameter
725  msg.Printf( wxT( "%f" ), m_lyrRotation );
726  aList.emplace_back( _( "Rotation" ), msg );
727 
728  // Display item polarity (item specific)
729  msg = m_LayerNegative ? _("Clear") : _("Dark");
730  aList.emplace_back( _( "Polarity" ), msg );
731 
732  // Display mirroring (item specific)
733  msg.Printf( wxT( "A:%s B:%s" ), m_mirrorA ? _( "Yes" ) : _( "No" ),
734  m_mirrorB ? _( "Yes" ) : _( "No" ) );
735  aList.emplace_back( _( "Mirror" ), msg );
736 
737  // Display AB axis swap (item specific)
738  msg = m_swapAxis ? wxT( "A=Y B=X" ) : wxT( "A=X B=Y" );
739  aList.emplace_back( _( "AB axis" ), msg );
740 
741  // Display net info, if exists
743  return;
744 
745  // Build full net info:
746  wxString net_msg;
747  wxString cmp_pad_msg;
748 
750  {
751  net_msg = _( "Net:" );
752  net_msg << " ";
753 
754  if( m_netAttributes.m_Netname.IsEmpty() )
755  net_msg << "<no net>";
756  else
758  }
759 
761  {
763  cmp_pad_msg.Printf( _( "Cmp: %s Pad: %s" ),
766  else
767  cmp_pad_msg.Printf( _( "Cmp: %s Pad: %s Fct %s" ),
771  }
772 
774  {
775  cmp_pad_msg = _( "Cmp:" );
776  cmp_pad_msg << " " << m_netAttributes.m_Cmpref;
777  }
778 
779  aList.emplace_back( net_msg, cmp_pad_msg );
780 }
781 
782 
784 {
785  if( m_Flashed )
786  return BITMAPS::pad;
787 
788  switch( m_Shape )
789  {
790  case GBR_SEGMENT:
791  case GBR_ARC:
792  case GBR_CIRCLE:
793  return BITMAPS::add_line;
794 
795  case GBR_SPOT_OVAL:
796  case GBR_SPOT_CIRCLE:
797  case GBR_SPOT_RECT:
798  case GBR_SPOT_POLY:
799  case GBR_SPOT_MACRO:
800  // should be handles by m_Flashed == true
801  return BITMAPS::pad;
802 
803  case GBR_POLYGON:
805  }
806 
807  return BITMAPS::info;
808 }
809 
810 
811 bool GERBER_DRAW_ITEM::HitTest( const wxPoint& aRefPos, int aAccuracy ) const
812 {
813  // In case the item has a very tiny width defined, allow it to be selected
814  const int MIN_HIT_TEST_RADIUS = Millimeter2iu( 0.01 );
815 
816  // calculate aRefPos in XY Gerber axis:
817  wxPoint ref_pos = GetXYPosition( aRefPos );
818 
819  SHAPE_POLY_SET poly;
820 
821  switch( m_Shape )
822  {
823  case GBR_POLYGON:
824  poly = m_Polygon;
825  return poly.Contains( VECTOR2I( ref_pos ), 0, aAccuracy );
826 
827  case GBR_SPOT_POLY:
828  poly = GetDcodeDescr()->m_Polygon;
829  poly.Move( VECTOR2I( m_Start ) );
830  return poly.Contains( VECTOR2I( ref_pos ), 0, aAccuracy );
831 
832  case GBR_SPOT_RECT:
833  return GetBoundingBox().Contains( aRefPos );
834 
835  case GBR_SPOT_OVAL:
836  {
837  EDA_RECT bbox = GetBoundingBox();
838 
839  if( ! bbox.Contains( aRefPos ) )
840  return false;
841 
842  // This is similar to a segment with thickness = min( m_Size.x, m_Size.y )
843  int radius = std::min( m_Size.x, m_Size.y )/2;
844  wxPoint start, end;
845 
846  if( m_Size.x > m_Size.y ) // Horizontal oval
847  {
848  int len = m_Size.y - m_Size.x;
849  start.x = -len/2;
850  end.x = len/2;
851  }
852  else // Vertical oval
853  {
854  int len = m_Size.x - m_Size.y;
855  start.y = -len/2;
856  end.y = len/2;
857  }
858 
859  start += bbox.Centre();
860  end += bbox.Centre();
861 
862  if( radius < MIN_HIT_TEST_RADIUS )
863  radius = MIN_HIT_TEST_RADIUS;
864 
865  return TestSegmentHit( aRefPos, start, end, radius );
866  }
867 
868  case GBR_ARC:
869  {
870  double radius = GetLineLength( m_Start, m_ArcCentre );
871  VECTOR2D test_radius = VECTOR2D( ref_pos ) - VECTOR2D( m_ArcCentre );
872 
873  int size = ( ( m_Size.x < MIN_HIT_TEST_RADIUS ) ? MIN_HIT_TEST_RADIUS : m_Size.x );
874 
875  // Are we close enough to the radius?
876  bool radius_hit = ( std::fabs( test_radius.EuclideanNorm() - radius) < size );
877 
878  if( radius_hit )
879  {
880  // Now check that we are within the arc angle
881 
882  VECTOR2D start = VECTOR2D( m_Start ) - VECTOR2D( m_ArcCentre );
884 
885  double start_angle = NormalizeAngleRadiansPos( start.Angle() );
886  double end_angle = NormalizeAngleRadiansPos( end.Angle() );
887 
888  if( m_Start == m_End )
889  {
890  start_angle = 0;
891  end_angle = 2 * M_PI;
892  }
893  else if( end_angle < start_angle )
894  {
895  end_angle += 2 * M_PI;
896  }
897 
898  double test_angle = NormalizeAngleRadiansPos( test_radius.Angle() );
899 
900  return ( test_angle > start_angle && test_angle < end_angle );
901  }
902 
903  return false;
904  }
905 
906  case GBR_SPOT_MACRO:
907  // Aperture macro polygons are already in absolute coordinates
908  auto p = GetDcodeDescr()->GetMacro()->GetApertureMacroShape( this, m_Start );
909  return p->Contains( VECTOR2I( aRefPos ), -1, aAccuracy );
910  }
911 
912  // TODO: a better analyze of the shape (perhaps create a D_CODE::HitTest for flashed items)
913  int radius = std::min( m_Size.x, m_Size.y ) >> 1;
914 
915  if( radius < MIN_HIT_TEST_RADIUS )
916  radius = MIN_HIT_TEST_RADIUS;
917 
918  if( m_Flashed )
919  return HitTestPoints( m_Start, ref_pos, radius );
920  else
921  return TestSegmentHit( ref_pos, m_Start, m_End, radius );
922 }
923 
924 
925 bool GERBER_DRAW_ITEM::HitTest( const EDA_RECT& aRefArea, bool aContained, int aAccuracy ) const
926 {
927  wxPoint pos = GetABPosition( m_Start );
928 
929  if( aRefArea.Contains( pos ) )
930  return true;
931 
932  pos = GetABPosition( m_End );
933 
934  if( aRefArea.Contains( pos ) )
935  return true;
936 
937  return false;
938 }
939 
940 
941 #if defined(DEBUG)
942 
943 void GERBER_DRAW_ITEM::Show( int nestLevel, std::ostream& os ) const
944 {
945  NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() <<
946 
947  " shape=\"" << m_Shape << '"' <<
948  " addr=\"" << std::hex << this << std::dec << '"' <<
949  " layer=\"" << GetLayer() << '"' <<
950  " size=\"" << m_Size << '"' <<
951  " flags=\"" << m_flags << '"' <<
952  " status=\"" << GetStatus() << '"' <<
953  "<start" << m_Start << "/>" <<
954  "<end" << m_End << "/>";
955 
956  os << "</" << GetClass().Lower().mb_str() << ">\n";
957 }
958 
959 #endif
960 
961 
962 void GERBER_DRAW_ITEM::ViewGetLayers( int aLayers[], int& aCount ) const
963 {
964  aCount = 2;
965 
966  aLayers[0] = GERBER_DRAW_LAYER( GetLayer() );
967  aLayers[1] = GERBER_DCODE_LAYER( aLayers[0] );
968 }
969 
970 
972 {
973  EDA_RECT bbox = GetBoundingBox();
974  return BOX2I( VECTOR2I( bbox.GetOrigin() ),
975  VECTOR2I( bbox.GetSize() ) );
976 }
977 
978 
979 double GERBER_DRAW_ITEM::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
980 {
981  // DCodes will be shown only if zoom is appropriate:
982  // Returns the level of detail of the item.
983  // A level of detail (LOD) is the minimal VIEW scale that
984  // is sufficient for an item to be shown on a given layer.
985  if( IsDCodeLayer( aLayer ) )
986  {
987  int size = 0;
988 
989  switch( m_Shape )
990  {
991  case GBR_SPOT_MACRO:
993  break;
994 
995  case GBR_ARC:
996  size = GetLineLength( m_Start, m_ArcCentre );
997  break;
998 
999  default:
1000  size = m_Size.x;
1001  }
1002 
1003  // the level of details is chosen experimentally, to show
1004  // only a readable text:
1005  double level = (double)Millimeter2iu( 3 );
1006  return level / ( size + 1 );
1007  }
1008 
1009  // Other layers are shown without any conditions
1010  return 0.0;
1011 }
1012 
1013 
1015  const KICAD_T scanTypes[] )
1016 {
1017  KICAD_T stype = *scanTypes;
1018 
1019  // If caller wants to inspect my type
1020  if( stype == Type() )
1021  {
1022  if( SEARCH_RESULT::QUIT == inspector( this, testData ) )
1023  return SEARCH_RESULT::QUIT;
1024  }
1025 
1026  return SEARCH_RESULT::CONTINUE;
1027 }
1028 
1029 
1031 {
1032  wxString layerName;
1033 
1035 
1036  return wxString::Format( _( "%s (D%d) on layer %d: %s" ),
1037  ShowGBRShape(),
1038  m_DCode,
1039  GetLayer() + 1,
1040  layerName );
1041 }
void SetLayerParameters()
Initialize parameters from Image and Layer parameters found in the gerber file: m_UnitsMetric,...
#define TEXT_ANGLE_HORIZ
Frequent text rotations, used with {Set,Get}TextAngle(), in 0.1 degrees for now, hoping to migrate to...
Definition: eda_text.h:50
bool m_DisplayPolygonsFill
Option to draw polygons (filled/sketch)
BOX2< VECTOR2I > BOX2I
Definition: box2.h:506
#define GERBER_DCODE_LAYER(x)
Definition: layer_ids.h:398
D_CODE * GetDcodeDescr() const
Return the GetDcodeDescr of this object, or NULL.
bool IsDCodeLayer(int aLayer)
Definition: layer_ids.h:968
wxString name
The name of the aperture macro.
Definition: am_primitive.h:231
int OutlineCount() const
Return the number of vertices in a given outline/hole.
wxString GetClass() const override
double GetLineLength(const wxPoint &aPointA, const wxPoint &aPointB)
Return the length of a line segment defined by aPointA and aPointB.
Definition: trigo.h:222
void MoveAB(const wxPoint &aMoveVector)
Move this object.
print info associated to a component (TO.C attribute)
coord_type GetX() const
Definition: box2.h:173
wxSize m_Size
Horizontal and vertical dimensions.
Definition: dcode.h:188
bool HasNegativeItems()
Optimize screen refresh (when no items are in background color refresh can be faster).
APERTURE_T m_Shape
shape ( Line, rectangle, circle , oval .. )
Definition: dcode.h:189
int color
Definition: DXF_plotter.cpp:57
virtual const BOX2I ViewBBox() const override
int GetLayer() const
Return the layer this item is on.
D_CODE * GetDCODE(int aDCODE) const
Return a pointer to the D_CODE within this GERBER for the given aDCODE.
Hold the image data and parameters for one gerber file and layer parameters.
int GetWidth() const
Definition: eda_rect.h:109
COLOR4D GetPositiveDrawColor() const
double RAD2DECIDEG(double rad)
Definition: trigo.h:234
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:121
void Print(wxDC *aDC, const wxPoint &aOffset, GBR_DISPLAY_OPTIONS *aOptions)
const EDA_RECT GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
bool HitTest(const wxPoint &aRefPos, int aAccuracy=0) const override
Test if the given wxPoint is within the bounds of this object.
EDA_ITEM_FLAGS GetStatus() const
Definition: eda_item.h:150
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Return true if a given subpolygon contains the point aP.
void SetNetAttributes(const GBR_NETLIST_METADATA &aNetAttributes)
EDA_ITEM_FLAGS m_flags
Definition: eda_item.h:481
Information which can be added in a gerber file as attribute of an object.
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:229
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
double NormalizeAngleRadiansPos(double Angle)
Definition: trigo.h:315
The base class for create windows for drawing purpose.
VECTOR2< int > VECTOR2I
Definition: vector2d.h:623
int PointCount() const
Return the number of points (vertices) in this line chain.
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
Return the text to display to be used in the selection clarification context menu when multiple items...
void NORMALIZE_ANGLE_90(T &Angle)
Definition: trigo.h:380
bool Contains(const wxPoint &aPoint) const
Definition: eda_rect.cpp:57
Definition: dcode.h:51
const INSPECTOR_FUNC & INSPECTOR
Definition: eda_item.h:94
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:77
void Mirror(bool aX=true, bool aY=false, const VECTOR2I &aRef={ 0, 0 })
Mirror the line points about y or x (or both)
bool m_DisplayLinesFill
Option to draw line items (filled/sketch)
GBR_DATA_FIELD m_PadPinFunction
for a pad: the pin function (defined in schematic)
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
#define LAST_DCODE
Definition: dcode.h:71
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
const wxPoint GetEnd() const
Definition: eda_rect.h:103
COLOR4D m_NegativeDrawColor
The color used to draw negative objects, usually the background color, but not always,...
wxPoint GetABPosition(const wxPoint &aXYPosition) const
Return the image position of aPosition for this object.
VECTOR2< double > VECTOR2D
Definition: vector2d.h:622
void Move(const VECTOR2I &aVector) override
void SetHeight(int val)
Definition: eda_rect.h:176
EDA_RECT GetBoundingBox() const
Return the bounding box of the shape.
Definition: am_primitive.h:226
#define FIRST_DCODE
Definition: dcode.h:70
Represent a set of closed polygons.
SHAPE_LINE_CHAIN & Outline(int aIndex)
const wxPoint GetOrigin() const
Definition: eda_rect.h:101
void SetEnd(int x, int y)
Definition: eda_rect.h:182
coord_type GetWidth() const
Definition: box2.h:180
GBR_DATA_FIELD m_Padname
for a flashed pad: the pad name ((TO.P attribute)
bool m_DisplayFlashedItemsFill
Option to draw flashed items (filled/sketch)
bool TestSegmentHit(const wxPoint &aRefPoint, const wxPoint &aStart, const wxPoint &aEnd, int aDist)
Test if aRefPoint is with aDistance on the line defined by aStart and aEnd.
Definition: trigo.cpp:129
void GRCircle(EDA_RECT *ClipBox, wxDC *DC, int xc, int yc, int r, int width, const COLOR4D &Color)
Definition: gr_basic.cpp:551
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)
Return the best size and orientation to display the D_Code on screen.
wxString m_Netname
for items associated to a net: the netname
#define _(s)
double Angle() const
Compute the angle of the vector.
Definition: vector2d.h:307
void GRFilledSegment(EDA_RECT *aClipBox, wxDC *aDC, const wxPoint &aStart, const wxPoint &aEnd, int aWidth, const COLOR4D &aColor)
Definition: gr_basic.cpp:377
void SetWidth(int val)
Definition: eda_rect.h:170
int NewOutline()
Creates a new hole in a given outline.
void GRClosedPoly(EDA_RECT *ClipBox, wxDC *DC, int n, const wxPoint *Points, bool Fill, const COLOR4D &Color, const COLOR4D &BgColor)
Draw a closed polyline and fill it if Fill, in object space.
Definition: gr_basic.cpp:507
void ConvertSegmentToPolygon()
Convert a line to an equivalent polygon.
#define GERBER_DRAW_LAYER(x)
Definition: layer_ids.h:396
wxString UnescapeString(const wxString &aSource)
std::map< wxString, int > m_NetnamesList
wxString m_AperFunction
the aperture attribute (created by a TA.AperFunction command).
Definition: dcode.h:200
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
virtual wxString GetSelectMenuText(EDA_UNITS aUnits) const override
Return a pointer to an image to be used in menus.
void GRArc1(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int xc, int yc, const COLOR4D &Color)
Definition: gr_basic.cpp:594
EDA_UNITS
Definition: eda_units.h:38
void Normalize()
Ensures that the height ant width are positive.
Definition: eda_rect.cpp:35
coord_type GetY() const
Definition: box2.h:174
void SetSize(const wxSize &size)
Definition: eda_rect.h:134
A gerber DCODE (also called Aperture) definition.
Definition: dcode.h:80
const char * name
Definition: DXF_plotter.cpp:56
BITMAPS
A list of all bitmap identifiers.
Definition: bitmaps_list.h:32
Represent a polyline (an zero-thickness chain of connected line segments).
bool HitTestPoints(const wxPoint &pointA, const wxPoint &pointB, double threshold)
Test, if two points are near each other.
Definition: trigo.h:184
Handle the component boundary box.
Definition: eda_rect.h:42
double DECIDEG2RAD(double deg)
Definition: trigo.h:233
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
SHAPE_POLY_SET m_Polygon
Definition: dcode.h:203
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:100
coord_type GetHeight() const
Definition: box2.h:181
wxPoint Centre() const
Definition: eda_rect.h:55
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
Definition: shape_arc.cpp:380
APERTURE_MACRO * GetMacro() const
Definition: dcode.h:125
print info associated to a flashed pad (TO.P attribute)
constexpr int delta
void PrintGerberPoly(wxDC *aDC, const COLOR4D &aColor, const wxPoint &aOffset, bool aFilledShape)
Print the polygon stored in m_PolyCorners.
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition: vector2d.h:293
wxPoint GetXYPosition(const wxPoint &aABPosition) const
Return the image position of aPosition for this object.
void ConvertShapeToPolygon()
Convert a shape to an equivalent polygon.
Definition: dcode.cpp:298
void DrawFlashedShape(GERBER_DRAW_ITEM *aParent, EDA_RECT *aClipBox, wxDC *aDC, const COLOR4D &aColor, const wxPoint &aShapePos, bool aFilledShape)
Draw the dcode shape for flashed items.
Definition: dcode.cpp:148
const Vec & GetOrigin() const
Definition: box2.h:176
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:68
void MoveXY(const wxPoint &aMoveVector)
Move this object.
SEARCH_RESULT
Definition: eda_item.h:41
Message panel definition file.
static constexpr int Millimeter2iu(double mm)
print info associated to a net (TO.N attribute)
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
int GetShapeDim(GERBER_DRAW_ITEM *aParent)
Calculate a value that can be used to evaluate the size of text when displaying the D-Code of an item...
Definition: dcode.cpp:116
GERBER_FILE_IMAGE * m_GerberImageFile
std::map< wxString, int > m_ComponentsList
const wxString GetDisplayName(int aIdx, bool aNameOnly=false, bool aFullName=false)
Get the display name for the layer at aIdx.
const wxString & GetValue() const
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Inflate the rectangle horizontally by dx and vertically by dy.
Definition: eda_rect.cpp:364
GERBER_LAYER & GetLayerParams()
const wxSize GetSize() const
Definition: eda_rect.h:91
int m_ImageRotation
Local rotation in degrees added to m_ImageRotation.
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:113
int m_NetAttribType
the type of net info (used to define the gerber string to create)
wxString ShowGBRShape() const
double ViewGetLOD(int aLayer, KIGFX::VIEW *aView) const override
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:103
SHAPE_POLY_SET * GetApertureMacroShape(const GERBER_DRAW_ITEM *aParent, const wxPoint &aShapePos)
Calculate the primitive shape for flashed items.
wxRealPoint m_drawScale
void GRCSegm(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, int aPenSize, const COLOR4D &Color)
Definition: gr_basic.cpp:271