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( pointCount );
271
272 for( int ii = 0; ii < pointCount; ii++ )
273 {
274 VECTOR2I p( m_Polygon.CVertex( ii ).x, m_Polygon.CVertex( ii ).y );
275 points[ii] = p + aPosition;
276 points[ii] = aParent->GetABPosition( points[ii] );
277 }
278
279 GRClosedPoly( aDC, pointCount, &points[0], aFilled, aColor );
280}
281
282
283// A helper function for D_CODE::ConvertShapeToPolygon(). Add a hole to a polygon
284static void addHoleToPolygon( SHAPE_POLY_SET* aPolygon, APERTURE_DEF_HOLETYPE aHoleShape,
285 const VECTOR2I& aSize, const VECTOR2I& aAnchorPos );
286
287
289{
290 VECTOR2I initialpos;
291 VECTOR2I currpos;
292
293 m_Polygon.RemoveAllContours();
294
295 switch( m_ApertType )
296 {
297 case APT_CIRCLE: // creates only a circle with rectangular hole
298 {
299 // Adjust the allowed approx error to convert arcs to segments:
300 int arc_to_seg_error = gerbIUScale.mmToIU( 0.005 ); // Allow 5 microns
301 TransformCircleToPolygon( m_Polygon, initialpos, m_Size.x >> 1, arc_to_seg_error,
302 ERROR_INSIDE );
304 }
305 break;
306
307 case APT_RECT:
308 m_Polygon.NewOutline();
309 currpos.x = m_Size.x / 2;
310 currpos.y = m_Size.y / 2;
311 initialpos = currpos;
312 m_Polygon.Append( VECTOR2I( currpos ) );
313 currpos.x -= m_Size.x;
314 m_Polygon.Append( VECTOR2I( currpos ) );
315 currpos.y -= m_Size.y;
316 m_Polygon.Append( VECTOR2I( currpos ) );
317 currpos.x += m_Size.x;
318 m_Polygon.Append( VECTOR2I( currpos ) );
319 currpos.y += m_Size.y;
320 m_Polygon.Append( VECTOR2I( currpos ) ); // close polygon
321 m_Polygon.Append( VECTOR2I( initialpos ) );
322
324 break;
325
326 case APT_OVAL:
327 {
328 // Use the shared tessellator so flashed ovals follow the same size-and-accuracy
329 // convention as circle apertures and drawn oval segments.
330 int arc_to_seg_error = gerbIUScale.mmToIU( 0.005 ); // Allow 5 microns
332 int width;
333
334 if( m_Size.x > m_Size.y ) // horizontal oval
335 {
336 delta = VECTOR2I( ( m_Size.x - m_Size.y ) / 2, 0 );
337 width = m_Size.y;
338 }
339 else // vertical oval
340 {
341 delta = VECTOR2I( 0, ( m_Size.y - m_Size.x ) / 2 );
342 width = m_Size.x;
343 }
344
345 TransformOvalToPolygon( m_Polygon, -delta, delta, width, arc_to_seg_error, ERROR_INSIDE );
346
348 }
349 break;
350
351 case APT_POLYGON:
352 m_Polygon.NewOutline();
353 currpos.x = m_Size.x >> 1; // first point is on X axis
354 initialpos = currpos;
355
356 // rs274x said: m_EdgesCount = 3 ... 12
357 if( m_EdgesCount < 3 )
358 m_EdgesCount = 3;
359
360 if( m_EdgesCount > 12 )
361 m_EdgesCount = 12;
362
363 for( int ii = 0; ii < m_EdgesCount; ii++ )
364 {
365 currpos = initialpos;
366 RotatePoint( currpos, ANGLE_360 * ii / m_EdgesCount );
367 m_Polygon.Append( currpos );
368 }
369
371
372 if( !m_Rotation.IsZero() ) // rotate polygonal shape:
373 m_Polygon.Rotate( -m_Rotation );
374
375 break;
376
377 case APT_MACRO:
378 APERTURE_MACRO* macro = GetMacro();
379 SHAPE_POLY_SET* macroShape = macro->GetApertureMacroShape( aParent, initialpos );
380 m_Polygon.Append( *macroShape );
381 break;
382 }
383}
384
385
386// The helper function for D_CODE::ConvertShapeToPolygon().
387// Add a hole to a polygon
388static void addHoleToPolygon( SHAPE_POLY_SET* aPolygon, APERTURE_DEF_HOLETYPE aHoleShape,
389 const VECTOR2I& aSize, const VECTOR2I& aAnchorPos )
390{
391 VECTOR2I currpos;
392 SHAPE_POLY_SET holeBuffer;
393
394 if( aHoleShape == APT_DEF_ROUND_HOLE )
395 {
396 // Adjust the allowed approx error to convert arcs to segments:
397 int arc_to_seg_error = gerbIUScale.mmToIU( 0.005 ); // Allow 5 microns
398 TransformCircleToPolygon( holeBuffer, VECTOR2I( 0, 0 ), aSize.x / 2, arc_to_seg_error,
399 ERROR_INSIDE );
400 }
401 else if( aHoleShape == APT_DEF_RECT_HOLE )
402 {
403 holeBuffer.NewOutline();
404 currpos.x = aSize.x / 2;
405 currpos.y = aSize.y / 2;
406 holeBuffer.Append( VECTOR2I( currpos ) ); // link to hole and begin hole
407 currpos.x -= aSize.x;
408 holeBuffer.Append( VECTOR2I( currpos ) );
409 currpos.y -= aSize.y;
410 holeBuffer.Append( VECTOR2I( currpos ) );
411 currpos.x += aSize.x;
412 holeBuffer.Append( VECTOR2I( currpos ) );
413 currpos.y += aSize.y;
414 holeBuffer.Append( VECTOR2I( currpos ) ); // close hole
415 }
416
417 aPolygon->BooleanSubtract( holeBuffer );
418 aPolygon->Fracture();
419}
@ 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:288
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.
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a oblong shape to a polygon, using multiple segments.
static void addHoleToPolygon(SHAPE_POLY_SET *aPolygon, APERTURE_DEF_HOLETYPE aHoleShape, const VECTOR2I &aSize, const VECTOR2I &aAnchorPos)
Definition dcode.cpp:388
#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_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