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 
29 #include <fctsys.h>
30 #include <gr_basic.h>
31 #include <common.h>
32 #include <trigo.h>
33 #include <bitmaps.h>
34 #include <class_drawpanel.h>
35 #include <msgpanel.h>
36 #include <gerbview_frame.h>
38 
39 #include <gerber_draw_item.h>
40 #include <gerber_file_image.h>
41 #include <gerber_file_image_list.h>
42 #include <kicad_string.h>
43 
46 {
47  m_GerberImageFile = aGerberImageFile;
49  m_Flashed = false;
50  m_DCode = 0;
51  m_UnitsMetric = false;
52  m_LayerNegative = false;
53  m_swapAxis = false;
54  m_mirrorA = false;
55  m_mirrorB = false;
56  m_drawScale.x = m_drawScale.y = 1.0;
57  m_lyrRotation = 0;
58 
59  if( m_GerberImageFile )
61 }
62 
63 
65 {
66 }
67 
68 
70 {
71  m_netAttributes = aNetAttributes;
72 
75  m_GerberImageFile->m_ComponentsList.insert( std::make_pair( m_netAttributes.m_Cmpref, 0 ) );
76 
78  m_GerberImageFile->m_NetnamesList.insert( std::make_pair( m_netAttributes.m_Netname, 0 ) );
79 }
80 
81 
83 {
84  // returns the layer this item is on, or 0 if the m_GerberImageFile is NULL.
86 }
87 
88 
89 bool GERBER_DRAW_ITEM::GetTextD_CodePrms( int& aSize, wxPoint& aPos, double& aOrientation )
90 {
91  // calculate the best size and orientation of the D_Code text
92 
93  if( m_DCode <= 0 )
94  return false; // No D_Code for this item
95 
96  if( m_Flashed || m_Shape == GBR_ARC )
97  {
98  aPos = m_Start;
99  }
100  else // it is a line:
101  {
102  aPos = ( m_Start + m_End) / 2;
103  }
104 
105  aPos = GetABPosition( aPos );
106 
107  int size; // the best size for the text
108 
109  if( GetDcodeDescr() )
110  size = GetDcodeDescr()->GetShapeDim( this );
111  else
112  size = std::min( m_Size.x, m_Size.y );
113 
114  aOrientation = TEXT_ANGLE_HORIZ;
115 
116  if( m_Flashed )
117  {
118  // A reasonable size for text is min_dim/3 because most of time this text has 3 chars.
119  aSize = size / 3;
120  }
121  else // this item is a line
122  {
123  wxPoint delta = m_Start - m_End;
124 
125  aOrientation = RAD2DECIDEG( atan2( (double)delta.y, (double)delta.x ) );
126  NORMALIZE_ANGLE_90( aOrientation );
127 
128  // A reasonable size for text is size/2 because text needs margin below and above it.
129  // a margin = size/4 seems good, expecting the line len is large enough to show 3 chars,
130  // that is the case most of time.
131  aSize = size / 2;
132  }
133 
134  return true;
135 }
136 
137 
138 bool GERBER_DRAW_ITEM::GetTextD_CodePrms( double& aSize, VECTOR2D& aPos, double& aOrientation )
139 {
140  // aOrientation is returned in radians
141  int size;
142  wxPoint pos;
143 
144  if( ! GetTextD_CodePrms( size, pos, aOrientation ) )
145  return false;
146 
147  aPos = pos;
148  aSize = (double) size;
149  aOrientation = DECIDEG2RAD( aOrientation );
150 
151  return true;
152 }
153 
154 
155 wxPoint GERBER_DRAW_ITEM::GetABPosition( const wxPoint& aXYPosition ) const
156 {
157  /* Note: RS274Xrevd_e is obscure about the order of transforms:
158  * For instance: Rotation must be made after or before mirroring ?
159  * Note: if something is changed here, GetYXPosition must reflect changes
160  */
161  wxPoint abPos = aXYPosition + m_GerberImageFile->m_ImageJustifyOffset;
162 
163  if( m_swapAxis )
164  std::swap( abPos.x, abPos.y );
165 
167  abPos.x = KiROUND( abPos.x * m_drawScale.x );
168  abPos.y = KiROUND( abPos.y * m_drawScale.y );
169  double rotation = m_lyrRotation * 10 + m_GerberImageFile->m_ImageRotation * 10;
170 
171  if( rotation )
172  RotatePoint( &abPos, -rotation );
173 
174  // Negate A axis if mirrored
175  if( m_mirrorA )
176  abPos.x = -abPos.x;
177 
178  // abPos.y must be negated when no mirror, because draw axis is top to bottom
179  if( !m_mirrorB )
180  abPos.y = -abPos.y;
181  return abPos;
182 }
183 
184 
185 wxPoint GERBER_DRAW_ITEM::GetXYPosition( const wxPoint& aABPosition ) const
186 {
187  // do the inverse transform made by GetABPosition
188  wxPoint xyPos = aABPosition;
189 
190  if( m_mirrorA )
191  xyPos.x = -xyPos.x;
192 
193  if( !m_mirrorB )
194  xyPos.y = -xyPos.y;
195 
196  double rotation = m_lyrRotation * 10 + m_GerberImageFile->m_ImageRotation * 10;
197 
198  if( rotation )
199  RotatePoint( &xyPos, rotation );
200 
201  xyPos.x = KiROUND( xyPos.x / m_drawScale.x );
202  xyPos.y = KiROUND( xyPos.y / m_drawScale.y );
204 
205  if( m_swapAxis )
206  std::swap( xyPos.x, xyPos.y );
207 
208  return xyPos - m_GerberImageFile->m_ImageJustifyOffset;
209 }
210 
211 
213 {
215  m_swapAxis = m_GerberImageFile->m_SwapAxis; // false if A = X, B = Y;
216 
217  // true if A =Y, B = Y
218  m_mirrorA = m_GerberImageFile->m_MirrorA; // true: mirror / axe A
219  m_mirrorB = m_GerberImageFile->m_MirrorB; // true: mirror / axe B
220  m_drawScale = m_GerberImageFile->m_Scale; // A and B scaling factor
221  m_layerOffset = m_GerberImageFile->m_Offset; // Offset from OF command
222 
223  // Rotation from RO command:
226 }
227 
228 
230 {
231  switch( m_Shape )
232  {
233  case GBR_SEGMENT:
234  return _( "Line" );
235 
236  case GBR_ARC:
237  return _( "Arc" );
238 
239  case GBR_CIRCLE:
240  return _( "Circle" );
241 
242  case GBR_SPOT_OVAL:
243  return wxT( "spot_oval" );
244 
245  case GBR_SPOT_CIRCLE:
246  return wxT( "spot_circle" );
247 
248  case GBR_SPOT_RECT:
249  return wxT( "spot_rect" );
250 
251  case GBR_SPOT_POLY:
252  return wxT( "spot_poly" );
253 
254  case GBR_POLYGON:
255  return wxT( "polygon" );
256 
257  case GBR_SPOT_MACRO:
258  {
259  wxString name = wxT( "apt_macro" );
260  D_CODE* dcode = GetDcodeDescr();
261 
262  if( dcode && dcode->GetMacro() )
263  name << wxT(" ") << dcode->GetMacro()->name;
264 
265  return name;
266  }
267 
268  default:
269  return wxT( "??" );
270  }
271 }
272 
273 
275 {
276  if( (m_DCode < FIRST_DCODE) || (m_DCode > LAST_DCODE) )
277  return NULL;
278 
279  if( m_GerberImageFile == NULL )
280  return NULL;
281 
283 }
284 
285 
287 {
288  // return a rectangle which is (pos,dim) in nature. therefore the +1
289  EDA_RECT bbox( m_Start, wxSize( 1, 1 ) );
290  D_CODE* code = GetDcodeDescr();
291 
292  // TODO(JE) GERBER_DRAW_ITEM maybe should actually be a number of subclasses.
293  // Until/unless that is changed, we need to do different things depending on
294  // what is actually being represented by this GERBER_DRAW_ITEM.
295 
296  switch( m_Shape )
297  {
298  case GBR_POLYGON:
299  {
300  auto bb = m_Polygon.BBox();
301  bbox.Inflate( bb.GetWidth() / 2, bb.GetHeight() / 2 );
302  bbox.SetOrigin( bb.GetOrigin().x, bb.GetOrigin().y );
303  break;
304  }
305 
306  case GBR_CIRCLE:
307  {
308  double radius = GetLineLength( m_Start, m_End );
309  bbox.Inflate( radius, radius );
310  break;
311  }
312 
313  case GBR_ARC:
314  {
315  // Note: using a larger-than-necessary BB to simplify computation
316  double radius = GetLineLength( m_Start, m_ArcCentre );
317  bbox.Move( m_ArcCentre - m_Start );
318  bbox.Inflate( radius + m_Size.x, radius + m_Size.x );
319  break;
320  }
321 
322  case GBR_SPOT_CIRCLE:
323  {
324  if( code )
325  {
326  int radius = code->m_Size.x >> 1;
327  bbox.Inflate( radius, radius );
328  }
329  break;
330  }
331 
332  case GBR_SPOT_RECT:
333  {
334  if( code )
335  bbox.Inflate( code->m_Size.x / 2, code->m_Size.y / 2 );
336  break;
337  }
338 
339  case GBR_SPOT_OVAL:
340  {
341  if( code )
342  bbox.Inflate( code->m_Size.x, code->m_Size.y );
343  break;
344  }
345 
346  case GBR_SPOT_POLY:
347  {
348  if( code )
349  {
350  if( code->m_Polygon.OutlineCount() == 0 )
351  code->ConvertShapeToPolygon();
352 
353  bbox.Inflate( code->m_Polygon.BBox().GetWidth() / 2,
354  code->m_Polygon.BBox().GetHeight() / 2 );
355  }
356  break;
357  }
358  case GBR_SPOT_MACRO:
359  {
360  if( code )
361  {
362  // Update the shape drawings and the bounding box coordiantes:
363  code->GetMacro()->GetApertureMacroShape( this, m_Start );
364  // now the bounding box is valid:
365  bbox = code->GetMacro()->GetBoundingBox();
366  }
367  break;
368  }
369 
370  case GBR_SEGMENT:
371  {
372  if( code && code->m_Shape == APT_RECT )
373  {
374  if( m_Polygon.OutlineCount() > 0 )
375  {
376  auto bb = m_Polygon.BBox();
377  bbox.Inflate( bb.GetWidth() / 2, bb.GetHeight() / 2 );
378  bbox.SetOrigin( bb.GetOrigin().x, bb.GetOrigin().y );
379  }
380  }
381  else
382  {
383  int radius = ( m_Size.x + 1 ) / 2;
384 
385  int ymax = std::max( m_Start.y, m_End.y ) + radius;
386  int xmax = std::max( m_Start.x, m_End.x ) + radius;
387 
388  int ymin = std::min( m_Start.y, m_End.y ) - radius;
389  int xmin = std::min( m_Start.x, m_End.x ) - radius;
390 
391  bbox = EDA_RECT( wxPoint( xmin, ymin ), wxSize( xmax - xmin + 1, ymax - ymin + 1 ) );
392  }
393 
394  break;
395  }
396  default:
397  wxASSERT_MSG( false, wxT( "GERBER_DRAW_ITEM shape is unknown!" ) );
398  break;
399  }
400 
401  // calculate the corners coordinates in current gerber axis orientations
402  wxPoint org = GetABPosition( bbox.GetOrigin() );
403  wxPoint end = GetABPosition( bbox.GetEnd() );
404 
405  // Set the corners position:
406  bbox.SetOrigin( org );
407  bbox.SetEnd( end );
408  bbox.Normalize();
409 
410  return bbox;
411 }
412 
413 
414 void GERBER_DRAW_ITEM::MoveAB( const wxPoint& aMoveVector )
415 {
416  wxPoint xymove = GetXYPosition( aMoveVector );
417 
418  m_Start += xymove;
419  m_End += xymove;
420  m_ArcCentre += xymove;
421 
422  if( m_Polygon.OutlineCount() > 0 )
423  {
424  for( auto it = m_Polygon.Iterate( 0 ); it; ++it )
425  *it += xymove;
426  }
427 }
428 
429 
430 void GERBER_DRAW_ITEM::MoveXY( const wxPoint& aMoveVector )
431 {
432  m_Start += aMoveVector;
433  m_End += aMoveVector;
434  m_ArcCentre += aMoveVector;
435 
436  if( m_Polygon.OutlineCount() > 0 )
437  {
438  for( auto it = m_Polygon.Iterate( 0 ); it; ++it )
439  *it += aMoveVector;
440  }
441 }
442 
443 
445 {
447 
448  // if isClear is true, this item has negative shape
449  return isClear;
450 }
451 
452 
453 void GERBER_DRAW_ITEM::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, GR_DRAWMODE aDrawMode,
454  const wxPoint& aOffset, GBR_DISPLAY_OPTIONS* aDrawOptions )
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  if( ( aDrawMode & GR_HIGHLIGHT ) && !( aDrawMode & GR_AND ) )
470  color.SetToLegacyHighlightColor();
471 
472  /* isDark is true if flash is positive and should use a drawing
473  * color other than the background color, else use the background color
474  * when drawing so that an erasure happens.
475  */
477 
478  if( !isDark )
479  {
480  // draw in background color ("negative" color)
481  color = aDrawOptions->m_NegativeDrawColor;
482  }
483 
484  GRSetDrawMode( aDC, aDrawMode );
485 
486  isFilled = aDrawOptions->m_DisplayLinesFill;
487 
488  switch( m_Shape )
489  {
490  case GBR_POLYGON:
491  isFilled = aDrawOptions->m_DisplayPolygonsFill;
492 
493  if( !isDark )
494  isFilled = true;
495 
496  DrawGbrPoly( aPanel->GetClipBox(), aDC, color, aOffset, isFilled );
497  break;
498 
499  case GBR_CIRCLE:
500  radius = KiROUND( GetLineLength( m_Start, m_End ) );
501 
502  halfPenWidth = m_Size.x >> 1;
503 
504  if( !isFilled )
505  {
506  // draw the border of the pen's path using two circles, each as narrow as possible
507  GRCircle( aPanel->GetClipBox(), aDC, GetABPosition( m_Start ),
508  radius - halfPenWidth, 0, color );
509  GRCircle( aPanel->GetClipBox(), aDC, GetABPosition( m_Start ),
510  radius + halfPenWidth, 0, color );
511  }
512  else // Filled mode
513  {
514  GRCircle( aPanel->GetClipBox(), aDC, GetABPosition( m_Start ),
515  radius, m_Size.x, color );
516  }
517  break;
518 
519  case GBR_ARC:
520  // Currently, arcs plotted with a rectangular aperture are not supported.
521  // a round pen only is expected.
522 
523 #if 0 // for arc debug only
524  GRLine( aPanel->GetClipBox(), aDC, GetABPosition( m_Start ),
526  GRLine( aPanel->GetClipBox(), aDC, GetABPosition( m_End ),
528 #endif
529 
530  if( !isFilled )
531  {
532  GRArc1( aPanel->GetClipBox(), aDC, GetABPosition( m_Start ),
534  0, color );
535  }
536  else
537  {
538  GRArc1( aPanel->GetClipBox(), aDC, GetABPosition( m_Start ),
540  m_Size.x, color );
541  }
542 
543  break;
544 
545  case GBR_SPOT_CIRCLE:
546  case GBR_SPOT_RECT:
547  case GBR_SPOT_OVAL:
548  case GBR_SPOT_POLY:
549  case GBR_SPOT_MACRO:
550  isFilled = aDrawOptions->m_DisplayFlashedItemsFill;
551  d_codeDescr->DrawFlashedShape( this, aPanel->GetClipBox(), aDC, color,
552  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  DrawGbrPoly( aPanel->GetClipBox(), aDC, color, aOffset, isFilled );
567  }
568  else
569  {
570  if( !isFilled )
571  {
572  GRCSegm( aPanel->GetClipBox(), aDC, GetABPosition( m_Start ),
573  GetABPosition( m_End ), m_Size.x, color );
574  }
575  else
576  {
577  GRFilledSegment( aPanel->GetClipBox(), aDC, GetABPosition( m_Start ),
578  GetABPosition( m_End ), 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 {
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  m_Polygon.Append( VECTOR2I( corner ) ); // Lower left corner, start point (1)
630  corner.y += m_Size.y;
631  m_Polygon.Append( VECTOR2I( corner ) ); // upper left corner, start point (2)
632 
633  if( delta.x || delta.y)
634  {
635  corner += delta;
636  m_Polygon.Append( VECTOR2I( corner ) ); // upper left corner, end point (3)
637  }
638 
639  corner.x += m_Size.x;
640  m_Polygon.Append( VECTOR2I( corner ) ); // upper right corner, end point (4)
641  corner.y -= m_Size.y;
642  m_Polygon.Append( VECTOR2I( corner ) ); // lower right corner, end point (5)
643 
644  if( delta.x || delta.y )
645  {
646  corner -= delta;
647  m_Polygon.Append( VECTOR2I( corner ) ); // lower left corner, start point (6)
648  }
649 
650  m_Polygon.Append( VECTOR2I( close ) ); // close the shape
651 
652  // Create final polygon:
653  for( auto it = m_Polygon.Iterate( 0 ); it; ++it )
654  {
655  if( change )
656  ( *it ).y = -( *it ).y;
657 
658  *it += start;
659  }
660 }
661 
662 
664  wxDC* aDC,
665  COLOR4D aColor,
666  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.Point( ii ).x, poly.Point( ii ).y );
678  points[ii] = p + aOffset;
679  points[ii] = GetABPosition( points[ii] );
680  }
681 
682  GRClosedPoly( aClipBox, aDC, pointCount, &points[0], aFilledShape, aColor, aColor );
683 }
684 
685 
686 void GERBER_DRAW_ITEM::GetMsgPanelInfo( EDA_UNITS_T aUnits, std::vector< MSG_PANEL_ITEM >& aList )
687 {
688  wxString msg;
689  wxString text;
690 
691  msg = ShowGBRShape();
692  aList.push_back( MSG_PANEL_ITEM( _( "Type" ), msg, DARKCYAN ) );
693 
694  // Display D_Code value with its attributes:
695  msg.Printf( _( "D Code %d" ), m_DCode );
696  D_CODE* apertDescr = GetDcodeDescr();
697 
698  if( !apertDescr || apertDescr->m_AperFunction.IsEmpty() )
699  text = _( "No attribute" );
700  else
701  text = apertDescr->m_AperFunction;
702 
703  aList.push_back( MSG_PANEL_ITEM( msg, text, RED ) );
704 
705  // Display graphic layer name
707  aList.push_back( MSG_PANEL_ITEM( _( "Graphic Layer" ), msg, DARKGREEN ) );
708 
709  // Display item rotation
710  // The full rotation is Image rotation + m_lyrRotation
711  // but m_lyrRotation is specific to this object
712  // so we display only this parameter
713  msg.Printf( wxT( "%f" ), m_lyrRotation );
714  aList.push_back( MSG_PANEL_ITEM( _( "Rotation" ), msg, BLUE ) );
715 
716  // Display item polarity (item specific)
717  msg = m_LayerNegative ? _("Clear") : _("Dark");
718  aList.push_back( MSG_PANEL_ITEM( _( "Polarity" ), msg, BLUE ) );
719 
720  // Display mirroring (item specific)
721  msg.Printf( wxT( "A:%s B:%s" ),
722  m_mirrorA ? _("Yes") : _("No"),
723  m_mirrorB ? _("Yes") : _("No"));
724  aList.push_back( MSG_PANEL_ITEM( _( "Mirror" ), msg, DARKRED ) );
725 
726  // Display AB axis swap (item specific)
727  msg = m_swapAxis ? wxT( "A=Y B=X" ) : wxT( "A=X B=Y" );
728  aList.push_back( MSG_PANEL_ITEM( _( "AB axis" ), msg, DARKRED ) );
729 
730  // Display net info, if exists
732  return;
733 
734  // Build full net info:
735  wxString net_msg;
736  wxString cmp_pad_msg;
737 
739  {
740  net_msg = _( "Net:" );
741  net_msg << " ";
742 
743  if( m_netAttributes.m_Netname.IsEmpty() )
744  net_msg << "<no net>";
745  else
747  }
748 
750  {
751  cmp_pad_msg.Printf( _( "Cmp: %s; Pad: %s" ),
754  }
755 
757  {
758  cmp_pad_msg = _( "Cmp:" );
759  cmp_pad_msg << " " << m_netAttributes.m_Cmpref;
760  }
761 
762  aList.push_back( MSG_PANEL_ITEM( net_msg, cmp_pad_msg, DARKCYAN ) );
763 }
764 
765 
767 {
768  if( m_Flashed )
769  return pad_xpm;
770 
771  switch( m_Shape )
772  {
773  case GBR_SEGMENT:
774  case GBR_ARC:
775  case GBR_CIRCLE:
776  return add_line_xpm;
777 
778  case GBR_SPOT_OVAL:
779  case GBR_SPOT_CIRCLE:
780  case GBR_SPOT_RECT:
781  case GBR_SPOT_POLY:
782  case GBR_SPOT_MACRO:
783  // should be handles by m_Flashed == true
784  return pad_xpm;
785 
786  case GBR_POLYGON:
787  return add_graphical_polygon_xpm;
788  }
789 
790  return info_xpm;
791 }
792 
793 
794 bool GERBER_DRAW_ITEM::HitTest( const wxPoint& aRefPos, int aAccuracy ) const
795 {
796  // In case the item has a very tiny width defined, allow it to be selected
797  const int MIN_HIT_TEST_RADIUS = Millimeter2iu( 0.01 );
798 
799  // calculate aRefPos in XY gerber axis:
800  wxPoint ref_pos = GetXYPosition( aRefPos );
801 
802  SHAPE_POLY_SET poly;
803 
804  switch( m_Shape )
805  {
806  case GBR_POLYGON:
807  poly = m_Polygon;
808  return poly.Contains( VECTOR2I( ref_pos ), 0 );
809 
810  case GBR_SPOT_POLY:
811  poly = GetDcodeDescr()->m_Polygon;
812  poly.Move( m_Start );
813  return poly.Contains( VECTOR2I( ref_pos ), 0 );
814 
815  case GBR_SPOT_RECT:
816  return GetBoundingBox().Contains( aRefPos );
817 
818  case GBR_ARC:
819  {
820  double radius = GetLineLength( m_Start, m_ArcCentre );
821  VECTOR2D test_radius = VECTOR2D( ref_pos ) - VECTOR2D( m_ArcCentre );
822 
823  int size = ( ( m_Size.x < MIN_HIT_TEST_RADIUS ) ? MIN_HIT_TEST_RADIUS
824  : m_Size.x );
825 
826  // Are we close enough to the radius?
827  bool radius_hit = ( std::fabs( test_radius.EuclideanNorm() - radius) < size );
828 
829  if( radius_hit )
830  {
831  // Now check that we are within the arc angle
832 
833  VECTOR2D start = VECTOR2D( m_Start ) - VECTOR2D( m_ArcCentre );
835 
836  double start_angle = NormalizeAngleRadiansPos( start.Angle() );
837  double end_angle = NormalizeAngleRadiansPos( end.Angle() );
838 
839  if( m_Start == m_End )
840  {
841  start_angle = 0;
842  end_angle = 2 * M_PI;
843  }
844  else if( end_angle < start_angle )
845  {
846  end_angle += 2 * M_PI;
847  }
848 
849  double test_angle = NormalizeAngleRadiansPos( test_radius.Angle() );
850 
851  return ( test_angle > start_angle && test_angle < end_angle );
852  }
853 
854  return false;
855  }
856 
857  case GBR_SPOT_MACRO:
858  // Aperture macro polygons are already in absolute coordinates
859  auto p = GetDcodeDescr()->GetMacro()->GetApertureMacroShape( this, m_Start );
860  for( int i = 0; i < p->OutlineCount(); ++i )
861  {
862  if( p->Contains( VECTOR2I( aRefPos ), i ) )
863  return true;
864  }
865  return false;
866  }
867 
868  // TODO: a better analyze of the shape (perhaps create a D_CODE::HitTest for flashed items)
869  int radius = std::min( m_Size.x, m_Size.y ) >> 1;
870 
871  if( radius < MIN_HIT_TEST_RADIUS )
872  radius = MIN_HIT_TEST_RADIUS;
873 
874  if( m_Flashed )
875  return HitTestPoints( m_Start, ref_pos, radius );
876  else
877  return TestSegmentHit( ref_pos, m_Start, m_End, radius );
878 }
879 
880 
881 bool GERBER_DRAW_ITEM::HitTest( const EDA_RECT& aRefArea, bool aContained, int aAccuracy ) const
882 {
883  wxPoint pos = GetABPosition( m_Start );
884 
885  if( aRefArea.Contains( pos ) )
886  return true;
887 
888  pos = GetABPosition( m_End );
889 
890  if( aRefArea.Contains( pos ) )
891  return true;
892 
893  return false;
894 }
895 
896 
897 #if defined(DEBUG)
898 
899 void GERBER_DRAW_ITEM::Show( int nestLevel, std::ostream& os ) const
900 {
901  NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() <<
902 
903  " shape=\"" << m_Shape << '"' <<
904  " addr=\"" << std::hex << this << std::dec << '"' <<
905  " layer=\"" << GetLayer() << '"' <<
906  " size=\"" << m_Size << '"' <<
907  " flags=\"" << m_Flags << '"' <<
908  " status=\"" << GetStatus() << '"' <<
909  "<start" << m_Start << "/>" <<
910  "<end" << m_End << "/>";
911 
912  os << "</" << GetClass().Lower().mb_str() << ">\n";
913 }
914 
915 #endif
916 
917 
918 void GERBER_DRAW_ITEM::ViewGetLayers( int aLayers[], int& aCount ) const
919 {
920  aCount = 2;
921 
922  aLayers[0] = GERBER_DRAW_LAYER( GetLayer() );
923  aLayers[1] = GERBER_DCODE_LAYER( aLayers[0] );
924 }
925 
926 
928 {
929  EDA_RECT bbox = GetBoundingBox();
930  return BOX2I( VECTOR2I( bbox.GetOrigin() ),
931  VECTOR2I( bbox.GetSize() ) );
932 }
933 
934 
935 unsigned int GERBER_DRAW_ITEM::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
936 {
937  // DCodes will be shown only if zoom is appropriate:
938  // Returns the level of detail of the item.
939  // A level of detail (LOD) is the minimal VIEW scale that
940  // is sufficient for an item to be shown on a given layer.
941  if( IsDCodeLayer( aLayer ) )
942  {
943  int size = 0;
944 
945  switch( m_Shape )
946  {
947  case GBR_SPOT_MACRO:
949  break;
950 
951  case GBR_ARC:
952  size = GetLineLength( m_Start, m_ArcCentre );
953  break;
954 
955  default:
956  size = m_Size.x;
957  }
958 
959  // the level of details is chosen experimentally, to show
960  // only a readable text:
961  const int level = Millimeter2iu( 4 );
962  return ( level / ( size + 1 ) );
963  }
964 
965  // Other layers are shown without any conditions
966  return 0;
967 }
968 
969 
970 SEARCH_RESULT GERBER_DRAW_ITEM::Visit( INSPECTOR inspector, void* testData, const KICAD_T scanTypes[] )
971 {
972  KICAD_T stype = *scanTypes;
973 
974  // If caller wants to inspect my type
975  if( stype == Type() )
976  {
977  if( SEARCH_QUIT == inspector( this, testData ) )
978  return SEARCH_QUIT;
979  }
980 
981  return SEARCH_CONTINUE;
982 }
983 
984 
986 {
987  wxString layerName;
988 
990 
991  return wxString::Format( _( "%s (D%d) on layer %d: %s" ),
992  ShowGBRShape(),
993  m_DCode,
994  GetLayer() + 1,
995  layerName );
996 }
Definition: colors.h:57
#define TEXT_ANGLE_HORIZ
void SetLayerParameters()
Function SetLayerParameters Initialize parameters from Image and Layer parameters found in the gerber...
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, bool aIgnoreHoles=false) const
Returns true if a given subpolygon contains the point aP.
void DrawGbrPoly(EDA_RECT *aClipBox, wxDC *aDC, COLOR4D aColor, const wxPoint &aOffset, bool aFilledShape)
Function DrawGbrPoly a helper function used to draw the polygon stored in m_PolyCorners.
bool m_DisplayPolygonsFill
Option to draw polygons (filled/sketch)
STATUS_FLAGS GetStatus() const
Definition: base_struct.h:256
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:200
BITMAP_DEF GetMenuImage() const override
void MoveAB(const wxPoint &aMoveVector)
Function MoveAB move this object.
void GRSetDrawMode(wxDC *DC, GR_DRAWMODE draw_mode)
Definition: gr_basic.cpp:223
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:213
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 GRCSegm(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, int aPenSize, COLOR4D Color)
Definition: gr_basic.cpp:415
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.
virtual EDA_RECT * GetClipBox()
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:216
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:274
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:329
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:711
static const int delta[8][2]
Definition: solve.cpp:112
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:102
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
GR_DRAWMODE
Drawmode. Compositing mode plus a flag or two.
Definition: gr_basic.h:37
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
void GRLine(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, COLOR4D Color, wxPenStyle aStyle)
Definition: gr_basic.cpp:285
int NewOutline()
Creates a new empty polygon in the set and returns its index
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 Draw(EDA_DRAW_PANEL *aPanel, wxDC *aDC, GR_DRAWMODE aDrawMode, const wxPoint &aOffset, GBR_DISPLAY_OPTIONS *aDrawOptions)
void Normalize()
Function Normalize ensures that the height ant width are positive.
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:154
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:526
void GRCircle(EDA_RECT *ClipBox, wxDC *DC, int xc, int yc, int r, int width, COLOR4D Color)
Definition: gr_basic.cpp:755
bool HitTestPoints(const wxPoint &pointA, const wxPoint &pointB, double threshold)
Test, if two points are near each other.
Definition: trigo.h:159
STATUS_FLAGS m_Flags
Flag bits for editing and other uses.
Definition: base_struct.h:181
size_t i
Definition: json11.cpp:597
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:212
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:157
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:303
Class EDA_MSG_ITEM is used EDA_MSG_PANEL as the item type for displaying messages.
Definition: msgpanel.h:53
Class VIEW.
Definition: view.h:61
bool TestSegmentHit(const wxPoint &aRefPoint, wxPoint aStart, wxPoint aEnd, int aDist)
Function TestSegmentHit test for hit on line segment i.e.
Definition: trigo.cpp:122
SEARCH_RESULT
Definition: base_struct.h:66
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:123
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:204
#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:799
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39
wxRealPoint m_drawScale