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-2019 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 #include <geometry/shape_arc.h>
38 #include <math/util.h> // for KiROUND
39 
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  // returns 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 
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  return abPos;
178 }
179 
180 
182 {
183  // do the inverse transform made by GetABPosition
184  wxPoint xyPos = aABPosition;
185 
186  if( m_mirrorA )
187  xyPos.x = -xyPos.x;
188 
189  if( !m_mirrorB )
190  xyPos.y = -xyPos.y;
191 
192  double rotation = m_lyrRotation * 10 + m_GerberImageFile->m_ImageRotation * 10;
193 
194  if( rotation )
195  RotatePoint( &xyPos, rotation );
196 
197  xyPos.x = KiROUND( xyPos.x / m_drawScale.x );
198  xyPos.y = KiROUND( xyPos.y / m_drawScale.y );
200 
201  if( m_swapAxis )
202  std::swap( xyPos.x, xyPos.y );
203 
204  return xyPos - m_GerberImageFile->m_ImageJustifyOffset;
205 }
206 
207 
209 {
211  m_swapAxis = m_GerberImageFile->m_SwapAxis; // false if A = X, B = Y;
212 
213  // true if A =Y, B = Y
214  m_mirrorA = m_GerberImageFile->m_MirrorA; // true: mirror / axe A
215  m_mirrorB = m_GerberImageFile->m_MirrorB; // true: mirror / axe B
216  m_drawScale = m_GerberImageFile->m_Scale; // A and B scaling factor
217  m_layerOffset = m_GerberImageFile->m_Offset; // Offset from OF command
218 
219  // Rotation from RO command:
222 }
223 
224 
226 {
227  switch( m_Shape )
228  {
229  case GBR_SEGMENT:
230  return _( "Line" );
231 
232  case GBR_ARC:
233  return _( "Arc" );
234 
235  case GBR_CIRCLE:
236  return _( "Circle" );
237 
238  case GBR_SPOT_OVAL:
239  return wxT( "spot_oval" );
240 
241  case GBR_SPOT_CIRCLE:
242  return wxT( "spot_circle" );
243 
244  case GBR_SPOT_RECT:
245  return wxT( "spot_rect" );
246 
247  case GBR_SPOT_POLY:
248  return wxT( "spot_poly" );
249 
250  case GBR_POLYGON:
251  return wxT( "polygon" );
252 
253  case GBR_SPOT_MACRO:
254  {
255  wxString name = wxT( "apt_macro" );
256  D_CODE* dcode = GetDcodeDescr();
257 
258  if( dcode && dcode->GetMacro() )
259  name << wxT(" ") << dcode->GetMacro()->name;
260 
261  return name;
262  }
263 
264  default:
265  return wxT( "??" );
266  }
267 }
268 
269 
271 {
272  if( (m_DCode < FIRST_DCODE) || (m_DCode > LAST_DCODE) )
273  return NULL;
274 
275  if( m_GerberImageFile == NULL )
276  return NULL;
277 
279 }
280 
281 
283 {
284  // return a rectangle which is (pos,dim) in nature. therefore the +1
285  EDA_RECT bbox( m_Start, wxSize( 1, 1 ) );
286  D_CODE* code = GetDcodeDescr();
287 
288  // TODO(JE) GERBER_DRAW_ITEM maybe should actually be a number of subclasses.
289  // Until/unless that is changed, we need to do different things depending on
290  // what is actually being represented by this GERBER_DRAW_ITEM.
291 
292  switch( m_Shape )
293  {
294  case GBR_POLYGON:
295  {
296  auto bb = m_Polygon.BBox();
297  bbox.Inflate( bb.GetWidth() / 2, bb.GetHeight() / 2 );
298  bbox.SetOrigin( bb.GetOrigin().x, bb.GetOrigin().y );
299  break;
300  }
301 
302  case GBR_CIRCLE:
303  {
304  double radius = GetLineLength( m_Start, m_End );
305  bbox.Inflate( radius, radius );
306  break;
307  }
308 
309  case GBR_ARC:
310  {
311  double arc_angle =
312  atan2( double( m_End.y - m_ArcCentre.y ), double( m_End.x - m_ArcCentre.x ) )
313  - atan2( double( m_Start.y - m_ArcCentre.y ), double( m_Start.x - m_ArcCentre.x ) );
314 
315  arc_angle *= 180.0 / M_PI;
316 
317  if( arc_angle < 0.0 )
318  arc_angle += 360.0;
319 
320  if( m_End == m_Start ) // Arc with the end point = start point is expected to be a circle
321  arc_angle = 360.0;
322 
323  SHAPE_ARC arc( m_ArcCentre, m_Start, arc_angle );
324  BOX2I arc_bbox = arc.BBox( m_Size.x / 2 ); // m_Size.x is the line thickness
325  bbox.SetOrigin( arc_bbox.GetX(), arc_bbox.GetY() );
326  bbox.SetWidth( arc_bbox.GetWidth() );
327  bbox.SetHeight( arc_bbox.GetHeight() );
328  break;
329  }
330 
331  case GBR_SPOT_CIRCLE:
332  {
333  if( code )
334  {
335  int radius = code->m_Size.x >> 1;
336  bbox.Inflate( radius, radius );
337  }
338  break;
339  }
340 
341  case GBR_SPOT_RECT:
342  {
343  if( code )
344  bbox.Inflate( code->m_Size.x / 2, code->m_Size.y / 2 );
345  break;
346  }
347 
348  case GBR_SPOT_OVAL:
349  {
350  if( code )
351  bbox.Inflate( code->m_Size.x /2, code->m_Size.y / 2 );
352  break;
353  }
354 
355  case GBR_SPOT_POLY:
356  {
357  if( code )
358  {
359  if( code->m_Polygon.OutlineCount() == 0 )
360  code->ConvertShapeToPolygon();
361 
362  bbox.Inflate( code->m_Polygon.BBox().GetWidth() / 2,
363  code->m_Polygon.BBox().GetHeight() / 2 );
364  }
365  break;
366  }
367  case GBR_SPOT_MACRO:
368  {
369  if( code )
370  {
371  // Update the shape drawings and the bounding box coordiantes:
372  code->GetMacro()->GetApertureMacroShape( this, m_Start );
373  // now the bounding box is valid:
374  bbox = code->GetMacro()->GetBoundingBox();
375  }
376  break;
377  }
378 
379  case GBR_SEGMENT:
380  {
381  if( code && code->m_Shape == APT_RECT )
382  {
383  if( m_Polygon.OutlineCount() > 0 )
384  {
385  auto bb = m_Polygon.BBox();
386  bbox.Inflate( bb.GetWidth() / 2, bb.GetHeight() / 2 );
387  bbox.SetOrigin( bb.GetOrigin().x, bb.GetOrigin().y );
388  }
389  }
390  else
391  {
392  int radius = ( m_Size.x + 1 ) / 2;
393 
394  int ymax = std::max( m_Start.y, m_End.y ) + radius;
395  int xmax = std::max( m_Start.x, m_End.x ) + radius;
396 
397  int ymin = std::min( m_Start.y, m_End.y ) - radius;
398  int xmin = std::min( m_Start.x, m_End.x ) - radius;
399 
400  bbox = EDA_RECT( wxPoint( xmin, ymin ), wxSize( xmax - xmin + 1, ymax - ymin + 1 ) );
401  }
402 
403  break;
404  }
405  default:
406  wxASSERT_MSG( false, wxT( "GERBER_DRAW_ITEM shape is unknown!" ) );
407  break;
408  }
409 
410  // calculate the corners coordinates in current gerber axis orientations
411  wxPoint org = GetABPosition( bbox.GetOrigin() );
412  wxPoint end = GetABPosition( bbox.GetEnd() );
413 
414  // Set the corners position:
415  bbox.SetOrigin( org );
416  bbox.SetEnd( end );
417  bbox.Normalize();
418 
419  return bbox;
420 }
421 
422 
423 void GERBER_DRAW_ITEM::MoveAB( const wxPoint& aMoveVector )
424 {
425  wxPoint xymove = GetXYPosition( aMoveVector );
426 
427  m_Start += xymove;
428  m_End += xymove;
429  m_ArcCentre += xymove;
430 
431  m_Polygon.Move( VECTOR2I( xymove ) );
432 }
433 
434 
435 void GERBER_DRAW_ITEM::MoveXY( const wxPoint& aMoveVector )
436 {
437  m_Start += aMoveVector;
438  m_End += aMoveVector;
439  m_ArcCentre += aMoveVector;
440 
441  m_Polygon.Move( VECTOR2I( aMoveVector ) );
442 }
443 
444 
446 {
448 
449  // if isClear is true, this item has negative shape
450  return isClear;
451 }
452 
453 
454 void GERBER_DRAW_ITEM::Print( wxDC* aDC, const wxPoint& aOffset, GBR_DISPLAY_OPTIONS* aOptions )
455 {
456  // used when a D_CODE is not found. default D_CODE to draw a flashed item
457  static D_CODE dummyD_CODE( 0 );
458  bool isFilled;
459  int radius;
460  int halfPenWidth;
461  static bool show_err;
462  D_CODE* d_codeDescr = GetDcodeDescr();
463 
464  if( d_codeDescr == NULL )
465  d_codeDescr = &dummyD_CODE;
466 
468 
469  /* isDark is true if flash is positive and should use a drawing
470  * color other than the background color, else use the background color
471  * when drawing so that an erasure happens.
472  */
474 
475  if( !isDark )
476  {
477  // draw in background color ("negative" color)
478  color = aOptions->m_NegativeDrawColor;
479  }
480 
481  isFilled = aOptions->m_DisplayLinesFill;
482 
483  switch( m_Shape )
484  {
485  case GBR_POLYGON:
486  isFilled = aOptions->m_DisplayPolygonsFill;
487 
488  if( !isDark )
489  isFilled = true;
490 
491  PrintGerberPoly( aDC, color, aOffset, isFilled );
492  break;
493 
494  case GBR_CIRCLE:
495  radius = KiROUND( GetLineLength( m_Start, m_End ) );
496 
497  halfPenWidth = m_Size.x >> 1;
498 
499  if( !isFilled )
500  {
501  // draw the border of the pen's path using two circles, each as narrow as possible
502  GRCircle( nullptr, aDC, GetABPosition( m_Start ), radius - halfPenWidth, 0, color );
503  GRCircle( nullptr, aDC, GetABPosition( m_Start ), radius + halfPenWidth, 0, color );
504  }
505  else // Filled mode
506  {
507  GRCircle( nullptr, aDC, GetABPosition( m_Start ), radius, m_Size.x, color );
508  }
509  break;
510 
511  case GBR_ARC:
512  // Currently, arcs plotted with a rectangular aperture are not supported.
513  // a round pen only is expected.
514  if( !isFilled )
515  {
516  GRArc1( nullptr, aDC, GetABPosition( m_Start ), GetABPosition( m_End ),
518  }
519  else
520  {
521  GRArc1( nullptr, aDC, GetABPosition( m_Start ), GetABPosition( m_End ),
523  }
524 
525  break;
526 
527  case GBR_SPOT_CIRCLE:
528  case GBR_SPOT_RECT:
529  case GBR_SPOT_OVAL:
530  case GBR_SPOT_POLY:
531  case GBR_SPOT_MACRO:
532  isFilled = aOptions->m_DisplayFlashedItemsFill;
533  d_codeDescr->DrawFlashedShape( this, nullptr, aDC, color, m_Start, isFilled );
534  break;
535 
536  case GBR_SEGMENT:
537  /* Plot a line from m_Start to m_End.
538  * Usually, a round pen is used, but some gerber files use a rectangular pen
539  * In fact, any aperture can be used to plot a line.
540  * currently: only a square pen is handled (I believe using a polygon gives a strange plot).
541  */
542  if( d_codeDescr->m_Shape == APT_RECT )
543  {
544  if( m_Polygon.OutlineCount() == 0 )
546 
547  PrintGerberPoly( aDC, color, aOffset, isFilled );
548  }
549  else
550  {
551  if( !isFilled )
552  {
553  GRCSegm( nullptr, aDC, GetABPosition( m_Start ), GetABPosition( m_End ),
554  m_Size.x, color );
555  }
556  else
557  {
559  m_Size.x, color );
560  }
561  }
562 
563  break;
564 
565  default:
566  if( !show_err )
567  {
568  wxMessageBox( wxT( "Trace_Segment() type error" ) );
569  show_err = true;
570  }
571 
572  break;
573  }
574 }
575 
576 
578 {
581 
582  wxPoint start = m_Start;
583  wxPoint end = m_End;
584 
585  // make calculations more easy if ensure start.x < end.x
586  // (only 2 quadrants to consider)
587  if( start.x > end.x )
588  std::swap( start, end );
589 
590  // calculate values relative to start point:
591  wxPoint delta = end - start;
592 
593  // calculate corners for the first quadrant only (delta.x and delta.y > 0 )
594  // currently, delta.x already is > 0.
595  // make delta.y > 0
596  bool change = delta.y < 0;
597 
598  if( change )
599  delta.y = -delta.y;
600 
601  // Now create the full polygon.
602  // Due to previous changes, the shape is always something like
603  // 3 4
604  // 2 5
605  // 1 6
606  wxPoint corner;
607  corner.x -= m_Size.x/2;
608  corner.y -= m_Size.y/2;
609  wxPoint close = corner;
610  m_Polygon.Append( VECTOR2I( corner ) ); // Lower left corner, start point (1)
611  corner.y += m_Size.y;
612  m_Polygon.Append( VECTOR2I( corner ) ); // upper left corner, start point (2)
613 
614  if( delta.x || delta.y)
615  {
616  corner += delta;
617  m_Polygon.Append( VECTOR2I( corner ) ); // upper left corner, end point (3)
618  }
619 
620  corner.x += m_Size.x;
621  m_Polygon.Append( VECTOR2I( corner ) ); // upper right corner, end point (4)
622  corner.y -= m_Size.y;
623  m_Polygon.Append( VECTOR2I( corner ) ); // lower right corner, end point (5)
624 
625  if( delta.x || delta.y )
626  {
627  corner -= delta;
628  m_Polygon.Append( VECTOR2I( corner ) ); // lower left corner, start point (6)
629  }
630 
631  m_Polygon.Append( VECTOR2I( close ) ); // close the shape
632 
633  // Create final polygon:
634  if( change )
635  m_Polygon.Mirror( false, true );
636 
637  m_Polygon.Move( VECTOR2I( start ) );
638 }
639 
640 
641 void GERBER_DRAW_ITEM::PrintGerberPoly( wxDC* aDC, COLOR4D aColor, const wxPoint& aOffset,
642  bool aFilledShape )
643 {
644  std::vector<wxPoint> points;
645  SHAPE_LINE_CHAIN& poly = m_Polygon.Outline( 0 );
646  int pointCount = poly.PointCount() - 1;
647 
648  points.reserve( pointCount );
649 
650  for( int ii = 0; ii < pointCount; ii++ )
651  {
652  wxPoint p( poly.CPoint( ii ).x, poly.CPoint( ii ).y );
653  points[ii] = p + aOffset;
654  points[ii] = GetABPosition( points[ii] );
655  }
656 
657  GRClosedPoly( nullptr, aDC, pointCount, &points[0], aFilledShape, aColor, aColor );
658 }
659 
660 
661 void GERBER_DRAW_ITEM::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
662 {
663  wxString msg;
664  wxString text;
665 
666  msg = ShowGBRShape();
667  aList.emplace_back( _( "Type" ), msg, DARKCYAN );
668 
669  // Display D_Code value with its attributes for items using a DCode:
670  if( m_Shape == GBR_POLYGON ) // Has no DCode, but can have an attribute
671  {
672  msg = _( "Attribute" );
673 
674  if( m_AperFunction.IsEmpty() )
675  text = _( "No attribute" );
676  else
677  text = m_AperFunction;
678  }
679  else
680  {
681  msg.Printf( _( "D Code %d" ), m_DCode );
682  D_CODE* apertDescr = GetDcodeDescr();
683 
684  if( !apertDescr || apertDescr->m_AperFunction.IsEmpty() )
685  text = _( "No attribute" );
686  else
687  text = apertDescr->m_AperFunction;
688  }
689 
690  aList.emplace_back( msg, text, RED );
691 
692  // Display graphic layer name
694  aList.emplace_back( _( "Graphic Layer" ), msg, DARKGREEN );
695 
696  // Display item rotation
697  // The full rotation is Image rotation + m_lyrRotation
698  // but m_lyrRotation is specific to this object
699  // so we display only this parameter
700  msg.Printf( wxT( "%f" ), m_lyrRotation );
701  aList.emplace_back( _( "Rotation" ), msg, BLUE );
702 
703  // Display item polarity (item specific)
704  msg = m_LayerNegative ? _("Clear") : _("Dark");
705  aList.emplace_back( _( "Polarity" ), msg, BLUE );
706 
707  // Display mirroring (item specific)
708  msg.Printf( wxT( "A:%s B:%s" ),
709  m_mirrorA ? _("Yes") : _("No"),
710  m_mirrorB ? _("Yes") : _("No"));
711  aList.emplace_back( _( "Mirror" ), msg, DARKRED );
712 
713  // Display AB axis swap (item specific)
714  msg = m_swapAxis ? wxT( "A=Y B=X" ) : wxT( "A=X B=Y" );
715  aList.emplace_back( _( "AB axis" ), msg, DARKRED );
716 
717  // Display net info, if exists
719  return;
720 
721  // Build full net info:
722  wxString net_msg;
723  wxString cmp_pad_msg;
724 
726  {
727  net_msg = _( "Net:" );
728  net_msg << " ";
729 
730  if( m_netAttributes.m_Netname.IsEmpty() )
731  net_msg << "<no net>";
732  else
734  }
735 
737  {
739  cmp_pad_msg.Printf( _( "Cmp: %s Pad: %s" ),
742  else
743  cmp_pad_msg.Printf( _( "Cmp: %s Pad: %s Fct %s" ),
747  }
748 
750  {
751  cmp_pad_msg = _( "Cmp:" );
752  cmp_pad_msg << " " << m_netAttributes.m_Cmpref;
753  }
754 
755  aList.emplace_back( net_msg, cmp_pad_msg, DARKCYAN );
756 }
757 
758 
760 {
761  if( m_Flashed )
762  return pad_xpm;
763 
764  switch( m_Shape )
765  {
766  case GBR_SEGMENT:
767  case GBR_ARC:
768  case GBR_CIRCLE:
769  return add_line_xpm;
770 
771  case GBR_SPOT_OVAL:
772  case GBR_SPOT_CIRCLE:
773  case GBR_SPOT_RECT:
774  case GBR_SPOT_POLY:
775  case GBR_SPOT_MACRO:
776  // should be handles by m_Flashed == true
777  return pad_xpm;
778 
779  case GBR_POLYGON:
781  }
782 
783  return info_xpm;
784 }
785 
786 
787 bool GERBER_DRAW_ITEM::HitTest( const wxPoint& aRefPos, int aAccuracy ) const
788 {
789  // In case the item has a very tiny width defined, allow it to be selected
790  const int MIN_HIT_TEST_RADIUS = Millimeter2iu( 0.01 );
791 
792  // calculate aRefPos in XY gerber axis:
793  wxPoint ref_pos = GetXYPosition( aRefPos );
794 
795  SHAPE_POLY_SET poly;
796 
797  switch( m_Shape )
798  {
799  case GBR_POLYGON:
800  poly = m_Polygon;
801  return poly.Contains( VECTOR2I( ref_pos ), 0, aAccuracy );
802 
803  case GBR_SPOT_POLY:
804  poly = GetDcodeDescr()->m_Polygon;
805  poly.Move( VECTOR2I( m_Start ) );
806  return poly.Contains( VECTOR2I( ref_pos ), 0, aAccuracy );
807 
808  case GBR_SPOT_RECT:
809  return GetBoundingBox().Contains( aRefPos );
810 
811  case GBR_SPOT_OVAL:
812  {
813  EDA_RECT bbox = GetBoundingBox();
814 
815  if( ! bbox.Contains( aRefPos ) )
816  return false;
817 
818  // This is similar to a segment with thickness = min( m_Size.x, m_Size.y )
819  int radius = std::min( m_Size.x, m_Size.y )/2;
820  wxPoint start, end;
821  if( m_Size.x > m_Size.y ) // Horizontal oval
822  {
823  int len = m_Size.y - m_Size.x;
824  start.x = -len/2;
825  end.x = len/2;
826  }
827  else // Vertical oval
828  {
829  int len = m_Size.x - m_Size.y;
830  start.y = -len/2;
831  end.y = len/2;
832  }
833  start += bbox.Centre();
834  end += bbox.Centre();
835 
836  if( radius < MIN_HIT_TEST_RADIUS )
837  radius = MIN_HIT_TEST_RADIUS;
838 
839  return TestSegmentHit( aRefPos, start, end, radius );
840  }
841 
842  case GBR_ARC:
843  {
844  double radius = GetLineLength( m_Start, m_ArcCentre );
845  VECTOR2D test_radius = VECTOR2D( ref_pos ) - VECTOR2D( m_ArcCentre );
846 
847  int size = ( ( m_Size.x < MIN_HIT_TEST_RADIUS ) ? MIN_HIT_TEST_RADIUS
848  : m_Size.x );
849 
850  // Are we close enough to the radius?
851  bool radius_hit = ( std::fabs( test_radius.EuclideanNorm() - radius) < size );
852 
853  if( radius_hit )
854  {
855  // Now check that we are within the arc angle
856 
857  VECTOR2D start = VECTOR2D( m_Start ) - VECTOR2D( m_ArcCentre );
859 
860  double start_angle = NormalizeAngleRadiansPos( start.Angle() );
861  double end_angle = NormalizeAngleRadiansPos( end.Angle() );
862 
863  if( m_Start == m_End )
864  {
865  start_angle = 0;
866  end_angle = 2 * M_PI;
867  }
868  else if( end_angle < start_angle )
869  {
870  end_angle += 2 * M_PI;
871  }
872 
873  double test_angle = NormalizeAngleRadiansPos( test_radius.Angle() );
874 
875  return ( test_angle > start_angle && test_angle < end_angle );
876  }
877 
878  return false;
879  }
880 
881  case GBR_SPOT_MACRO:
882  // Aperture macro polygons are already in absolute coordinates
883  auto p = GetDcodeDescr()->GetMacro()->GetApertureMacroShape( this, m_Start );
884  return p->Contains( VECTOR2I( aRefPos ), -1, aAccuracy );
885  }
886 
887  // TODO: a better analyze of the shape (perhaps create a D_CODE::HitTest for flashed items)
888  int radius = std::min( m_Size.x, m_Size.y ) >> 1;
889 
890  if( radius < MIN_HIT_TEST_RADIUS )
891  radius = MIN_HIT_TEST_RADIUS;
892 
893  if( m_Flashed )
894  return HitTestPoints( m_Start, ref_pos, radius );
895  else
896  return TestSegmentHit( ref_pos, m_Start, m_End, radius );
897 }
898 
899 
900 bool GERBER_DRAW_ITEM::HitTest( const EDA_RECT& aRefArea, bool aContained, int aAccuracy ) const
901 {
902  wxPoint pos = GetABPosition( m_Start );
903 
904  if( aRefArea.Contains( pos ) )
905  return true;
906 
907  pos = GetABPosition( m_End );
908 
909  if( aRefArea.Contains( pos ) )
910  return true;
911 
912  return false;
913 }
914 
915 
916 #if defined(DEBUG)
917 
918 void GERBER_DRAW_ITEM::Show( int nestLevel, std::ostream& os ) const
919 {
920  NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() <<
921 
922  " shape=\"" << m_Shape << '"' <<
923  " addr=\"" << std::hex << this << std::dec << '"' <<
924  " layer=\"" << GetLayer() << '"' <<
925  " size=\"" << m_Size << '"' <<
926  " flags=\"" << m_Flags << '"' <<
927  " status=\"" << GetStatus() << '"' <<
928  "<start" << m_Start << "/>" <<
929  "<end" << m_End << "/>";
930 
931  os << "</" << GetClass().Lower().mb_str() << ">\n";
932 }
933 
934 #endif
935 
936 
937 void GERBER_DRAW_ITEM::ViewGetLayers( int aLayers[], int& aCount ) const
938 {
939  aCount = 2;
940 
941  aLayers[0] = GERBER_DRAW_LAYER( GetLayer() );
942  aLayers[1] = GERBER_DCODE_LAYER( aLayers[0] );
943 }
944 
945 
947 {
948  EDA_RECT bbox = GetBoundingBox();
949  return BOX2I( VECTOR2I( bbox.GetOrigin() ),
950  VECTOR2I( bbox.GetSize() ) );
951 }
952 
953 
954 unsigned int GERBER_DRAW_ITEM::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
955 {
956  // DCodes will be shown only if zoom is appropriate:
957  // Returns the level of detail of the item.
958  // A level of detail (LOD) is the minimal VIEW scale that
959  // is sufficient for an item to be shown on a given layer.
960  if( IsDCodeLayer( aLayer ) )
961  {
962  int size = 0;
963 
964  switch( m_Shape )
965  {
966  case GBR_SPOT_MACRO:
968  break;
969 
970  case GBR_ARC:
971  size = GetLineLength( m_Start, m_ArcCentre );
972  break;
973 
974  default:
975  size = m_Size.x;
976  }
977 
978  // the level of details is chosen experimentally, to show
979  // only a readable text:
980  const int level = Millimeter2iu( 4 );
981  return ( level / ( size + 1 ) );
982  }
983 
984  // Other layers are shown without any conditions
985  return 0;
986 }
987 
988 
989 SEARCH_RESULT GERBER_DRAW_ITEM::Visit( INSPECTOR inspector, void* testData, const KICAD_T scanTypes[] )
990 {
991  KICAD_T stype = *scanTypes;
992 
993  // If caller wants to inspect my type
994  if( stype == Type() )
995  {
996  if( SEARCH_RESULT::QUIT == inspector( this, testData ) )
997  return SEARCH_RESULT::QUIT;
998  }
999 
1000  return SEARCH_RESULT::CONTINUE;
1001 }
1002 
1003 
1005 {
1006  wxString layerName;
1007 
1009 
1010  return wxString::Format( _( "%s (D%d) on layer %d: %s" ),
1011  ShowGBRShape(),
1012  m_DCode,
1013  GetLayer() + 1,
1014  layerName );
1015 }
#define TEXT_ANGLE_HORIZ
EDA_UNITS
Definition: common.h:198
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:229
BOX2< VECTOR2I > BOX2I
Definition: box2.h:521
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)
Return the length of a line segment defined by aPointA and aPointB.
Definition: trigo.h:206
PNG memory record (file in memory).
Definition: bitmap_def.h:29
BITMAP_DEF GetMenuImage() const override
void MoveAB(const wxPoint &aMoveVector)
Function MoveAB move this object.
const BITMAP_OPAQUE pad_xpm[1]
Definition: pad.cpp:41
print info associated to a component (TO.C attribute)
coord_type GetX() const
Definition: box2.h:189
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
const wxString & GetValue()
int color
Definition: DXF_plotter.cpp:61
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.
GERBER_FILE_IMAGE holds the Image data and parameters for one gerber file and layer parameters (TODO:...
int GetWidth() const
Definition: eda_rect.h:119
COLOR4D GetPositiveDrawColor() const
double RAD2DECIDEG(double rad)
Definition: trigo.h:219
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:131
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 SetNetAttributes(const GBR_NETLIST_METADATA &aNetAttributes)
this class handle info which can be added in a gerber file as attribute of an object the GBR_INFO_TYP...
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:208
double NormalizeAngleRadiansPos(double Angle)
Definition: trigo.h:281
The base class for create windows for drawing purpose.
VECTOR2< int > VECTOR2I
Definition: vector2d.h:594
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:338
bool Contains(const wxPoint &aPoint) const
Function Contains.
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
void Mirror(bool aX=true, bool aY=false, const VECTOR2I &aRef={ 0, 0 })
Mirrors 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)
bool TestSegmentHit(const wxPoint &aRefPoint, wxPoint aStart, wxPoint aEnd, int aDist)
Test if aRefPoint is with aDistance on the line defined by aStart and aEnd.
Definition: trigo.cpp:129
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Function GetMsgPanelInfo populates aList of MSG_PANEL_ITEM objects with it's internal state for displ...
#define LAST_DCODE
Definition: dcode.h:72
#define GERBER_DCODE_LAYER(x)
const INSPECTOR_FUNC & INSPECTOR
Definition: base_struct.h:105
const VECTOR2I & CPoint(int aIndex) const
Function Point()
const wxPoint GetEnd() const
Definition: eda_rect.h:116
const BITMAP_OPAQUE add_graphical_polygon_xpm[1]
COLOR4D m_NegativeDrawColor
The color used to draw negative objects, usually the background color, but not always,...
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.
#define NULL
VECTOR2< double > VECTOR2D
Definition: vector2d.h:593
void Move(const VECTOR2I &aVector) override
void SetHeight(int val)
Definition: eda_rect.h:186
EDA_RECT GetBoundingBox() const
Returns the bounding box of the shape.
Definition: am_primitive.h:231
#define FIRST_DCODE
Definition: dcode.h:71
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:114
void SetEnd(int x, int y)
Definition: eda_rect.h:192
coord_type GetWidth() const
Definition: box2.h:196
GBR_DATA_FIELD m_Padname
for a flashed pad: the pad name ((TO.P attribute)
const BITMAP_OPAQUE add_line_xpm[1]
Definition: add_line.cpp:30
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
double Angle() const
Function Angle computes the angle of the vector.
Definition: vector2d.h:313
void SetWidth(int val)
Definition: eda_rect.h:180
const BITMAP_OPAQUE info_xpm[1]
Definition: info.cpp:75
int NewOutline()
Creates a new empty polygon in the set and returns its index
Definition: color4d.h:59
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 aUnits) const override
void Normalize()
Function Normalize ensures that the height ant width are positive.
coord_type GetY() const
Definition: box2.h:190
Definition: color4d.h:56
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.
D_CODE holds a gerber DCODE (also called Aperture) definition.
Definition: dcode.h:82
const char * name
Definition: DXF_plotter.cpp:60
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
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
#define _(s)
Definition: 3d_actions.cpp:33
SHAPE_LINE_CHAIN.
wxString UnescapeString(const wxString &aSource)
Definition: string.cpp:131
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:596
bool HitTestPoints(const wxPoint &pointA, const wxPoint &pointB, double threshold)
Test, if two points are near each other.
Definition: trigo.h:166
STATUS_FLAGS m_Flags
Definition: base_struct.h:176
void RemoveAllContours()
Removes all outlines & holes (clears) the polygon set.
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
double DECIDEG2RAD(double deg)
Definition: trigo.h:218
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:68
SHAPE_POLY_SET m_Polygon
Definition: dcode.h:107
EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boards.
Definition: base_struct.h:159
The common library.
coord_type GetHeight() const
Definition: box2.h:197
wxPoint Centre() const
Definition: eda_rect.h:62
const BOX2I BBox(int aClearance=0) const override
Function BBox()
Definition: shape_arc.cpp:155
APERTURE_MACRO * GetMacro() const
Definition: dcode.h:157
print info associated to a flashed pad (TO.P attribute)
T EuclideanNorm() const
Destructor.
Definition: vector2d.h:299
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
VIEW.
Definition: view.h:61
SEARCH_RESULT
Definition: base_struct.h:51
void MoveXY(const wxPoint &aMoveVector)
Function MoveXY move this object.
Message panel definition file.
void GRClosedPoly(EDA_RECT *ClipBox, wxDC *DC, int n, const 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:552
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_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:103
KICAD_T Type() const
Function Type()
Definition: base_struct.h:193
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:640
COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:99
wxRealPoint m_drawScale