KiCad PCB EDA Suite
dcode.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) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2011 Wayne Stambaugh <[email protected]>
6  * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
31 #include <trigo.h>
32 #include <eda_rect.h>
33 #include <gerbview_frame.h>
34 #include <gerber_file_image.h>
35 #include <convert_to_biu.h>
37 
38 #define DCODE_DEFAULT_SIZE Millimeter2iu( 0.1 )
39 
40 /* Format Gerber: NOTES:
41  * Tools and D_CODES
42  * tool number (identification of shapes)
43  * 1 to 999
44  *
45  * D_CODES:
46  * D01 ... D9 = command codes:
47  * D01 = activating light (pen down) while moving
48  * D02 = light extinction (pen up) while moving
49  * D03 = Flash
50  * D04 to D09 = non used
51  * D10 ... D999 = Identification Tool (Shape id)
52  *
53  * For tools defining a shape):
54  * DCode min = D10
55  * DCode max = 999
56  */
57 
58 
59 D_CODE::D_CODE( int num_dcode )
60 {
61  m_Num_Dcode = num_dcode;
63 }
64 
65 
67 {
68 }
69 
70 
72 {
76  m_Drill.x = m_Drill.y = 0;
78  m_InUse = false;
79  m_Defined = false;
80  m_Macro = nullptr;
81  m_Rotation = 0.0;
82  m_EdgesCount = 0;
84 }
85 
86 
87 const wxChar* D_CODE::ShowApertureType( APERTURE_T aType )
88 {
89  const wxChar* ret;
90 
91  switch( aType )
92  {
93  case APT_CIRCLE:
94  ret = wxT( "Round" ); break;
95 
96  case APT_RECT:
97  ret = wxT( "Rect" ); break;
98 
99  case APT_OVAL:
100  ret = wxT( "Oval" ); break;
101 
102  case APT_POLYGON:
103  ret = wxT( "Poly" ); break;
104 
105  case APT_MACRO:
106  ret = wxT( "Macro" ); break;
107 
108  default:
109  ret = wxT( "???" ); break;
110  }
111 
112  return ret;
113 }
114 
115 
117 {
118  int dim = -1;
119 
120  switch( m_Shape )
121  {
122  case APT_CIRCLE:
123  dim = m_Size.x;
124  break;
125 
126  case APT_RECT:
127  case APT_OVAL:
128  dim = std::min( m_Size.x, m_Size.y );
129  break;
130 
131  case APT_POLYGON:
132  dim = std::min( m_Size.x, m_Size.y );
133  break;
134 
135  case APT_MACRO:
136  if( m_Macro )
137  dim = m_Macro->GetShapeDim( aParent );
138  break;
139 
140  default:
141  break;
142  }
143 
144  return dim;
145 }
146 
147 
148 void D_CODE::DrawFlashedShape( GERBER_DRAW_ITEM* aParent, EDA_RECT* aClipBox, wxDC* aDC,
149  const COLOR4D& aColor, const wxPoint& aShapePos, bool aFilledShape )
150 {
151  int radius;
152 
153  switch( m_Shape )
154  {
155  case APT_MACRO:
156  GetMacro()->DrawApertureMacroShape( aParent, aClipBox, aDC, aColor, aShapePos,
157  aFilledShape );
158  break;
159 
160  case APT_CIRCLE:
161  radius = m_Size.x >> 1;
162 
163  if( !aFilledShape )
164  {
165  GRCircle( aClipBox, aDC, aParent->GetABPosition(aShapePos), radius, 0, aColor );
166  }
167  else if( m_DrillShape == APT_DEF_NO_HOLE )
168  {
169  GRFilledCircle( aClipBox, aDC, aParent->GetABPosition(aShapePos), radius, aColor );
170  }
171  else if( m_DrillShape == APT_DEF_ROUND_HOLE ) // round hole in shape
172  {
173  int width = (m_Size.x - m_Drill.x ) / 2;
174  GRCircle( aClipBox, aDC, aParent->GetABPosition(aShapePos),
175  radius - (width / 2), width, aColor );
176  }
177  else // rectangular hole
178  {
179  if( m_Polygon.OutlineCount() == 0 )
181 
182  DrawFlashedPolygon( aParent, aClipBox, aDC, aColor, aFilledShape, aShapePos );
183  }
184 
185  break;
186 
187  case APT_RECT:
188  {
189  wxPoint start;
190  start.x = aShapePos.x - m_Size.x / 2;
191  start.y = aShapePos.y - m_Size.y / 2;
192  wxPoint end = start + m_Size;
193  start = aParent->GetABPosition( start );
194  end = aParent->GetABPosition( end );
195 
196  if( !aFilledShape )
197  {
198  GRRect( aClipBox, aDC, start.x, start.y, end.x, end.y, 0, aColor );
199  }
200  else if( m_DrillShape == APT_DEF_NO_HOLE )
201  {
202  GRFilledRect( aClipBox, aDC, start.x, start.y, end.x, end.y, 0, aColor, aColor );
203  }
204  else
205  {
206  if( m_Polygon.OutlineCount() == 0 )
208 
209  DrawFlashedPolygon( aParent, aClipBox, aDC, aColor, aFilledShape, aShapePos );
210  }
211  }
212  break;
213 
214  case APT_OVAL:
215  {
216  wxPoint start = aShapePos;
217  wxPoint end = aShapePos;
218 
219  if( m_Size.x > m_Size.y ) // horizontal oval
220  {
221  int delta = ( m_Size.x - m_Size.y ) / 2;
222  start.x -= delta;
223  end.x += delta;
224  radius = m_Size.y; // Width in fact
225  }
226  else // vertical oval
227  {
228  int delta = ( m_Size.y - m_Size.x ) / 2;
229  start.y -= delta;
230  end.y += delta;
231  radius = m_Size.x; // Width in fact
232  }
233 
234  start = aParent->GetABPosition( start );
235  end = aParent->GetABPosition( end );
236 
237  if( !aFilledShape )
238  {
239  GRCSegm( aClipBox, aDC, start.x, start.y, end.x, end.y, radius, aColor );
240  }
241  else if( m_DrillShape == APT_DEF_NO_HOLE )
242  {
243  GRFillCSegm( aClipBox, aDC, start.x, start.y, end.x, end.y, radius, aColor );
244  }
245  else
246  {
247  if( m_Polygon.OutlineCount() == 0 )
249 
250  DrawFlashedPolygon( aParent, aClipBox, aDC, aColor, aFilledShape, aShapePos );
251  }
252  }
253 
254  break;
255 
256  case APT_POLYGON:
257  if( m_Polygon.OutlineCount() == 0 )
259 
260  DrawFlashedPolygon( aParent, aClipBox, aDC, aColor, aFilledShape, aShapePos );
261  break;
262  }
263 }
264 
265 
266 void D_CODE::DrawFlashedPolygon( GERBER_DRAW_ITEM* aParent, EDA_RECT* aClipBox, wxDC* aDC,
267  const COLOR4D& aColor, bool aFilled, const wxPoint& aPosition )
268 {
269  if( m_Polygon.OutlineCount() == 0 )
270  return;
271 
272  int pointCount = m_Polygon.VertexCount();
273  std::vector<wxPoint> points;
274  points.reserve( pointCount );
275 
276  for( int ii = 0; ii < pointCount; ii++ )
277  {
278  wxPoint p( m_Polygon.CVertex( ii ).x, m_Polygon.CVertex( ii ).y );
279  points[ii] = p + aPosition;
280  points[ii] = aParent->GetABPosition( points[ii] );
281  }
282 
283  GRClosedPoly( aClipBox, aDC, pointCount, &points[0], aFilled, aColor, aColor );
284 }
285 
286 
287 // TODO(snh): Remove the hard-coded count
288 #define SEGS_CNT 64 // number of segments to approximate a circle
289 
290 
291 // A helper function for D_CODE::ConvertShapeToPolygon(). Add a hole to a polygon
292 static void addHoleToPolygon( SHAPE_POLY_SET* aPolygon,
293  APERTURE_DEF_HOLETYPE aHoleShape,
294  const wxSize& aSize,
295  const wxPoint& aAnchorPos );
296 
297 
299 {
300  wxPoint initialpos;
301  wxPoint currpos;
302 
304 
305  switch( m_Shape )
306  {
307  case APT_CIRCLE: // creates only a circle with rectangular hole
308  TransformCircleToPolygon( m_Polygon, initialpos, m_Size.x >> 1, ARC_HIGH_DEF,
309  ERROR_INSIDE );
311  break;
312 
313  case APT_RECT:
315  currpos.x = m_Size.x / 2;
316  currpos.y = m_Size.y / 2;
317  initialpos = currpos;
318  m_Polygon.Append( VECTOR2I( currpos ) );
319  currpos.x -= m_Size.x;
320  m_Polygon.Append( VECTOR2I( currpos ) );
321  currpos.y -= m_Size.y;
322  m_Polygon.Append( VECTOR2I( currpos ) );
323  currpos.x += m_Size.x;
324  m_Polygon.Append( VECTOR2I( currpos ) );
325  currpos.y += m_Size.y;
326  m_Polygon.Append( VECTOR2I( currpos ) ); // close polygon
327  m_Polygon.Append( VECTOR2I( initialpos ) );
328 
330  break;
331 
332  case APT_OVAL:
333  {
335  int delta, radius;
336 
337  // we create an horizontal oval shape. then rotate if needed
338  if( m_Size.x > m_Size.y ) // horizontal oval
339  {
340  delta = ( m_Size.x - m_Size.y ) / 2;
341  radius = m_Size.y / 2;
342  }
343  else // vertical oval
344  {
345  delta = (m_Size.y - m_Size.x) / 2;
346  radius = m_Size.x / 2;
347  }
348 
349  currpos.y = radius;
350  initialpos = currpos;
351  m_Polygon.Append( VECTOR2I( currpos ) );
352 
353  // build the right arc of the shape
354  unsigned ii = 0;
355 
356  for( ; ii <= SEGS_CNT / 2; ii++ )
357  {
358  currpos = initialpos;
359  RotatePoint( &currpos, ii * 3600.0 / SEGS_CNT );
360  currpos.x += delta;
361  m_Polygon.Append( VECTOR2I( currpos ) );
362  }
363 
364  // build the left arc of the shape
365  for( ii = SEGS_CNT / 2; ii <= SEGS_CNT; ii++ )
366  {
367  currpos = initialpos;
368  RotatePoint( &currpos, ii * 3600.0 / SEGS_CNT );
369  currpos.x -= delta;
370  m_Polygon.Append( VECTOR2I( currpos ) );
371  }
372 
373  m_Polygon.Append( VECTOR2I( initialpos ) ); // close outline
374 
375  if( m_Size.y > m_Size.x ) // vertical oval, rotate polygon.
376  m_Polygon.Rotate( -M_PI / 2 );
377 
379  }
380 
381  break;
382 
383  case APT_POLYGON:
385  currpos.x = m_Size.x >> 1; // first point is on X axis
386  initialpos = currpos;
387 
388  // rs274x said: m_EdgesCount = 3 ... 12
389  if( m_EdgesCount < 3 )
390  m_EdgesCount = 3;
391 
392  if( m_EdgesCount > 12 )
393  m_EdgesCount = 12;
394 
395  for( int ii = 0; ii < m_EdgesCount; ii++ )
396  {
397  currpos = initialpos;
398  RotatePoint( &currpos, ii * 3600.0 / m_EdgesCount );
399  m_Polygon.Append( VECTOR2I( currpos ) );
400  }
401 
403 
404  if( m_Rotation ) // rotate polygonal shape:
405  {
406  double angle = m_Rotation * M_PI / 180;
407  m_Polygon.Rotate( angle, VECTOR2I( 0, 0 ) );
408  }
409 
410  break;
411 
412  case APT_MACRO:
413 
414  // TODO
415  break;
416  }
417 }
418 
419 
420 // The helper function for D_CODE::ConvertShapeToPolygon().
421 // Add a hole to a polygon
422 static void addHoleToPolygon( SHAPE_POLY_SET* aPolygon,
423  APERTURE_DEF_HOLETYPE aHoleShape,
424  const wxSize& aSize,
425  const wxPoint& aAnchorPos )
426 {
427  wxPoint currpos;
428  SHAPE_POLY_SET holeBuffer;
429 
430  if( aHoleShape == APT_DEF_ROUND_HOLE )
431  {
432  TransformCircleToPolygon( holeBuffer, wxPoint( 0, 0 ), aSize.x / 2, ARC_HIGH_DEF,
433  ERROR_INSIDE );
434  }
435  else if( aHoleShape == APT_DEF_RECT_HOLE )
436  {
437  holeBuffer.NewOutline();
438  currpos.x = aSize.x / 2;
439  currpos.y = aSize.y / 2;
440  holeBuffer.Append( VECTOR2I( currpos ) ); // link to hole and begin hole
441  currpos.x -= aSize.x;
442  holeBuffer.Append( VECTOR2I( currpos ) );
443  currpos.y -= aSize.y;
444  holeBuffer.Append( VECTOR2I( currpos ) );
445  currpos.x += aSize.x;
446  holeBuffer.Append( VECTOR2I( currpos ) );
447  currpos.y += aSize.y;
448  holeBuffer.Append( VECTOR2I( currpos ) ); // close hole
449  }
450 
451  aPolygon->BooleanSubtract( holeBuffer, SHAPE_POLY_SET::PM_FAST );
452  aPolygon->Fracture( SHAPE_POLY_SET::PM_FAST );
453 }
int OutlineCount() const
Return the number of vertices in a given outline/hole.
void GRFilledRect(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, const COLOR4D &Color, const COLOR4D &BgColor)
Definition: gr_basic.cpp:811
wxSize m_Size
Horizontal and vertical dimensions.
Definition: dcode.h:188
Definition: dcode.h:52
bool m_InUse
false if the aperture (previously defined) is not used to draw something
Definition: dcode.h:197
APERTURE_T m_Shape
shape ( Line, rectangle, circle , oval .. )
Definition: dcode.h:189
const VECTOR2I & CVertex(int aIndex, int aOutline, int aHole) const
Return the aGlobalIndex-th vertex in the poly set.
double m_Rotation
shape rotation in degrees
Definition: dcode.h:194
APERTURE_MACRO * m_Macro
no ownership, points to GERBER.m_aperture_macros element.
Definition: dcode.h:209
wxSize m_Drill
dimension of the hole (if any) (drill file)
Definition: dcode.h:191
int VertexCount(int aOutline=-1, int aHole=-1) const
Return the number of points in the shape poly set.
#define DCODE_DEFAULT_SIZE
Definition: dcode.cpp:38
void Rotate(double aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
void GRRect(EDA_RECT *aClipBox, wxDC *aDC, int x1, int y1, int x2, int y2, const COLOR4D &aColor)
Definition: gr_basic.cpp:774
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:229
VECTOR2< int > VECTOR2I
Definition: vector2d.h:623
Definition: dcode.h:51
APERTURE_DEF_HOLETYPE
Definition: dcode.h:61
bool m_Defined
false if the aperture is not defined in the header
Definition: dcode.h:199
D_CODE(int num_dcode)
Definition: dcode.cpp:59
static void addHoleToPolygon(SHAPE_POLY_SET *aPolygon, APERTURE_DEF_HOLETYPE aHoleShape, const wxSize &aSize, const wxPoint &aAnchorPos)
Definition: dcode.cpp:422
wxPoint GetABPosition(const wxPoint &aXYPosition) const
Return the image position of aPosition for this object.
void DrawFlashedPolygon(GERBER_DRAW_ITEM *aParent, EDA_RECT *aClipBox, wxDC *aDC, const COLOR4D &aColor, bool aFilled, const wxPoint &aPosition)
A helper function used to draw the polygon stored in m_PolyCorners.
Definition: dcode.cpp:266
Represent a set of closed polygons.
APERTURE_T
The set of all gerber aperture types allowed, according to page 16 of http://gerbv....
Definition: dcode.h:49
int m_Num_Dcode
D code value ( >= 10 )
Definition: dcode.h:190
void GRCircle(EDA_RECT *ClipBox, wxDC *DC, int xc, int yc, int r, int width, const COLOR4D &Color)
Definition: gr_basic.cpp:551
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aCornerBuffer, const wxPoint &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
#define SEGS_CNT
Definition: dcode.cpp:288
static const wxChar * ShowApertureType(APERTURE_T aType)
Return a character string telling what type of aperture type aType is.
Definition: dcode.cpp:87
void GRFillCSegm(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, const COLOR4D &Color)
Definition: gr_basic.cpp:369
int NewOutline()
Creates a new hole in a given outline.
void GRClosedPoly(EDA_RECT *ClipBox, wxDC *DC, int n, const wxPoint *Points, bool Fill, const COLOR4D &Color, const COLOR4D &BgColor)
Draw a closed polyline and fill it if Fill, in object space.
Definition: gr_basic.cpp:507
void Fracture(POLYGON_MODE aFastMode)
Convert a single outline slitted ("fractured") polygon into a set ouf outlines with holes.
void DrawApertureMacroShape(GERBER_DRAW_ITEM *aParent, EDA_RECT *aClipBox, wxDC *aDC, const COLOR4D &aColor, const wxPoint &aShapePos, bool aFilledShape)
Draw the primitive shape for flashed items.
APERTURE_DEF_HOLETYPE m_DrillShape
shape of the hole (0 = no hole, round = 1, rect = 2).
Definition: dcode.h:192
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
Handle the component boundary box.
Definition: eda_rect.h:42
SHAPE_POLY_SET m_Polygon
Definition: dcode.h:203
int m_EdgesCount
in aperture definition Polygon only: number of edges for the polygon
Definition: dcode.h:195
APERTURE_MACRO * GetMacro() const
Definition: dcode.h:125
constexpr int delta
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
void ConvertShapeToPolygon()
Convert a shape to an equivalent polygon.
Definition: dcode.cpp:298
void DrawFlashedShape(GERBER_DRAW_ITEM *aParent, EDA_RECT *aClipBox, wxDC *aDC, const COLOR4D &aColor, const wxPoint &aShapePos, bool aFilledShape)
Draw the dcode shape for flashed items.
Definition: dcode.cpp:148
int GetShapeDim(GERBER_DRAW_ITEM *aParent)
Calculate a value that can be used to evaluate the size of text when displaying the D-Code of an item...
int GetShapeDim(GERBER_DRAW_ITEM *aParent)
Calculate a value that can be used to evaluate the size of text when displaying the D-Code of an item...
Definition: dcode.cpp:116
~D_CODE()
Definition: dcode.cpp:66
void Clear_D_CODE_Data()
Definition: dcode.cpp:71
void GRFilledCircle(EDA_RECT *ClipBox, wxDC *DC, int x, int y, int r, int width, const COLOR4D &Color, const COLOR4D &BgColor)
Definition: gr_basic.cpp:575
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:103
void GRCSegm(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, int aPenSize, const COLOR4D &Color)
Definition: gr_basic.cpp:271