KiCad PCB EDA Suite
AM_PRIMITIVE Class Reference

An aperture macro primitive as given in Table 3 of http://gerbv.sourceforge.net/docs/rs274xrevd_e.pdf. More...

#include <am_primitive.h>

Public Member Functions

 AM_PRIMITIVE (bool aGerbMetric, AM_PRIMITIVE_ID aId=AMP_UNKNOWN)
 
 ~AM_PRIMITIVE ()
 
bool IsAMPrimitiveExposureOn (const GERBER_DRAW_ITEM *aParent) const
 
int GetShapeDim (const 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. More...
 
void DrawBasicShape (const GERBER_DRAW_ITEM *aParent, SHAPE_POLY_SET &aShapeBuffer, const wxPoint &aShapePos)
 Draw (in fact generate the actual polygonal shape of) the primitive shape of an aperture macro instance. More...
 

Public Attributes

AM_PRIMITIVE_ID primitive_id
 The primitive type. More...
 
AM_PARAMS params
 A sequence of parameters used by. More...
 
bool m_GerbMetric
 

Private Member Functions

void ConvertShapeToPolygon (const GERBER_DRAW_ITEM *aParent, std::vector< wxPoint > &aBuffer)
 Convert a shape to an equivalent polygon. More...
 

Detailed Description

An aperture macro primitive as given in Table 3 of http://gerbv.sourceforge.net/docs/rs274xrevd_e.pdf.

Definition at line 93 of file am_primitive.h.

Constructor & Destructor Documentation

◆ AM_PRIMITIVE()

AM_PRIMITIVE::AM_PRIMITIVE ( bool  aGerbMetric,
AM_PRIMITIVE_ID  aId = AMP_UNKNOWN 
)
inline

Definition at line 102 of file am_primitive.h.

103  {
104  primitive_id = aId;
105  m_GerbMetric = aGerbMetric;
106  }
bool m_GerbMetric
Definition: am_primitive.h:99
AM_PRIMITIVE_ID primitive_id
The primitive type.
Definition: am_primitive.h:96

References m_GerbMetric, and primitive_id.

◆ ~AM_PRIMITIVE()

AM_PRIMITIVE::~AM_PRIMITIVE ( )
inline

Definition at line 109 of file am_primitive.h.

109 {}

Member Function Documentation

◆ ConvertShapeToPolygon()

void AM_PRIMITIVE::ConvertShapeToPolygon ( const GERBER_DRAW_ITEM aParent,
std::vector< wxPoint > &  aBuffer 
)
private

Convert a shape to an equivalent polygon.

Arcs and circles are approximated by segments. Useful when a shape is not a graphic primitive (shape with hole, rotated shape ... ) and cannot be easily drawn.

Note
Some schapes conbining circles and solid lines (rectangles), only rectangles are converted because circles are very easy to draw (no rotation problem) so convert them in polygons and draw them as polygons is not a good idea.

Definition at line 459 of file am_primitive.cpp.

461 {
462  D_CODE* tool = aParent->GetDcodeDescr();
463 
464  switch( primitive_id )
465  {
466  case AMP_CIRCLE:
467  {
468  /* Generated by an aperture macro declaration like:
469  * "1,1,0.3,0.5, 1.0*"
470  * type (1), exposure, diameter, pos.x, pos.y, <rotation>
471  * <rotation> is a optional parameter: rotation from origin.
472  * type is not stored in parameters list, so the first parameter is exposure
473  */
474  int radius = scaletoIU( params[1].GetValue( tool ), m_GerbMetric ) / 2;
475 
476  // A circle primitive can have a 0 size (for instance when used in roundrect macro),
477  // so skip it
478  if( radius <= 0 )
479  break;
480 
481  wxPoint center = mapPt( params[2].GetValue( tool ), params[3].GetValue( tool ),
482  m_GerbMetric );
483  wxPoint corner;
484  const int delta = 3600 / seg_per_circle; // rot angle in 0.1 degree
485 
486  for( int angle = 0; angle < 3600; angle += delta )
487  {
488  corner.x = radius;
489  corner.y = 0;
490  RotatePoint( &corner, angle );
491  corner += center;
492  aBuffer.push_back( corner );
493  }
494 
495  break;
496  }
497 
498  case AMP_LINE2:
499  case AMP_LINE20: // Line with rectangle ends. (Width, start and end pos + rotation)
500  {
501  int width = scaletoIU( params[1].GetValue( tool ), m_GerbMetric );
502  wxPoint start = mapPt( params[2].GetValue( tool ),
503  params[3].GetValue( tool ), m_GerbMetric );
504  wxPoint end = mapPt( params[4].GetValue( tool ),
505  params[5].GetValue( tool ), m_GerbMetric );
506  wxPoint delta = end - start;
507  int len = KiROUND( EuclideanNorm( delta ) );
508 
509  // To build the polygon, we must create a horizontal polygon starting to "start"
510  // and rotate it to have the end point to "end"
511  wxPoint currpt;
512  currpt.y += width / 2; // Upper left
513  aBuffer.push_back( currpt );
514  currpt.x = len; // Upper right
515  aBuffer.push_back( currpt );
516  currpt.y -= width; // lower right
517  aBuffer.push_back( currpt );
518  currpt.x = 0; // lower left
519  aBuffer.push_back( currpt );
520 
521  // Rotate rectangle and move it to the actual start point
522  double angle = ArcTangente( delta.y, delta.x );
523 
524  for( unsigned ii = 0; ii < 4; ii++ )
525  {
526  RotatePoint( &aBuffer[ii], -angle );
527  aBuffer[ii] += start;
528  }
529 
530  break;
531  }
532 
533  case AMP_LINE_CENTER:
534  {
535  wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ),
536  m_GerbMetric );
537  wxPoint pos = mapPt( params[3].GetValue( tool ), params[4].GetValue( tool ),
538  m_GerbMetric );
539 
540  // Build poly:
541  pos.x -= size.x / 2;
542  pos.y -= size.y / 2; // Lower left
543  aBuffer.push_back( pos );
544  pos.y += size.y; // Upper left
545  aBuffer.push_back( pos );
546  pos.x += size.x; // Upper right
547  aBuffer.push_back( pos );
548  pos.y -= size.y; // lower right
549  aBuffer.push_back( pos );
550  break;
551  }
552 
553  case AMP_LINE_LOWER_LEFT:
554  {
555  wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ),
556  m_GerbMetric );
557  wxPoint lowerLeft = mapPt( params[3].GetValue( tool ), params[4].GetValue( tool ),
558  m_GerbMetric );
559 
560  // Build poly:
561  aBuffer.push_back( lowerLeft );
562  lowerLeft.y += size.y; // Upper left
563  aBuffer.push_back( lowerLeft );
564  lowerLeft.x += size.x; // Upper right
565  aBuffer.push_back( lowerLeft );
566  lowerLeft.y -= size.y; // lower right
567  aBuffer.push_back( lowerLeft );
568  break;
569  }
570 
571  case AMP_THERMAL:
572  {
573  // Only 1/4 of the full shape is built, because the other 3 shapes will be draw from
574  // this first rotated by 90, 180 and 270 deg.
575  // params = center.x (unused here), center.y (unused here), outside diam, inside diam,
576  // crosshair thickness.
577  int outerRadius = scaletoIU( params[2].GetValue( tool ), m_GerbMetric ) / 2;
578  int innerRadius = scaletoIU( params[3].GetValue( tool ), m_GerbMetric ) / 2;
579 
580  // Safety checks to guarantee no divide-by-zero
581  outerRadius = std::max( 1, outerRadius );
582  innerRadius = std::max( 1, innerRadius );
583 
584  int halfthickness = scaletoIU( params[4].GetValue( tool ), m_GerbMetric ) / 2;
585  double angle_start = RAD2DECIDEG( asin( (double) halfthickness / innerRadius ) );
586 
587  // Draw shape in the first quadrant (X and Y > 0)
588  wxPoint pos, startpos;
589 
590  // Inner arc
591  startpos.x = innerRadius;
592  double angle_end = 900 - angle_start;
593 
594  for( double angle = angle_start; angle < angle_end; angle += 100 )
595  {
596  pos = startpos;
597  RotatePoint( &pos, angle );
598  aBuffer.push_back( pos );
599  }
600 
601  // Last point
602  pos = startpos;
603  RotatePoint( &pos, angle_end );
604  aBuffer.push_back( pos );
605 
606  // outer arc
607  startpos.x = outerRadius;
608  startpos.y = 0;
609  angle_start = RAD2DECIDEG( asin( (double) halfthickness / outerRadius ) );
610  angle_end = 900 - angle_start;
611 
612  // First point, near Y axis, outer arc
613  for( double angle = angle_end; angle > angle_start; angle -= 100 )
614  {
615  pos = startpos;
616  RotatePoint( &pos, angle );
617  aBuffer.push_back( pos );
618  }
619 
620  // last point
621  pos = startpos;
622  RotatePoint( &pos, angle_start );
623  aBuffer.push_back( pos );
624 
625  aBuffer.push_back( aBuffer[0] ); // Close poly
626  }
627  break;
628 
629  case AMP_MOIRE:
630  {
631  // A cross hair with n concentric circles. Only the cross is built as
632  // polygon because circles can be drawn easily
633  int crossHairThickness = scaletoIU( params[6].GetValue( tool ), m_GerbMetric );
634  int crossHairLength = scaletoIU( params[7].GetValue( tool ), m_GerbMetric );
635 
636  // Create cross. First create 1/4 of the shape.
637  // Others point are the same, rotated by 90, 180 and 270 deg
638  wxPoint pos( crossHairThickness / 2, crossHairLength / 2 );
639  aBuffer.push_back( pos );
640  pos.y = crossHairThickness / 2;
641  aBuffer.push_back( pos );
642  pos.x = -crossHairLength / 2;
643  aBuffer.push_back( pos );
644  pos.y = -crossHairThickness / 2;
645  aBuffer.push_back( pos );
646 
647  // Copy the 4 shape, rotated by 90, 180 and 270 deg
648  for( int jj = 1; jj <= 3; jj ++ )
649  {
650  for( int ii = 0; ii < 4; ii++ )
651  {
652  pos = aBuffer[ii];
653  RotatePoint( &pos, jj*900 );
654  aBuffer.push_back( pos );
655  }
656  }
657 
658  break;
659  }
660 
661  case AMP_OUTLINE:
662  // already is a polygon. Do nothing
663  break;
664 
665  case AMP_POLYGON: // Creates a regular polygon
666  {
667  int vertexcount = KiROUND( params[1].GetValue( tool ) );
668  int radius = scaletoIU( params[4].GetValue( tool ), m_GerbMetric ) / 2;
669 
670  // rs274x said: vertex count = 3 ... 10, and the first corner is on the X axis
671  if( vertexcount < 3 )
672  vertexcount = 3;
673 
674  if( vertexcount > 10 )
675  vertexcount = 10;
676 
677  for( int ii = 0; ii <= vertexcount; ii++ )
678  {
679  wxPoint pos( radius, 0);
680  RotatePoint( &pos, ii * 3600 / vertexcount );
681  aBuffer.push_back( pos );
682  }
683 
684  break;
685  }
686 
687  case AMP_COMMENT:
688  case AMP_UNKNOWN:
689  case AMP_EOF:
690  break;
691  }
692 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:146
bool m_GerbMetric
Definition: am_primitive.h:99
D_CODE * GetDcodeDescr() const
Return the GetDcodeDescr of this object, or NULL.
double RAD2DECIDEG(double rad)
Definition: trigo.h:234
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:229
int scaletoIU(double aCoord, bool isMetric)
Convert a distance given in floating point to our internal units.
const int seg_per_circle
static wxPoint mapPt(double x, double y, bool isMetric)
Translate a point from the aperture macro coordinate system to our deci-mils coordinate system.
A gerber DCODE (also called Aperture) definition.
Definition: dcode.h:80
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
constexpr int delta
double ArcTangente(int dy, int dx)
Definition: trigo.cpp:183
AM_PARAMS params
A sequence of parameters used by.
Definition: am_primitive.h:97
AM_PRIMITIVE_ID primitive_id
The primitive type.
Definition: am_primitive.h:96

References AMP_CIRCLE, AMP_COMMENT, AMP_EOF, AMP_LINE2, AMP_LINE20, AMP_LINE_CENTER, AMP_LINE_LOWER_LEFT, AMP_MOIRE, AMP_OUTLINE, AMP_POLYGON, AMP_THERMAL, AMP_UNKNOWN, PNS::angle(), ArcTangente(), delta, EuclideanNorm(), GERBER_DRAW_ITEM::GetDcodeDescr(), KiROUND(), m_GerbMetric, mapPt(), params, primitive_id, RAD2DECIDEG(), RotatePoint(), scaletoIU(), and seg_per_circle.

Referenced by DrawBasicShape().

◆ DrawBasicShape()

void AM_PRIMITIVE::DrawBasicShape ( const GERBER_DRAW_ITEM aParent,
SHAPE_POLY_SET aShapeBuffer,
const wxPoint &  aShapePos 
)

Draw (in fact generate the actual polygonal shape of) the primitive shape of an aperture macro instance.

Parameters
aParentis the parent GERBER_DRAW_ITEM which is actually drawn.
aShapeBufferis a SHAPE_POLY_SET to put the shape converted to a polygon.
aShapePosis the actual shape position.

Definition at line 97 of file am_primitive.cpp.

99 {
100 #define TO_POLY_SHAPE \
101  { \
102  if( polybuffer.size() > 1 ) \
103  { \
104  aShapeBuffer.NewOutline(); \
105  \
106  for( unsigned jj = 0; jj < polybuffer.size(); jj++ ) \
107  aShapeBuffer.Append( polybuffer[jj].x, polybuffer[jj].y ); \
108  \
109  aShapeBuffer.Append( polybuffer[0].x, polybuffer[0].y ); \
110  } \
111  }
112 
113  // Draw the primitive shape for flashed items.
114  // Create a static buffer to avoid a lot of memory reallocation.
115  static std::vector<wxPoint> polybuffer;
116  polybuffer.clear();
117 
118  wxPoint curPos = aShapePos;
119  D_CODE* tool = aParent->GetDcodeDescr();
120  double rotation;
121 
122  switch( primitive_id )
123  {
124  case AMP_CIRCLE: // Circle, given diameter and position
125  {
126  /* Generated by an aperture macro declaration like:
127  * "1,1,0.3,0.5, 1.0*"
128  * type (1), exposure, diameter, pos.x, pos.y, <rotation>
129  * <rotation> is a optional parameter: rotation from origin.
130  * type is not stored in parameters list, so the first parameter is exposure
131  */
132  ConvertShapeToPolygon( aParent, polybuffer );
133 
134  // shape rotation (if any):
135  if( params.size() >= 5 )
136  {
137  rotation = params[4].GetValue( tool ) * 10.0;
138 
139  if( rotation != 0)
140  {
141  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
142  RotatePoint( &polybuffer[ii], -rotation );
143  }
144  }
145 
146 
147  // Move to current position:
148  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
149  {
150  polybuffer[ii] += curPos;
151  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
152  }
153 
155  break;
156  }
157 
158  case AMP_LINE2:
159  case AMP_LINE20: // Line with rectangle ends. (Width, start and end pos + rotation)
160  {
161  /* Vector Line, Primitive Code 20.
162  * A vector line is a rectangle defined by its line width, start and end points.
163  * The line ends are rectangular.
164  */
165  /* Generated by an aperture macro declaration like:
166  * "2,1,0.3,0,0, 0.5, 1.0,-135*"
167  * type (2), exposure, width, start.x, start.y, end.x, end.y, rotation
168  * type is not stored in parameters list, so the first parameter is exposure
169  */
170  ConvertShapeToPolygon( aParent, polybuffer );
171 
172  // shape rotation:
173  rotation = params[6].GetValue( tool ) * 10.0;
174 
175  if( rotation != 0)
176  {
177  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
178  RotatePoint( &polybuffer[ii], -rotation );
179  }
180 
181  // Move to current position:
182  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
183  {
184  polybuffer[ii] += curPos;
185  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
186  }
187 
189  break;
190  }
191 
192  case AMP_LINE_CENTER:
193  {
194  /* Center Line, Primitive Code 21
195  * A center line primitive is a rectangle defined by its width, height, and center point
196  */
197  /* Generated by an aperture macro declaration like:
198  * "21,1,0.3,0.03,0,0,-135*"
199  * type (21), exposure, ,width, height, center pos.x, center pos.y, rotation
200  * type is not stored in parameters list, so the first parameter is exposure
201  */
202  ConvertShapeToPolygon( aParent, polybuffer );
203 
204  // shape rotation:
205  rotation = params[5].GetValue( tool ) * 10.0;
206 
207  if( rotation != 0 )
208  {
209  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
210  RotatePoint( &polybuffer[ii], -rotation );
211  }
212 
213  // Move to current position:
214  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
215  {
216  polybuffer[ii] += curPos;
217  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
218  }
219 
221  break;
222  }
223 
224  case AMP_LINE_LOWER_LEFT:
225  {
226  /* Generated by an aperture macro declaration like:
227  * "22,1,0.3,0.03,0,0,-135*"
228  * type (22), exposure, ,width, height, corner pos.x, corner pos.y, rotation
229  * type is not stored in parameters list, so the first parameter is exposure
230  */
231  ConvertShapeToPolygon( aParent, polybuffer );
232 
233  // shape rotation:
234  rotation = params[5].GetValue( tool ) * 10.0;
235  if( rotation != 0)
236  {
237  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
238  RotatePoint( &polybuffer[ii], -rotation );
239  }
240 
241  // Move to current position:
242  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
243  {
244  polybuffer[ii] += curPos;
245  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
246  }
247 
249  break;
250  }
251 
252  case AMP_THERMAL:
253  {
254  /* Generated by an aperture macro declaration like:
255  * "7, 0,0,1.0,0.3,0.01,-13*"
256  * type (7), center.x , center.y, outside diam, inside diam, crosshair thickness, rotation
257  * type is not stored in parameters list, so the first parameter is center.x
258  *
259  * The thermal primitive is a ring (annulus) interrupted by four gaps. Exposure is always
260  * on.
261  */
262  std::vector<wxPoint> subshape_poly;
263  curPos += mapPt( params[0].GetValue( tool ), params[1].GetValue( tool ), m_GerbMetric );
264  ConvertShapeToPolygon( aParent, subshape_poly );
265 
266  // shape rotation:
267  rotation = params[5].GetValue( tool ) * 10.0;
268 
269  // Because a thermal shape has 4 identical sub-shapes, only one is created in subshape_poly.
270  // We must draw 4 sub-shapes rotated by 90 deg
271  for( int ii = 0; ii < 4; ii++ )
272  {
273  polybuffer = subshape_poly;
274  double sub_rotation = rotation + 900 * ii;
275 
276  for( unsigned jj = 0; jj < polybuffer.size(); jj++ )
277  RotatePoint( &polybuffer[jj], -sub_rotation );
278 
279  // Move to current position:
280  for( unsigned jj = 0; jj < polybuffer.size(); jj++ )
281  {
282  polybuffer[jj] += curPos;
283  polybuffer[jj] = aParent->GetABPosition( polybuffer[jj] );
284  }
285 
287  }
288  }
289  break;
290 
291  case AMP_MOIRE:
292  {
293  /* Moire, Primitive Code 6
294  * The moire primitive is a cross hair centered on concentric rings (annuli).
295  * Exposure is always on.
296  */
297  curPos += mapPt( params[0].GetValue( tool ), params[1].GetValue( tool ),
298  m_GerbMetric );
299 
300  /* Generated by an aperture macro declaration like:
301  * "6,0,0,0.125,.01,0.01,3,0.003,0.150,0"
302  * type(6), pos.x, pos.y, diam, penwidth, gap, circlecount, crosshair thickness,
303  * crosshair len, rotation. The type is not stored in parameters list, so the first
304  * parameter is pos.x.
305  */
306  int outerDiam = scaletoIU( params[2].GetValue( tool ), m_GerbMetric );
307  int penThickness = scaletoIU( params[3].GetValue( tool ), m_GerbMetric );
308  int gap = scaletoIU( params[4].GetValue( tool ), m_GerbMetric );
309  int numCircles = KiROUND( params[5].GetValue( tool ) );
310 
311  // Draw circles:
312  wxPoint center = aParent->GetABPosition( curPos );
313 
314  // adjust outerDiam by this on each nested circle
315  int diamAdjust = ( gap + penThickness ) * 2;
316 
317  for( int i = 0; i < numCircles; ++i, outerDiam -= diamAdjust )
318  {
319  if( outerDiam <= 0 )
320  break;
321 
322  // Note: outerDiam is the outer diameter of the ring.
323  // the ring graphic diameter is (outerDiam - penThickness)
324  if( outerDiam <= penThickness )
325  { // No room to draw a ring (no room for the hole):
326  // draw a circle instead (with no hole), with the right diameter
327  TransformCircleToPolygon( aShapeBuffer, center, outerDiam / 2, ARC_HIGH_DEF,
328  ERROR_INSIDE );
329  }
330  else
331  {
332  TransformRingToPolygon( aShapeBuffer, center, ( outerDiam - penThickness ) / 2,
333  penThickness, ARC_HIGH_DEF, ERROR_INSIDE );
334  }
335  }
336 
337  // Draw the cross:
338  ConvertShapeToPolygon( aParent, polybuffer );
339 
340  rotation = params[8].GetValue( tool ) * 10.0;
341 
342  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
343  {
344  // shape rotation:
345  RotatePoint( &polybuffer[ii], -rotation );
346 
347  // Move to current position:
348  polybuffer[ii] += curPos;
349  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
350  }
351 
353  break;
354  }
355 
356  case AMP_OUTLINE:
357  {
358  /* Outline, Primitive Code 4
359  * An outline primitive is an area enclosed by an n-point polygon defined by its start
360  * point and n
361  * subsequent points. The outline must be closed, i.e. the last point must be equal to
362  * the start point. There must be at least one subsequent point (to close the outline).
363  * The outline of the primitive is actually the contour (see 2.6) that consists of linear
364  * segments only, so it must conform to all the requirements described for contours.
365  * Warning: Make no mistake: n is the number of subsequent points, being the number of
366  * vertices of the outline or one less than the number of coordinate pairs.
367  */
368  /* Generated by an aperture macro declaration like:
369  * "4,1,3,0.0,0.0,0.0,0.5,0.5,0.5,0.5,0.0,-25"
370  * type(4), exposure, corners count, corner1.x, corner.1y, ..., corner1.x, corner.1y,
371  * rotation
372  * type is not stored in parameters list, so the first parameter is exposure
373  */
374  // params[0] is the exposure and params[1] is the corners count after the first corner
375  int numCorners = (int) params[1].GetValue( tool );
376 
377  // the shape rotation is the last param of list, after corners
378  int last_prm = params.size() - 1;
379  rotation = params[last_prm].GetValue( tool ) * 10.0;
380  wxPoint pos;
381 
382  // Read points.
383  // Note: numCorners is the polygon corner count, following the first corner
384  // * the polygon is always closed,
385  // * therefore the last XY coordinate is the same as the first
386  int prm_idx = 2; // params[2] is the first X coordinate
387 
388  for( int i = 0; i <= numCorners; ++i )
389  {
390  pos.x = scaletoIU( params[prm_idx].GetValue( tool ), m_GerbMetric );
391  prm_idx++;
392  pos.y = scaletoIU( params[prm_idx].GetValue( tool ), m_GerbMetric );
393  prm_idx++;
394  polybuffer.push_back(pos);
395 
396  // Guard: ensure prm_idx < last_prm
397  // I saw malformed gerber files with numCorners = number
398  // of coordinates instead of number of coordinates following the first point
399  if( prm_idx >= last_prm )
400  break;
401  }
402 
403  // rotate polygon and move it to the actual position shape rotation:
404  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
405  {
406  RotatePoint( &polybuffer[ii], -rotation );
407  }
408 
409  // Move to current position:
410  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
411  {
412  polybuffer[ii] += curPos;
413  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
414  }
415 
417  break;
418  }
419 
420  case AMP_POLYGON:
421  /* Polygon, Primitive Code 5
422  * A polygon primitive is a regular polygon defined by the number of vertices n, the
423  * center point and the diameter of the circumscribed circle
424  */
425  /* Generated by an aperture macro declaration like:
426  * "5,1,0.6,0,0,0.5,25"
427  * type(5), exposure, vertices count, pox.x, pos.y, diameter, rotation
428  * type is not stored in parameters list, so the first parameter is exposure
429  */
430  curPos += mapPt( params[2].GetValue( tool ), params[3].GetValue( tool ), m_GerbMetric );
431 
432  // Creates the shape:
433  ConvertShapeToPolygon( aParent, polybuffer );
434 
435  // rotate polygon and move it to the actual position
436  rotation = params[5].GetValue( tool ) * 10.0;
437  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
438  {
439  RotatePoint( &polybuffer[ii], -rotation );
440  polybuffer[ii] += curPos;
441  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
442  }
443 
445 
446  break;
447 
448  case AMP_EOF:
449  // not yet supported, waiting for you.
450  break;
451 
452  case AMP_UNKNOWN:
453  default:
454  break;
455  }
456 }
bool m_GerbMetric
Definition: am_primitive.h:99
D_CODE * GetDcodeDescr() const
Return the GetDcodeDescr of this object, or NULL.
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:229
int scaletoIU(double aCoord, bool isMetric)
Convert a distance given in floating point to our internal units.
void ConvertShapeToPolygon(const GERBER_DRAW_ITEM *aParent, std::vector< wxPoint > &aBuffer)
Convert a shape to an equivalent polygon.
wxPoint GetABPosition(const wxPoint &aXYPosition) const
Return the image position of aPosition for this object.
#define TO_POLY_SHAPE
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aCornerBuffer, const wxPoint &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
static wxPoint mapPt(double x, double y, bool isMetric)
Translate a point from the aperture macro coordinate system to our deci-mils coordinate system.
A gerber DCODE (also called Aperture) definition.
Definition: dcode.h:80
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
void TransformRingToPolygon(SHAPE_POLY_SET &aCornerBuffer, const wxPoint &aCentre, int aRadius, int aWidth, int aError, ERROR_LOC aErrorLoc)
Convert arcs to multiple straight segments.
AM_PARAMS params
A sequence of parameters used by.
Definition: am_primitive.h:97
AM_PRIMITIVE_ID primitive_id
The primitive type.
Definition: am_primitive.h:96

References AMP_CIRCLE, AMP_EOF, AMP_LINE2, AMP_LINE20, AMP_LINE_CENTER, AMP_LINE_LOWER_LEFT, AMP_MOIRE, AMP_OUTLINE, AMP_POLYGON, AMP_THERMAL, AMP_UNKNOWN, ConvertShapeToPolygon(), ERROR_INSIDE, GERBER_DRAW_ITEM::GetABPosition(), GERBER_DRAW_ITEM::GetDcodeDescr(), KiROUND(), m_GerbMetric, mapPt(), params, primitive_id, RotatePoint(), scaletoIU(), TO_POLY_SHAPE, TransformCircleToPolygon(), and TransformRingToPolygon().

◆ GetShapeDim()

int AM_PRIMITIVE::GetShapeDim ( const 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.

Due to the complexity of the shape of some primitives one cannot calculate the "size" of a shape (only a bounding box) but here, the "dimension" of the shape is the diameter of the primitive or for lines the width of the line.

Parameters
aParentis the parent GERBER_DRAW_ITEM which is actually drawn
Returns
a dimension, or -1 if no dim to calculate

Definition at line 695 of file am_primitive.cpp.

696 {
697  int dim = -1;
698  D_CODE* tool = aParent->GetDcodeDescr();
699 
700  switch( primitive_id )
701  {
702  case AMP_CIRCLE:
703  // params = exposure, diameter, pos.x, pos.y
704  dim = scaletoIU( params[1].GetValue( tool ), m_GerbMetric ); // Diameter
705  break;
706 
707  case AMP_LINE2:
708  case AMP_LINE20: // Line with rectangle ends. (Width, start and end pos + rotation)
709  dim = scaletoIU( params[1].GetValue( tool ), m_GerbMetric ); // line width
710  break;
711 
712  case AMP_LINE_CENTER:
713  {
714  wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ),
715  m_GerbMetric );
716  dim = std::min(size.x, size.y);
717  break;
718  }
719 
720  case AMP_LINE_LOWER_LEFT:
721  {
722  wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ),
723  m_GerbMetric );
724  dim = std::min(size.x, size.y);
725  break;
726  }
727 
728  case AMP_THERMAL:
729  {
730  // Only 1/4 of the full shape is built, because the other 3 shapes will be draw from
731  // this first rotated by 90, 180 and 270 deg.
732  // params = center.x (unused here), center.y (unused here), outside diam, inside diam,
733  // crosshair thickness.
734  dim = scaletoIU( params[2].GetValue( tool ), m_GerbMetric ) / 2; // Outer diam
735  break;
736  }
737 
738  case AMP_MOIRE: // A cross hair with n concentric circles.
739  dim = scaletoIU( params[7].GetValue( tool ), m_GerbMetric ); // = cross hair len
740  break;
741 
742  case AMP_OUTLINE: // a free polygon :
743  {
744  // dim = min side of the bounding box (this is a poor criteria, but what is a good
745  // criteria b?)
746  // exposure, corners count, corner1.x, corner.1y, ..., rotation
747  // note: corners count is the count of corners following corner1
748  int numPoints = (int) params[1].GetValue( tool );
749 
750  // Read points. numPoints does not include the starting point, so add 1.
751  // and calculate the bounding box;
752  wxSize pos_min, pos_max, pos;
753  int prm_idx = 2; // params[2] is the first X coordinate
754  int last_prm = params.size() - 1;
755 
756  for( int i = 0; i<= numPoints; ++i )
757  {
758  pos.x = scaletoIU( params[prm_idx].GetValue( tool ), m_GerbMetric );
759  prm_idx++;
760  pos.y = scaletoIU( params[prm_idx].GetValue( tool ), m_GerbMetric );
761  prm_idx++;
762 
763  if( i == 0 )
764  {
765  pos_min = pos_max = pos;
766  }
767  else
768  {
769  // upper right corner:
770  if( pos_min.x > pos.x )
771  pos_min.x = pos.x;
772 
773  if( pos_min.y > pos.y )
774  pos_min.y = pos.y;
775 
776  // lower left corner:
777  if( pos_max.x < pos.x )
778  pos_max.x = pos.x;
779 
780  if( pos_max.y < pos.y )
781  pos_max.y = pos.y;
782  }
783 
784  // Guard: ensure prm_idx < last_prm (last prm is orientation)
785  // I saw malformed gerber files with numCorners = number
786  // of coordinates instead of number of coordinates following the first point
787  if( prm_idx >= last_prm )
788  break;
789  }
790 
791  // calculate dim
792  wxSize size;
793  size.x = pos_max.x - pos_min.x;
794  size.y = pos_max.y - pos_min.y;
795  dim = std::min( size.x, size.y );
796  break;
797  }
798 
799  case AMP_POLYGON: // Regular polygon
800  dim = scaletoIU( params[4].GetValue( tool ), m_GerbMetric ) / 2; // Radius
801  break;
802 
803  case AMP_COMMENT:
804  case AMP_UNKNOWN:
805  case AMP_EOF:
806  break;
807  }
808 
809  return dim;
810 }
bool m_GerbMetric
Definition: am_primitive.h:99
D_CODE * GetDcodeDescr() const
Return the GetDcodeDescr of this object, or NULL.
int scaletoIU(double aCoord, bool isMetric)
Convert a distance given in floating point to our internal units.
static wxPoint mapPt(double x, double y, bool isMetric)
Translate a point from the aperture macro coordinate system to our deci-mils coordinate system.
A gerber DCODE (also called Aperture) definition.
Definition: dcode.h:80
AM_PARAMS params
A sequence of parameters used by.
Definition: am_primitive.h:97
AM_PRIMITIVE_ID primitive_id
The primitive type.
Definition: am_primitive.h:96

References AMP_CIRCLE, AMP_COMMENT, AMP_EOF, AMP_LINE2, AMP_LINE20, AMP_LINE_CENTER, AMP_LINE_LOWER_LEFT, AMP_MOIRE, AMP_OUTLINE, AMP_POLYGON, AMP_THERMAL, AMP_UNKNOWN, GERBER_DRAW_ITEM::GetDcodeDescr(), m_GerbMetric, mapPt(), params, primitive_id, and scaletoIU().

◆ IsAMPrimitiveExposureOn()

bool AM_PRIMITIVE::IsAMPrimitiveExposureOn ( const GERBER_DRAW_ITEM aParent) const
Returns
true if the first parameter is not 0 (it can be only 0 or 1). Some but not all primitives use the first parameter as an exposure control. Others are always ON. In a aperture macro shape, a basic primitive with exposure off is a hole in the shape it is NOT a negative shape

Definition at line 59 of file am_primitive.cpp.

60 {
61  /*
62  * Some but not all primitives use the first parameter as an exposure control.
63  * Others are always ON.
64  * In a aperture macro shape, a basic primitive with exposure off is a hole in the shape
65  * it is NOT a negative shape
66  */
67  wxASSERT( params.size() );
68 
69  switch( primitive_id )
70  {
71  case AMP_CIRCLE:
72  case AMP_LINE2:
73  case AMP_LINE20:
74  case AMP_LINE_CENTER:
76  case AMP_OUTLINE:
77  case AMP_POLYGON:
78  // All have an exposure parameter and can return a value (0 or 1)
79  return params[0].GetValue( aParent->GetDcodeDescr() ) != 0;
80  break;
81 
82  case AMP_THERMAL: // Exposure is always on
83  case AMP_MOIRE: // Exposure is always on
84  case AMP_EOF:
85  case AMP_UNKNOWN:
86  default:
87  return 1; // All have no exposure parameter and are always 0N return true
88  break;
89  }
90 }
D_CODE * GetDcodeDescr() const
Return the GetDcodeDescr of this object, or NULL.
AM_PARAMS params
A sequence of parameters used by.
Definition: am_primitive.h:97
AM_PRIMITIVE_ID primitive_id
The primitive type.
Definition: am_primitive.h:96

References AMP_CIRCLE, AMP_EOF, AMP_LINE2, AMP_LINE20, AMP_LINE_CENTER, AMP_LINE_LOWER_LEFT, AMP_MOIRE, AMP_OUTLINE, AMP_POLYGON, AMP_THERMAL, AMP_UNKNOWN, GERBER_DRAW_ITEM::GetDcodeDescr(), params, and primitive_id.

Member Data Documentation

◆ m_GerbMetric

bool AM_PRIMITIVE::m_GerbMetric

Definition at line 99 of file am_primitive.h.

Referenced by AM_PRIMITIVE(), ConvertShapeToPolygon(), DrawBasicShape(), and GetShapeDim().

◆ params

AM_PARAMS AM_PRIMITIVE::params

A sequence of parameters used by.

Definition at line 97 of file am_primitive.h.

Referenced by ConvertShapeToPolygon(), DrawBasicShape(), GetShapeDim(), IsAMPrimitiveExposureOn(), and GERBER_FILE_IMAGE::ReadApertureMacro().

◆ primitive_id

AM_PRIMITIVE_ID AM_PRIMITIVE::primitive_id

The documentation for this class was generated from the following files: