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