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-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_Shape )
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_Shape )
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_Shape )
305 {
306 case APT_CIRCLE: // creates only a circle with rectangular hole
308 ERROR_INSIDE );
310 break;
311
312 case APT_RECT:
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 {
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.
376
378 }
379 break;
380
381 case APT_POLYGON:
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:
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 TransformCircleToPolygon( holeBuffer, VECTOR2I( 0, 0 ), aSize.x / 2, ARC_HIGH_DEF,
427 ERROR_INSIDE );
428 }
429 else if( aHoleShape == APT_DEF_RECT_HOLE )
430 {
431 holeBuffer.NewOutline();
432 currpos.x = aSize.x / 2;
433 currpos.y = aSize.y / 2;
434 holeBuffer.Append( VECTOR2I( currpos ) ); // link to hole and begin hole
435 currpos.x -= aSize.x;
436 holeBuffer.Append( VECTOR2I( currpos ) );
437 currpos.y -= aSize.y;
438 holeBuffer.Append( VECTOR2I( currpos ) );
439 currpos.x += aSize.x;
440 holeBuffer.Append( VECTOR2I( currpos ) );
441 currpos.y += aSize.y;
442 holeBuffer.Append( VECTOR2I( currpos ) ); // close hole
443 }
444
445 aPolygon->BooleanSubtract( holeBuffer, SHAPE_POLY_SET::PM_FAST );
447}
constexpr int ARC_HIGH_DEF
Definition: base_units.h:121
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.
coord_type GetHeight() const
Definition: box2.h:188
coord_type GetWidth() const
Definition: box2.h:187
APERTURE_MACRO * GetMacro() const
Definition: dcode.h:124
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:191
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:195
wxSize m_Drill
dimension of the hole (if any) (drill file)
Definition: dcode.h:192
int m_EdgesCount
in aperture definition Polygon only: number of edges for the polygon
Definition: dcode.h:196
static const wxChar * ShowApertureType(APERTURE_T aType)
Return a character string telling what type of aperture type aType is.
Definition: dcode.cpp:86
APERTURE_T m_Shape
shape ( Line, rectangle, circle , oval .. )
Definition: dcode.h:190
bool m_Defined
false if the aperture is not defined in the header
Definition: dcode.h:200
APERTURE_DEF_HOLETYPE m_DrillShape
shape of the hole (0 = no hole, round = 1, rect = 2).
Definition: dcode.h:193
SHAPE_POLY_SET m_Polygon
Definition: dcode.h:204
bool m_InUse
false if the aperture (previously defined) is not used to draw something
Definition: dcode.h:198
APERTURE_MACRO * m_Macro
no ownership, points to GERBER.m_aperture_macros element.
Definition: dcode.h:210
wxSize m_Size
Horizontal and vertical dimensions.
Definition: dcode.h:189
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:169
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 BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
void Fracture(POLYGON_MODE aFastMode)
Convert a single outline slitted ("fractured") polygon into a set ouf outlines with holes.
int VertexCount(int aOutline=-1, int aHole=-1) const
Return the number of points in the shape poly set.
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...
int NewOutline()
Creates a new hole in a given outline.
const VECTOR2I & CVertex(int aIndex, int aOutline, int aHole) const
Return the aGlobalIndex-th vertex in the poly set.
int OutlineCount() const
Return the number of vertices in a given outline/hole.
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:418
#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, according to page 16 of http://gerbv....
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_360
Definition: eda_angle.h:418
static constexpr EDA_ANGLE & ANGLE_90
Definition: eda_angle.h:414
static constexpr EDA_ANGLE & ANGLE_0
Definition: eda_angle.h:412
@ ERROR_INSIDE
void GRRect(wxDC *DC, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, const COLOR4D &aColor)
Definition: gr_basic.cpp:387
void GRCSegm(wxDC *DC, const VECTOR2I &A, const VECTOR2I &B, int width, const COLOR4D &Color)
Definition: gr_basic.cpp:192
void GRCircle(wxDC *aDC, const VECTOR2I &aPos, int aRadius, int aWidth, const COLOR4D &aColor)
Definition: gr_basic.cpp:348
void GRFilledSegment(wxDC *aDC, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, const COLOR4D &aColor)
Definition: gr_basic.cpp:269
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:342
void GRFilledRect(wxDC *DC, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, const COLOR4D &aColor, const COLOR4D &aBgColor)
Definition: gr_basic.cpp:394
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:360
constexpr int delta
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Definition: trigo.cpp:183
VECTOR2< int > VECTOR2I
Definition: vector2d.h:618