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 <stambaughw@verizon.net>
6  * Copyright (C) 1992-2016 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 /***************/
60 /* Class DCODE */
61 /***************/
62 
63 
64 D_CODE::D_CODE( int num_dcode )
65 {
66  m_Num_Dcode = num_dcode;
68 }
69 
70 
72 {
73 }
74 
75 
77 {
81  m_Drill.x = m_Drill.y = 0;
83  m_InUse = false;
84  m_Defined = false;
85  m_Macro = NULL;
86  m_Rotation = 0.0;
87  m_EdgesCount = 0;
89 }
90 
91 
92 const wxChar* D_CODE::ShowApertureType( APERTURE_T aType )
93 {
94  const wxChar* ret;
95 
96  switch( aType )
97  {
98  case APT_CIRCLE:
99  ret = wxT( "Round" ); break;
100 
101  case APT_RECT:
102  ret = wxT( "Rect" ); break;
103 
104  case APT_OVAL:
105  ret = wxT( "Oval" ); break;
106 
107  case APT_POLYGON:
108  ret = wxT( "Poly" ); break;
109 
110  case APT_MACRO:
111  ret = wxT( "Macro" ); break;
112 
113  default:
114  ret = wxT( "???" ); break;
115  }
116 
117  return ret;
118 }
119 
121 {
122  int dim = -1;
123  switch( m_Shape )
124  {
125  case APT_CIRCLE:
126  dim = m_Size.x;
127  break;
128 
129  case APT_RECT:
130  case APT_OVAL:
131  dim = std::min( m_Size.x, m_Size.y );
132  break;
133 
134  case APT_POLYGON:
135  dim = std::min( m_Size.x, m_Size.y );
136  break;
137 
138  case APT_MACRO:
139  if( m_Macro )
140  dim = m_Macro->GetShapeDim( aParent );
141  break;
142 
143  default:
144  break;
145  }
146 
147  return dim;
148 }
149 
150 
152  EDA_RECT* aClipBox, wxDC* aDC, COLOR4D aColor,
153  wxPoint aShapePos, bool aFilledShape )
154 {
155  int radius;
156 
157  switch( m_Shape )
158  {
159  case APT_MACRO:
160  GetMacro()->DrawApertureMacroShape( aParent, aClipBox, aDC, aColor,
161  aShapePos, aFilledShape);
162  break;
163 
164  case APT_CIRCLE:
165  radius = m_Size.x >> 1;
166  if( !aFilledShape )
167  GRCircle( aClipBox, aDC, aParent->GetABPosition(aShapePos), radius, 0, aColor );
168  else
170  {
171  GRFilledCircle( aClipBox, aDC, aParent->GetABPosition(aShapePos),
172  radius, aColor );
173  }
174  else if( m_DrillShape == APT_DEF_ROUND_HOLE ) // round hole in shape
175  {
176  int width = (m_Size.x - m_Drill.x ) / 2;
177  GRCircle( aClipBox, aDC, aParent->GetABPosition(aShapePos),
178  radius - (width / 2), width, aColor );
179  }
180  else // rectangular hole
181  {
182  if( m_Polygon.OutlineCount() == 0 )
184 
185  DrawFlashedPolygon( aParent, aClipBox, aDC, aColor, aFilledShape, aShapePos );
186  }
187  break;
188 
189  case APT_RECT:
190  {
191  wxPoint start;
192  start.x = aShapePos.x - m_Size.x / 2;
193  start.y = aShapePos.y - m_Size.y / 2;
194  wxPoint end = start + m_Size;
195  start = aParent->GetABPosition( start );
196  end = aParent->GetABPosition( end );
197 
198  if( !aFilledShape )
199  {
200  GRRect( aClipBox, aDC, start.x, start.y, end.x, end.y, 0, aColor );
201  }
202  else if( m_DrillShape == APT_DEF_NO_HOLE )
203  {
204  GRFilledRect( aClipBox, aDC, start.x, start.y, end.x, end.y, 0, aColor, aColor );
205  }
206  else
207  {
208  if( m_Polygon.OutlineCount() == 0 )
210 
211  DrawFlashedPolygon( aParent, aClipBox, aDC, aColor, aFilledShape, aShapePos );
212  }
213  }
214  break;
215 
216  case APT_OVAL:
217  {
218  wxPoint start = aShapePos;
219  wxPoint end = aShapePos;
220 
221  if( m_Size.x > m_Size.y ) // horizontal oval
222  {
223  int delta = (m_Size.x - m_Size.y) / 2;
224  start.x -= delta;
225  end.x += delta;
226  radius = m_Size.y; // Width in fact
227  }
228  else // vertical oval
229  {
230  int delta = (m_Size.y - m_Size.x) / 2;
231  start.y -= delta;
232  end.y += delta;
233  radius = m_Size.x; // Width in fact
234  }
235 
236  start = aParent->GetABPosition( start );
237  end = aParent->GetABPosition( end );
238 
239  if( !aFilledShape )
240  {
241  GRCSegm( aClipBox, aDC, start.x, start.y, end.x, end.y, radius, aColor );
242  }
243  else if( m_DrillShape == APT_DEF_NO_HOLE )
244  {
245  GRFillCSegm( aClipBox, aDC, start.x, start.y, end.x, end.y, radius, aColor );
246  }
247  else
248  {
249  if( m_Polygon.OutlineCount() == 0 )
251 
252  DrawFlashedPolygon( aParent, aClipBox, aDC, aColor, aFilledShape, aShapePos );
253  }
254  }
255  break;
256 
257  case APT_POLYGON:
258  if( m_Polygon.OutlineCount() == 0 )
260 
261  DrawFlashedPolygon( aParent, aClipBox, aDC, aColor, aFilledShape, aShapePos );
262  break;
263  }
264 }
265 
266 
268  EDA_RECT* aClipBox, wxDC* aDC,
269  COLOR4D aColor, bool aFilled,
270  const wxPoint& aPosition )
271 {
272  if( m_Polygon.OutlineCount() == 0 )
273  return;
274 
275  int pointCount = m_Polygon.VertexCount();
276  std::vector<wxPoint> points;
277  points.reserve( pointCount );
278 
279  for( int ii = 0; ii < pointCount; ii++ )
280  {
281  wxPoint p( m_Polygon.CVertex( ii ).x, m_Polygon.CVertex( ii ).y );
282  points[ii] = p + aPosition;
283  points[ii] = aParent->GetABPosition( points[ii] );
284  }
285 
286  GRClosedPoly( aClipBox, aDC, pointCount, &points[0], aFilled, aColor, aColor );
287 }
288 
289 // TODO(snh): Remove the hard-coded count
290 #define SEGS_CNT 64 // number of segments to approximate a circle
291 
292 
293 // A helper function for D_CODE::ConvertShapeToPolygon(). Add a hole to a polygon
294 static void addHoleToPolygon( SHAPE_POLY_SET* aPolygon,
295  APERTURE_DEF_HOLETYPE aHoleShape,
296  wxSize aSize,
297  wxPoint aAnchorPos );
298 
299 
301 {
302  wxPoint initialpos;
303  wxPoint currpos;
304 
306 
307  switch( m_Shape )
308  {
309  case APT_CIRCLE: // creates only a circle with rectangular hole
310  TransformCircleToPolygon( m_Polygon, initialpos, m_Size.x >> 1, ARC_HIGH_DEF,
311  ERROR_INSIDE );
313  break;
314 
315  case APT_RECT:
317  currpos.x = m_Size.x / 2;
318  currpos.y = m_Size.y / 2;
319  initialpos = currpos;
320  m_Polygon.Append( VECTOR2I( currpos ) );
321  currpos.x -= m_Size.x;
322  m_Polygon.Append( VECTOR2I( currpos ) );
323  currpos.y -= m_Size.y;
324  m_Polygon.Append( VECTOR2I( currpos ) );
325  currpos.x += m_Size.x;
326  m_Polygon.Append( VECTOR2I( currpos ) );
327  currpos.y += m_Size.y;
328  m_Polygon.Append( VECTOR2I( currpos ) ); // close polygon
329  m_Polygon.Append( VECTOR2I( initialpos ) );
330 
332  break;
333 
334  case APT_OVAL:
335  {
337  int delta, radius;
338 
339  // we create an horizontal oval shape. then rotate if needed
340  if( m_Size.x > m_Size.y ) // horizontal oval
341  {
342  delta = (m_Size.x - m_Size.y) / 2;
343  radius = m_Size.y / 2;
344  }
345  else // vertical oval
346  {
347  delta = (m_Size.y - m_Size.x) / 2;
348  radius = m_Size.x / 2;
349  }
350 
351  currpos.y = radius;
352  initialpos = currpos;
353  m_Polygon.Append( VECTOR2I( currpos ) );
354 
355  // build the right arc of the shape
356  unsigned ii = 0;
357 
358  for( ; ii <= SEGS_CNT / 2; ii++ )
359  {
360  currpos = initialpos;
361  RotatePoint( &currpos, ii * 3600.0 / SEGS_CNT );
362  currpos.x += delta;
363  m_Polygon.Append( VECTOR2I( currpos ) );
364  }
365 
366  // build the left arc of the shape
367  for( ii = SEGS_CNT / 2; ii <= SEGS_CNT; ii++ )
368  {
369  currpos = initialpos;
370  RotatePoint( &currpos, ii * 3600.0 / SEGS_CNT );
371  currpos.x -= delta;
372  m_Polygon.Append( VECTOR2I( currpos ) );
373  }
374 
375  m_Polygon.Append( VECTOR2I( initialpos ) ); // close outline
376 
377  if( m_Size.y > m_Size.x ) // vertical oval, rotate polygon.
378  m_Polygon.Rotate( -M_PI / 2 );
379 
381  }
382  break;
383 
384  case APT_POLYGON:
386  currpos.x = m_Size.x >> 1; // first point is on X axis
387  initialpos = currpos;
388 
389  // rs274x said: m_EdgesCount = 3 ... 12
390  if( m_EdgesCount < 3 )
391  m_EdgesCount = 3;
392 
393  if( m_EdgesCount > 12 )
394  m_EdgesCount = 12;
395 
396  for( int ii = 0; ii < m_EdgesCount; ii++ )
397  {
398  currpos = initialpos;
399  RotatePoint( &currpos, ii * 3600.0 / m_EdgesCount );
400  m_Polygon.Append( VECTOR2I( currpos ) );
401  }
402 
404 
405  if( m_Rotation ) // rotate polygonal shape:
406  {
407  double angle = m_Rotation * M_PI / 180;
408  m_Polygon.Rotate( angle, VECTOR2I( 0, 0 ) );
409  }
410 
411  break;
412 
413  case APT_MACRO:
414 
415  // TODO
416  break;
417  }
418 }
419 
420 
421 // The helper function for D_CODE::ConvertShapeToPolygon().
422 // Add a hole to a polygon
423 static void addHoleToPolygon( SHAPE_POLY_SET* aPolygon,
424  APERTURE_DEF_HOLETYPE aHoleShape,
425  wxSize aSize,
426  wxPoint aAnchorPos )
427 {
428  wxPoint currpos;
429  SHAPE_POLY_SET holeBuffer;
430 
431  if( aHoleShape == APT_DEF_ROUND_HOLE )
432  {
433  TransformCircleToPolygon( holeBuffer, wxPoint( 0, 0 ), aSize.x / 2, ARC_HIGH_DEF,
434  ERROR_INSIDE );
435  }
436  else if( aHoleShape == APT_DEF_RECT_HOLE )
437  {
438  holeBuffer.NewOutline();
439  currpos.x = aSize.x / 2;
440  currpos.y = aSize.y / 2;
441  holeBuffer.Append( VECTOR2I( currpos ) ); // link to hole and begin hole
442  currpos.x -= aSize.x;
443  holeBuffer.Append( VECTOR2I( currpos ) );
444  currpos.y -= aSize.y;
445  holeBuffer.Append( VECTOR2I( currpos ) );
446  currpos.x += aSize.x;
447  holeBuffer.Append( VECTOR2I( currpos ) );
448  currpos.y += aSize.y;
449  holeBuffer.Append( VECTOR2I( currpos ) ); // close hole
450  }
451 
452  aPolygon->BooleanSubtract( holeBuffer, SHAPE_POLY_SET::PM_FAST );
453  aPolygon->Fracture( SHAPE_POLY_SET::PM_FAST );
454 }
int OutlineCount() const
Returns the number of outlines in the set
static void addHoleToPolygon(SHAPE_POLY_SET *aPolygon, APERTURE_DEF_HOLETYPE aHoleShape, wxSize aSize, wxPoint aAnchorPos)
Definition: dcode.cpp:423
wxSize m_Size
Horizontal and vertical dimensions.
Definition: dcode.h:94
Definition: dcode.h:53
bool m_InUse
false if the aperure (previously defined) is not used to draw something
Definition: dcode.h:102
APERTURE_T m_Shape
shape ( Line, rectangle, circle , oval .. )
Definition: dcode.h:95
void DrawApertureMacroShape(GERBER_DRAW_ITEM *aParent, EDA_RECT *aClipBox, wxDC *aDC, COLOR4D aColor, wxPoint aShapePos, bool aFilledShape)
Function DrawApertureMacroShape Draw the primitive shape for flashed items.
const VECTOR2I & CVertex(int aIndex, int aOutline, int aHole) const
Returns the index-th vertex in a given hole outline within a given outline
double m_Rotation
shape rotation in degrees
Definition: dcode.h:99
APERTURE_MACRO * m_Macro
no ownership, points to
Definition: dcode.h:85
void GRFilledRect(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, COLOR4D Color, COLOR4D BgColor)
Definition: gr_basic.cpp:882
wxSize m_Drill
dimension of the hole (if any) (draill file)
Definition: dcode.h:97
int VertexCount(int aOutline=-1, int aHole=-1) const
Returns the number of vertices in a given outline/hole
#define DCODE_DEFAULT_SIZE
Definition: dcode.cpp:38
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:310
void Rotate(double aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Function Rotate rotates all vertices by a given angle.
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:208
VECTOR2< int > VECTOR2I
Definition: vector2d.h:594
void GRFilledCircle(EDA_RECT *ClipBox, wxDC *DC, int x, int y, int r, int width, COLOR4D Color, COLOR4D BgColor)
Definition: gr_basic.cpp:617
Definition: dcode.h:52
APERTURE_DEF_HOLETYPE
Definition: dcode.h:62
bool m_Defined
false if the aperture is not defined in the header
Definition: dcode.h:104
D_CODE(int num_dcode)
Definition: dcode.cpp:64
void GRRect(EDA_RECT *aClipBox, wxDC *aDC, int x1, int y1, int x2, int y2, COLOR4D aColor)
Definition: gr_basic.cpp:842
wxPoint GetABPosition(const wxPoint &aXYPosition) const
Function GetABPosition returns the image position of aPosition for this object.
#define NULL
SHAPE_POLY_SET.
void GRFillCSegm(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, COLOR4D Color)
Definition: gr_basic.cpp:413
APERTURE_T
Enum APERTURE_T is the set of all gerber aperture types allowed, according to page 16 of http://gerbv...
Definition: dcode.h:50
int m_Num_Dcode
D code value ( >= 10 )
Definition: dcode.h:96
#define SEGS_CNT
Definition: dcode.cpp:290
static const wxChar * ShowApertureType(APERTURE_T aType)
Function ShowApertureType returns a character string telling what type of aperture type aType is.
Definition: dcode.cpp:92
void DrawFlashedPolygon(GERBER_DRAW_ITEM *aParent, EDA_RECT *aClipBox, wxDC *aDC, COLOR4D aColor, bool aFilled, const wxPoint &aPosition)
Function DrawFlashedPolygon a helper function used to draw the polygon stored ion m_PolyCorners Draw ...
Definition: dcode.cpp:267
int NewOutline()
Creates a new empty polygon in the set and returns its index
void Fracture(POLYGON_MODE aFastMode)
Converts a set of polygons with holes to a singe outline with "slits"/"fractures" connecting the oute...
APERTURE_DEF_HOLETYPE m_DrillShape
shape of the hole (0 = no hole, round = 1, rect = 2) */
Definition: dcode.h:98
void TransformCircleToPolygon(SHAPE_POLY_SET &aCornerBuffer, wxPoint aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc)
Function TransformCircleToPolygon convert a circle to a polygon, using multiple straight lines.
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:151
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
void GRCircle(EDA_RECT *ClipBox, wxDC *DC, int xc, int yc, int r, int width, COLOR4D Color)
Definition: gr_basic.cpp:594
void RemoveAllContours()
Removes all outlines & holes (clears) the polygon set.
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
SHAPE_POLY_SET m_Polygon
Definition: dcode.h:107
int m_EdgesCount
in aperture definition Polygon only: number of edges for the polygon
Definition: dcode.h:100
APERTURE_MACRO * GetMacro() const
Definition: dcode.h:157
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Performs boolean polyset difference For aFastMode meaning, see function booleanOp
void ConvertShapeToPolygon()
Function ConvertShapeToPolygon convert a shape to an equivalent polygon.
Definition: dcode.cpp:300
int GetShapeDim(GERBER_DRAW_ITEM *aParent)
Function GetShapeDim Calculate a value that can be used to evaluate the size of text when displaying ...
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:550
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:120
~D_CODE()
Definition: dcode.cpp:71
void Clear_D_CODE_Data()
Definition: dcode.cpp:76
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)
COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:100