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 
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  {
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 
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 
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 name>";
745  else
746  net_msg << m_netAttributes.m_Netname;
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 ) 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 ) 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
COLOR4D GetPositiveDrawColor() const
void SetLayerParameters()
Function SetLayerParameters Initialize parameters from Image and Layer parameters found in the gerber...
KICAD_T Type() const
Function Type()
Definition: base_struct.h:201
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)
BOX2< VECTOR2I > BOX2I
Definition: box2.h:520
void Move(const wxPoint &aMoveVector)
Function Move moves the rectangle by the aMoveVector.
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
wxString GetClass() const override
Function GetClass returns the class name.
const wxPoint GetOrigin() const
Definition: eda_rect.h:112
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:191
PNG memory record (file in memory).
Definition: bitmap_types.h:43
BITMAP_DEF GetMenuImage() const override
>
D_CODE * GetDCODE(int aDCODE) const
Function GetDCODE returns a pointer to the D_CODE within this GERBER for the given aDCODE...
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:120
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.
const wxSize GetSize() const
Definition: eda_rect.h:101
int PointCount() const
Function PointCount()
bool Contains(const wxPoint &aPoint) const
Function Contains.
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
Class GERBER_FILE_IMAGE holds the Image data and parameters for one gerber file and layer parameters ...
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, bool aIgnoreHoles=false) const
Returns true if a given subpolygon contains the point aP.
double RAD2DECIDEG(double rad)
Definition: trigo.h:204
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...
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...
int OutlineCount() const
Returns the number of outlines in the set
this class handle info which can be added in a gerber file as attribute of an obtect the GBR_INFO_TYP...
STATUS_FLAGS GetStatus() const
Definition: base_struct.h:253
double NormalizeAngleRadiansPos(double Angle)
Definition: trigo.h:265
void GetMsgPanelInfo(EDA_UNITS_T aUnits, std::vector< MSG_PANEL_ITEM > &aList) override
Function GetMsgPanelInfo populates aList of MSG_PANEL_ITEM objects with it&#39;s internal state for displ...
VECTOR2< int > VECTOR2I
Definition: vector2d.h:587
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:320
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)
coord_type GetWidth() const
Definition: box2.h:195
#define LAST_DCODE
Definition: dcode.h:72
#define GERBER_DCODE_LAYER(x)
const INSPECTOR_FUNC & INSPECTOR
Definition: base_struct.h:102
D_CODE * GetDcodeDescr() const
Function GetDcodeDescr returns the GetDcodeDescr of this object, or NULL.
double Angle() const
Function Angle computes the angle of the vector.
Definition: vector2d.h:306
COLOR4D m_NegativeDrawColor
The color used to draw negative objects, usually the background color, but not always, when negative objects must be visible.
int GetLayer() const
Function GetLayer returns the layer this item is on.
wxString m_Padname
for a flashed pad: the pad name ((TO.P attribute)
SHAPE_POLY_SET * GetApertureMacroShape(const GERBER_DRAW_ITEM *aParent, wxPoint aShapePos)
Function GetApertureMacroShape Calculate the primitive shape for flashed items.
wxString ShowGBRShape() const
T EuclideanNorm() const
Destructor.
Definition: vector2d.h:292
VECTOR2< double > VECTOR2D
Definition: vector2d.h:586
void Move(const VECTOR2I &aVector) override
#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
void SetEnd(int x, int y)
Definition: eda_rect.h:134
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
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
const wxPoint GetEnd() const
Definition: eda_rect.h:114
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.
coord_type GetHeight() const
Definition: box2.h:196
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:92
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.
EDA_RECT GetBoundingBox() const
Returns the bounding box of the shape.
Definition: am_primitive.h:231
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:150
STATUS_FLAGS m_Flags
Flag bits for editing and other uses.
Definition: base_struct.h:178
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:203
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:154
The common library.
int GetWidth() const
Definition: eda_rect.h:117
APERTURE_MACRO * GetMacro() const
Definition: dcode.h:157
print info associated to a flashed pad (TO.P attribute)
VECTOR2I & Point(int aIndex)
Function Point()
#define GERBER_DRAW_LAYER(x)
void ConvertShapeToPolygon()
Function ConvertShapeToPolygon convert a shape to an equivalent polygon.
Definition: dcode.cpp:303
bool HitTest(const wxPoint &aRefPos) const override
Function HitTest tests if the given wxPoint is within the bounds of this object.
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.
wxPoint GetXYPosition(const wxPoint &aABPosition) const
Function GetXYPosition returns the image position of aPosition for this object.
wxPoint GetABPosition(const wxPoint &aXYPosition) const
Function GetABPosition returns the image position of aPosition for this object.
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:159
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
GERBER_LAYER & GetLayerParams()
Function GetLayerParams.
#define min(a, b)
Definition: auxiliary.h:85
int m_NetAttribType
the type of net info (used to define the gerber string to create)
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