KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 The 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, see <https://www.gnu.org/licenses/>.
20 */
21
26
27#include <trigo.h>
28#include <gerbview_frame.h>
29#include <gerber_file_image.h>
30#include <eda_units.h>
32
33#define DCODE_DEFAULT_SIZE gerbIUScale.mmToIU( 0.1 )
34
35/* Format Gerber: NOTES:
36 * Tools and D_CODES
37 * tool number (identification of shapes)
38 * 1 to 999
39 *
40 * D_CODES:
41 * D01 ... D9 = command codes:
42 * D01 = activating light (pen down) while moving
43 * D02 = light extinction (pen up) while moving
44 * D03 = Flash
45 * D04 to D09 = non used
46 * D10 ... D999 = Identification Tool (Shape id)
47 *
48 * For tools defining a shape):
49 * DCode min = D10
50 * DCode max = 999
51 */
52
53
54D_CODE::D_CODE( int num_dcode )
55{
56 m_Num_Dcode = num_dcode;
58}
59
60
64
65
67{
71 m_Drill.x = m_Drill.y = 0;
73 m_InUse = false;
74 m_Defined = false;
75 m_Macro = nullptr;
77 m_EdgesCount = 0;
78 m_Polygon.RemoveAllContours();
79}
80
81
83{
84 const wxChar* ret;
85
86 switch( aType )
87 {
88 case APT_CIRCLE:
89 ret = wxT( "Round" ); break;
90
91 case APT_RECT:
92 ret = wxT( "Rect" ); break;
93
94 case APT_OVAL:
95 ret = wxT( "Oval" ); break;
96
97 case APT_POLYGON:
98 ret = wxT( "Poly" ); break;
99
100 case APT_MACRO:
101 ret = wxT( "Macro" ); break;
102
103 default:
104 ret = wxT( "???" ); break;
105 }
106
107 return ret;
108}
109
110
112{
113 int dim = 0;
114
115 switch( m_ApertType )
116 {
117 case APT_CIRCLE:
118 dim = m_Size.x;
119 break;
120
121 case APT_RECT:
122 case APT_OVAL:
123 dim = std::min( m_Size.x, m_Size.y );
124 break;
125
126 case APT_POLYGON:
127 dim = std::min( m_Size.x, m_Size.y );
128 break;
129
130 case APT_MACRO:
131 if( m_Macro )
132 {
133 if( m_Polygon.OutlineCount() == 0 )
134 ConvertShapeToPolygon( aParent );
135
136 BOX2I bbox = m_Polygon.BBox();
137 dim = std::min( bbox.GetWidth(), bbox.GetHeight() );
138 }
139 break;
140
141 default:
142 break;
143 }
144
145 return dim;
146}
147
148
149void D_CODE::DrawFlashedShape( const GERBER_DRAW_ITEM* aParent, wxDC* aDC, const COLOR4D& aColor,
150 const VECTOR2I& aShapePos, bool aFilledShape )
151{
152 int radius;
153
154 switch( m_ApertType )
155 {
156 case APT_CIRCLE:
157 radius = m_Size.x >> 1;
158
159 if( !aFilledShape )
160 {
161 GRCircle( aDC, aParent->GetABPosition(aShapePos), radius, 0, aColor );
162 }
163 else if( m_DrillShape == APT_DEF_NO_HOLE )
164 {
165 GRFilledCircle( aDC, aParent->GetABPosition(aShapePos), radius, 0, aColor, aColor );
166 }
167 else if( m_DrillShape == APT_DEF_ROUND_HOLE ) // round hole in shape
168 {
169 int width = (m_Size.x - m_Drill.x ) / 2;
170 GRCircle( aDC, aParent->GetABPosition(aShapePos), radius - (width / 2), width, aColor );
171 }
172 else // rectangular hole
173 {
174 if( m_Polygon.OutlineCount() == 0 )
175 ConvertShapeToPolygon( aParent );
176
177 DrawFlashedPolygon( aParent, aDC, aColor, aFilledShape, aShapePos );
178 }
179
180 break;
181
182 case APT_RECT:
183 {
184 VECTOR2I start;
185 start.x = aShapePos.x - m_Size.x / 2;
186 start.y = aShapePos.y - m_Size.y / 2;
187 VECTOR2I end = start + m_Size;
188 start = aParent->GetABPosition( start );
189 end = aParent->GetABPosition( end );
190
191 if( !aFilledShape )
192 {
193 GRRect( aDC, start, end, 0, aColor );
194 }
195 else if( m_DrillShape == APT_DEF_NO_HOLE )
196 {
197 GRFilledRect( aDC, start, end, 0, aColor, aColor );
198 }
199 else
200 {
201 if( m_Polygon.OutlineCount() == 0 )
202 ConvertShapeToPolygon( aParent );
203
204 DrawFlashedPolygon( aParent, aDC, aColor, aFilledShape, aShapePos );
205 }
206 }
207 break;
208
209 case APT_OVAL:
210 {
211 VECTOR2I start = aShapePos;
212 VECTOR2I end = aShapePos;
213
214 if( m_Size.x > m_Size.y ) // horizontal oval
215 {
216 int delta = ( m_Size.x - m_Size.y ) / 2;
217 start.x -= delta;
218 end.x += delta;
219 radius = m_Size.y; // Width in fact
220 }
221 else // vertical oval
222 {
223 int delta = ( m_Size.y - m_Size.x ) / 2;
224 start.y -= delta;
225 end.y += delta;
226 radius = m_Size.x; // Width in fact
227 }
228
229 start = aParent->GetABPosition( start );
230 end = aParent->GetABPosition( end );
231
232 if( !aFilledShape )
233 {
234 GRCSegm( aDC, start, end, radius, aColor );
235 }
236 else if( m_DrillShape == APT_DEF_NO_HOLE )
237 {
238 GRFilledSegment( aDC, start, end, radius, aColor );
239 }
240 else
241 {
242 if( m_Polygon.OutlineCount() == 0 )
243 ConvertShapeToPolygon( aParent );
244
245 DrawFlashedPolygon( aParent, aDC, aColor, aFilledShape, aShapePos );
246 }
247 }
248
249 break;
250
251 case APT_MACRO:
252 case APT_POLYGON:
253 if( m_Polygon.OutlineCount() == 0 )
254 ConvertShapeToPolygon( aParent );
255
256 DrawFlashedPolygon( aParent, aDC, aColor, aFilledShape, aShapePos );
257 break;
258 }
259}
260
261
262void D_CODE::DrawFlashedPolygon( const GERBER_DRAW_ITEM* aParent, wxDC* aDC,
263 const COLOR4D& aColor,
264 bool aFilled, const VECTOR2I& aPosition )
265{
266 if( m_Polygon.OutlineCount() == 0 )
267 return;
268
269 int pointCount = m_Polygon.VertexCount();
270 std::vector<VECTOR2I> points;
271 points.reserve( pointCount );
272
273 for( int ii = 0; ii < pointCount; ii++ )
274 {
275 VECTOR2I p( m_Polygon.CVertex( ii ).x, m_Polygon.CVertex( ii ).y );
276 points[ii] = p + aPosition;
277 points[ii] = aParent->GetABPosition( points[ii] );
278 }
279
280 GRClosedPoly( aDC, pointCount, &points[0], aFilled, aColor );
281}
282
283
284// TODO(snh): Remove the hard-coded count
285#define SEGS_CNT 64 // number of segments to approximate a circle
286
287
288// A helper function for D_CODE::ConvertShapeToPolygon(). Add a hole to a polygon
289static void addHoleToPolygon( SHAPE_POLY_SET* aPolygon, APERTURE_DEF_HOLETYPE aHoleShape,
290 const VECTOR2I& aSize, const VECTOR2I& aAnchorPos );
291
292
294{
295 VECTOR2I initialpos;
296 VECTOR2I currpos;
297
298 m_Polygon.RemoveAllContours();
299
300 switch( m_ApertType )
301 {
302 case APT_CIRCLE: // creates only a circle with rectangular hole
303 {
304 // Adjust the allowed approx error to convert arcs to segments:
305 int arc_to_seg_error = gerbIUScale.mmToIU( 0.005 ); // Allow 5 microns
306 TransformCircleToPolygon( m_Polygon, initialpos, m_Size.x >> 1, arc_to_seg_error,
307 ERROR_INSIDE );
309 }
310 break;
311
312 case APT_RECT:
313 m_Polygon.NewOutline();
314 currpos.x = m_Size.x / 2;
315 currpos.y = m_Size.y / 2;
316 initialpos = currpos;
317 m_Polygon.Append( VECTOR2I( currpos ) );
318 currpos.x -= m_Size.x;
319 m_Polygon.Append( VECTOR2I( currpos ) );
320 currpos.y -= m_Size.y;
321 m_Polygon.Append( VECTOR2I( currpos ) );
322 currpos.x += m_Size.x;
323 m_Polygon.Append( VECTOR2I( currpos ) );
324 currpos.y += m_Size.y;
325 m_Polygon.Append( VECTOR2I( currpos ) ); // close polygon
326 m_Polygon.Append( VECTOR2I( initialpos ) );
327
329 break;
330
331 case APT_OVAL:
332 {
333 m_Polygon.NewOutline();
334 int delta, radius;
335
336 // we create an horizontal oval shape. then rotate if needed
337 if( m_Size.x > m_Size.y ) // horizontal oval
338 {
339 delta = ( m_Size.x - m_Size.y ) / 2;
340 radius = m_Size.y / 2;
341 }
342 else // vertical oval
343 {
344 delta = (m_Size.y - m_Size.x) / 2;
345 radius = m_Size.x / 2;
346 }
347
348 currpos.y = radius;
349 initialpos = currpos;
350 m_Polygon.Append( VECTOR2I( currpos ) );
351
352 // build the right arc of the shape
353 unsigned ii = 0;
354
355 for( ; ii <= SEGS_CNT / 2; ii++ )
356 {
357 currpos = initialpos;
358 RotatePoint( currpos, ANGLE_360 * ii / SEGS_CNT );
359 currpos.x += delta;
360 m_Polygon.Append( VECTOR2I( currpos ) );
361 }
362
363 // build the left arc of the shape
364 for( ii = SEGS_CNT / 2; ii <= SEGS_CNT; ii++ )
365 {
366 currpos = initialpos;
367 RotatePoint( currpos, ANGLE_360 * ii / SEGS_CNT );
368 currpos.x -= delta;
369 m_Polygon.Append( currpos );
370 }
371
372 m_Polygon.Append( initialpos ); // close outline
373
374 if( m_Size.y > m_Size.x ) // vertical oval, rotate polygon.
375 m_Polygon.Rotate( ANGLE_90 );
376
378 }
379 break;
380
381 case APT_POLYGON:
382 m_Polygon.NewOutline();
383 currpos.x = m_Size.x >> 1; // first point is on X axis
384 initialpos = currpos;
385
386 // rs274x said: m_EdgesCount = 3 ... 12
387 if( m_EdgesCount < 3 )
388 m_EdgesCount = 3;
389
390 if( m_EdgesCount > 12 )
391 m_EdgesCount = 12;
392
393 for( int ii = 0; ii < m_EdgesCount; ii++ )
394 {
395 currpos = initialpos;
396 RotatePoint( currpos, ANGLE_360 * ii / m_EdgesCount );
397 m_Polygon.Append( currpos );
398 }
399
401
402 if( !m_Rotation.IsZero() ) // rotate polygonal shape:
403 m_Polygon.Rotate( -m_Rotation );
404
405 break;
406
407 case APT_MACRO:
408 APERTURE_MACRO* macro = GetMacro();
409 SHAPE_POLY_SET* macroShape = macro->GetApertureMacroShape( aParent, initialpos );
410 m_Polygon.Append( *macroShape );
411 break;
412 }
413}
414
415
416// The helper function for D_CODE::ConvertShapeToPolygon().
417// Add a hole to a polygon
418static void addHoleToPolygon( SHAPE_POLY_SET* aPolygon, APERTURE_DEF_HOLETYPE aHoleShape,
419 const VECTOR2I& aSize, const VECTOR2I& aAnchorPos )
420{
421 VECTOR2I currpos;
422 SHAPE_POLY_SET holeBuffer;
423
424 if( aHoleShape == APT_DEF_ROUND_HOLE )
425 {
426 // Adjust the allowed approx error to convert arcs to segments:
427 int arc_to_seg_error = gerbIUScale.mmToIU( 0.005 ); // Allow 5 microns
428 TransformCircleToPolygon( holeBuffer, VECTOR2I( 0, 0 ), aSize.x / 2, arc_to_seg_error,
429 ERROR_INSIDE );
430 }
431 else if( aHoleShape == APT_DEF_RECT_HOLE )
432 {
433 holeBuffer.NewOutline();
434 currpos.x = aSize.x / 2;
435 currpos.y = aSize.y / 2;
436 holeBuffer.Append( VECTOR2I( currpos ) ); // link to hole and begin hole
437 currpos.x -= aSize.x;
438 holeBuffer.Append( VECTOR2I( currpos ) );
439 currpos.y -= aSize.y;
440 holeBuffer.Append( VECTOR2I( currpos ) );
441 currpos.x += aSize.x;
442 holeBuffer.Append( VECTOR2I( currpos ) );
443 currpos.y += aSize.y;
444 holeBuffer.Append( VECTOR2I( currpos ) ); // close hole
445 }
446
447 aPolygon->BooleanSubtract( holeBuffer );
448 aPolygon->Fracture();
449}
@ ERROR_INSIDE
constexpr EDA_IU_SCALE gerbIUScale
Definition base_units.h:120
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
Support the "aperture macro" defined within standard RS274X.
SHAPE_POLY_SET * GetApertureMacroShape(const GERBER_DRAW_ITEM *aParent, const VECTOR2I &aShapePos)
Calculate the primitive shape for flashed items.
constexpr size_type GetWidth() const
Definition box2.h:210
constexpr size_type GetHeight() const
Definition box2.h:211
APERTURE_MACRO * GetMacro() const
Definition dcode.h:132
void Clear_D_CODE_Data()
Definition dcode.cpp:66
void DrawFlashedShape(const GERBER_DRAW_ITEM *aParent, wxDC *aDC, const COLOR4D &aColor, const VECTOR2I &aShapePos, bool aFilledShape)
Draw the dcode shape for flashed items.
Definition dcode.cpp:149
int m_Num_Dcode
D code value ( >= 10 )
Definition dcode.h:200
D_CODE(int num_dcode)
Definition dcode.cpp:54
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:111
~D_CODE()
Definition dcode.cpp:61
void DrawFlashedPolygon(const GERBER_DRAW_ITEM *aParent, wxDC *aDC, const COLOR4D &aColor, bool aFilled, const VECTOR2I &aPosition)
A helper function used to draw the polygon stored in m_PolyCorners.
Definition dcode.cpp:262
EDA_ANGLE m_Rotation
shape rotation
Definition dcode.h:204
VECTOR2I m_Drill
dimension of the hole (if any) (drill file)
Definition dcode.h:201
int m_EdgesCount
in aperture definition Polygon only: number of edges for the polygon
Definition dcode.h:205
static const wxChar * ShowApertureType(APERTURE_T aType)
Return a character string telling what type of aperture type aType is.
Definition dcode.cpp:82
VECTOR2I m_Size
Horizontal and vertical dimensions.
Definition dcode.h:197
APERTURE_T m_ApertType
Aperture type ( Line, rectangle, circle, oval poly, macro )
Definition dcode.h:198
bool m_Defined
false if the aperture is not defined in the header
Definition dcode.h:209
APERTURE_DEF_HOLETYPE m_DrillShape
shape of the hole (0 = no hole, round = 1, rect = 2).
Definition dcode.h:202
SHAPE_POLY_SET m_Polygon
Definition dcode.h:213
bool m_InUse
false if the aperture (previously defined) is not used to draw something
Definition dcode.h:207
APERTURE_MACRO * m_Macro
no ownership, points to GERBER.m_aperture_macros element.
Definition dcode.h:219
void ConvertShapeToPolygon(const GERBER_DRAW_ITEM *aParent)
Convert a shape to an equivalent polygon.
Definition dcode.cpp:293
VECTOR2I GetABPosition(const VECTOR2I &aXYPosition) const
Return the image position of aPosition for this object.
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
Represent a set of closed polygons.
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)
int NewOutline()
Creates a new empty polygon in the set and returns its index.
void Fracture(bool aSimplify=true)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &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:285
static void addHoleToPolygon(SHAPE_POLY_SET *aPolygon, APERTURE_DEF_HOLETYPE aHoleShape, const VECTOR2I &aSize, const VECTOR2I &aAnchorPos)
Definition dcode.cpp:418
#define DCODE_DEFAULT_SIZE
Definition dcode.cpp:33
APERTURE_DEF_HOLETYPE
Definition dcode.h:56
@ APT_DEF_NO_HOLE
Definition dcode.h:57
@ APT_DEF_ROUND_HOLE
Definition dcode.h:58
@ APT_DEF_RECT_HOLE
Definition dcode.h:59
APERTURE_T
The set of all gerber aperture types allowed from ADD dcode command, like ADD11C,0....
Definition dcode.h:44
@ APT_RECT
Definition dcode.h:46
@ APT_OVAL
Definition dcode.h:47
@ APT_POLYGON
Definition dcode.h:48
@ APT_CIRCLE
Definition dcode.h:45
@ APT_MACRO
Definition dcode.h:50
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:411
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:413
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:417
void GRRect(wxDC *DC, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, const COLOR4D &aColor)
Definition gr_basic.cpp:397
void GRCSegm(wxDC *DC, const VECTOR2I &A, const VECTOR2I &B, int width, const COLOR4D &Color)
Definition gr_basic.cpp:201
void GRCircle(wxDC *aDC, const VECTOR2I &aPos, int aRadius, int aWidth, const COLOR4D &aColor)
Definition gr_basic.cpp:358
void GRFilledSegment(wxDC *aDC, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, const COLOR4D &aColor)
Definition gr_basic.cpp:278
void GRClosedPoly(wxDC *DC, int n, const VECTOR2I *Points, bool Fill, const COLOR4D &Color)
Draw a closed polyline and fill it if Fill, in object space.
Definition gr_basic.cpp:352
void GRFilledRect(wxDC *DC, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, const COLOR4D &aColor, const COLOR4D &aBgColor)
Definition gr_basic.cpp:404
void GRFilledCircle(wxDC *aDC, const VECTOR2I &aPos, int aRadius, int aWidth, const COLOR4D &aStrokeColor, const COLOR4D &aFillColor)
Draw a circle onto the drawing context aDC centered at the user coordinates (x,y).
Definition gr_basic.cpp:370
int radius
VECTOR2I end
int delta
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:225
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683