KiCad PCB EDA Suite
am_primitive.cpp
Go to the documentation of this file.
1 
5 /*
6  * This program source code file is part of KiCad, a free EDA CAD application.
7  *
8  * Copyright (C) 1992-2017 Jean-Pierre Charras <jp.charras at wanadoo.fr>
9  * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
10  * Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, you may find one here:
24  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
25  * or you may search the http://www.gnu.org website for the version 2 license,
26  * or you may write to the Free Software Foundation, Inc.,
27  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
28  */
29 
30 #include <trigo.h>
31 #include <convert_to_biu.h>
33 #include <math/util.h> // for KiROUND
34 
35 #include <gerbview.h>
36 #include <gerber_file_image.h>
37 
38 
43 extern int scaletoIU( double aCoord, bool isMetric ); // defined it rs274d_read_XY_and_IJ_coordiantes.cpp
44 
51 static wxPoint mapPt( double x, double y, bool isMetric )
52 {
53  wxPoint ret( scaletoIU( x, isMetric ), scaletoIU( y, isMetric ) );
54 
55  return ret;
56 }
57 
58 
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 }
91 
92 // TODO(snh): Remove hard coded count
93 const int seg_per_circle = 64; // Number of segments to approximate a circle
94 
96  SHAPE_POLY_SET& aShapeBuffer,
97  wxPoint aShapePos )
98 {
99  #define TO_POLY_SHAPE { aShapeBuffer.NewOutline(); \
100  for( unsigned jj = 0; jj < polybuffer.size(); jj++ )\
101  aShapeBuffer.Append( polybuffer[jj].x, polybuffer[jj].y );\
102  aShapeBuffer.Append( polybuffer[0].x, polybuffer[0].y );}
103 
104  // Draw the primitive shape for flashed items.
105  static std::vector<wxPoint> polybuffer; // create a static buffer to avoid a lot of memory reallocation
106  polybuffer.clear();
107 
108  wxPoint curPos = aShapePos;
109  D_CODE* tool = aParent->GetDcodeDescr();
110  double rotation;
111 
112  switch( primitive_id )
113  {
114  case AMP_CIRCLE: // Circle, given diameter and position
115  {
116  /* Generated by an aperture macro declaration like:
117  * "1,1,0.3,0.5, 1.0*"
118  * type (1), exposure, diameter, pos.x, pos.y, <rotation>
119  * <rotation> is a optional parameter: rotation from origin.
120  * type is not stored in parameters list, so the first parameter is exposure
121  */
122  ConvertShapeToPolygon( aParent, polybuffer );
123 
124  // shape rotation (if any):
125  if( params.size() >= 5 )
126  {
127  rotation = params[4].GetValue( tool ) * 10.0;
128 
129  if( rotation != 0)
130  {
131  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
132  RotatePoint( &polybuffer[ii], -rotation );
133  }
134  }
135 
136 
137  // Move to current position:
138  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
139  {
140  polybuffer[ii] += curPos;
141  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
142  }
143 
145  }
146  break;
147 
148  case AMP_LINE2:
149  case AMP_LINE20: // Line with rectangle ends. (Width, start and end pos + rotation)
150  {
151  /* Vector Line, Primitive Code 20.
152  * A vector line is a rectangle defined by its line width, start and end points.
153  * The line ends are rectangular.
154  */
155  /* Generated by an aperture macro declaration like:
156  * "2,1,0.3,0,0, 0.5, 1.0,-135*"
157  * type (2), exposure, width, start.x, start.y, end.x, end.y, rotation
158  * type is not stored in parameters list, so the first parameter is exposure
159  */
160  ConvertShapeToPolygon( aParent, polybuffer );
161 
162  // shape rotation:
163  rotation = params[6].GetValue( tool ) * 10.0;
164 
165  if( rotation != 0)
166  {
167  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
168  RotatePoint( &polybuffer[ii], -rotation );
169  }
170 
171  // Move to current position:
172  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
173  {
174  polybuffer[ii] += curPos;
175  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
176  }
177 
179  }
180  break;
181 
182  case AMP_LINE_CENTER:
183  {
184  /* Center Line, Primitive Code 21
185  * A center line primitive is a rectangle defined by its width, height, and center point
186  */
187  /* Generated by an aperture macro declaration like:
188  * "21,1,0.3,0.03,0,0,-135*"
189  * type (21), exposure, ,width, height, center pos.x, center pos.y, rotation
190  * type is not stored in parameters list, so the first parameter is exposure
191  */
192  ConvertShapeToPolygon( aParent, polybuffer );
193 
194  // shape rotation:
195  rotation = params[5].GetValue( tool ) * 10.0;
196 
197  if( rotation != 0 )
198  {
199  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
200  RotatePoint( &polybuffer[ii], -rotation );
201  }
202 
203  // Move to current position:
204  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
205  {
206  polybuffer[ii] += curPos;
207  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
208  }
209 
211  }
212  break;
213 
214  case AMP_LINE_LOWER_LEFT:
215  {
216  /* Generated by an aperture macro declaration like:
217  * "22,1,0.3,0.03,0,0,-135*"
218  * type (22), exposure, ,width, height, corner pos.x, corner pos.y, rotation
219  * type is not stored in parameters list, so the first parameter is exposure
220  */
221  ConvertShapeToPolygon( aParent, polybuffer );
222 
223  // shape rotation:
224  rotation = params[5].GetValue( tool ) * 10.0;
225  if( rotation != 0)
226  {
227  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
228  RotatePoint( &polybuffer[ii], -rotation );
229  }
230 
231  // Move to current position:
232  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
233  {
234  polybuffer[ii] += curPos;
235  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
236  }
237 
239  }
240  break;
241 
242  case AMP_THERMAL:
243  {
244  /* Generated by an aperture macro declaration like:
245  * "7, 0,0,1.0,0.3,0.01,-13*"
246  * type (7), center.x , center.y, outside diam, inside diam, crosshair thickness, rotation
247  * type is not stored in parameters list, so the first parameter is center.x
248  *
249  * The thermal primitive is a ring (annulus) interrupted by four gaps. Exposure is always on.
250  */
251  std::vector<wxPoint> subshape_poly;
252  curPos += mapPt( params[0].GetValue( tool ), params[1].GetValue( tool ), m_GerbMetric );
253  ConvertShapeToPolygon( aParent, subshape_poly );
254 
255  // shape rotation:
256  rotation = params[5].GetValue( tool ) * 10.0;
257 
258  // Because a thermal shape has 4 identical sub-shapes, only one is created in subshape_poly.
259  // We must draw 4 sub-shapes rotated by 90 deg
260  for( int ii = 0; ii < 4; ii++ )
261  {
262  polybuffer = subshape_poly;
263  double sub_rotation = rotation + 900 * ii;
264 
265  for( unsigned jj = 0; jj < polybuffer.size(); jj++ )
266  RotatePoint( &polybuffer[jj], -sub_rotation );
267 
268  // Move to current position:
269  for( unsigned jj = 0; jj < polybuffer.size(); jj++ )
270  {
271  polybuffer[jj] += curPos;
272  polybuffer[jj] = aParent->GetABPosition( polybuffer[jj] );
273  }
274 
276  }
277  }
278  break;
279 
280  case AMP_MOIRE:
281  {
282  /* Moire, Primitive Code 6
283  * The moire primitive is a cross hair centered on concentric rings (annuli).
284  * Exposure is always on.
285  */
286  curPos += mapPt( params[0].GetValue( tool ), params[1].GetValue( tool ),
287  m_GerbMetric );
288 
289  /* Generated by an aperture macro declaration like:
290  * "6,0,0,0.125,.01,0.01,3,0.003,0.150,0"
291  * type(6), pos.x, pos.y, diam, penwidth, gap, circlecount, crosshair thickness, crosshaire len, rotation
292  * type is not stored in parameters list, so the first parameter is pos.x
293  */
294  int outerDiam = scaletoIU( params[2].GetValue( tool ), m_GerbMetric );
295  int penThickness = scaletoIU( params[3].GetValue( tool ), m_GerbMetric );
296  int gap = scaletoIU( params[4].GetValue( tool ), m_GerbMetric );
297  int numCircles = KiROUND( params[5].GetValue( tool ) );
298 
299  // Draw circles:
300  wxPoint center = aParent->GetABPosition( curPos );
301  // adjust outerDiam by this on each nested circle
302  int diamAdjust = (gap + penThickness) * 2;
303 
304  for( int i = 0; i < numCircles; ++i, outerDiam -= diamAdjust )
305  {
306  if( outerDiam <= 0 )
307  break;
308 
309  // Note: outerDiam is the outer diameter of the ring.
310  // the ring graphic diameter is (outerDiam - penThickness)
311  if( outerDiam <= penThickness )
312  { // No room to draw a ring (no room for the hole):
313  // draw a circle instead (with no hole), with the right diameter
314  TransformCircleToPolygon( aShapeBuffer, center, outerDiam / 2, ARC_HIGH_DEF,
315  ERROR_INSIDE );
316  }
317  else
318  {
319  TransformRingToPolygon( aShapeBuffer, center, ( outerDiam - penThickness ) / 2,
320  penThickness, ARC_HIGH_DEF, ERROR_INSIDE );
321  }
322  }
323 
324  // Draw the cross:
325  ConvertShapeToPolygon( aParent, polybuffer );
326 
327  rotation = params[8].GetValue( tool ) * 10.0;
328  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
329  {
330  // shape rotation:
331  RotatePoint( &polybuffer[ii], -rotation );
332  // Move to current position:
333  polybuffer[ii] += curPos;
334  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
335  }
336 
338  }
339  break;
340 
341  case AMP_OUTLINE:
342  {
343  /* Outline, Primitive Code 4
344  * An outline primitive is an area enclosed by an n-point polygon defined by its start point and n
345  * subsequent points. The outline must be closed, i.e. the last point must be equal to the start
346  * point. There must be at least one subsequent point (to close the outline).
347  * The outline of the primitive is actually the contour (see 2.6) that consists of linear segments
348  * only, so it must conform to all the requirements described for contours.
349  * Warning: Make no mistake: n is the number of subsequent points, being the number of
350  * vertices of the outline or one less than the number of coordinate pairs.
351  */
352  /* Generated by an aperture macro declaration like:
353  * "4,1,3,0.0,0.0,0.0,0.5,0.5,0.5,0.5,0.0,-25"
354  * type(4), exposure, corners count, corner1.x, corner.1y, ..., corner1.x, corner.1y, rotation
355  * type is not stored in parameters list, so the first parameter is exposure
356  */
357  // params[0] is the exposure and params[1] is the corners count after the first corner
358  int numCorners = (int) params[1].GetValue( tool );
359  // the shape rotation is the last param of list, after corners
360  int last_prm = params.size() - 1;
361  rotation = params[last_prm].GetValue( tool ) * 10.0;
362  wxPoint pos;
363 
364  // Read points.
365  // Note: numCorners is the polygon corner count, following the first corner
366  // * the polygon is always closed,
367  // * therefore the last XY coordinate is the same as the first
368  int prm_idx = 2; // params[2] is the first X coordinate
369 
370  for( int i = 0; i <= numCorners; ++i )
371  {
372  pos.x = scaletoIU( params[prm_idx].GetValue( tool ), m_GerbMetric );
373  prm_idx++;
374  pos.y = scaletoIU( params[prm_idx].GetValue( tool ), m_GerbMetric );
375  prm_idx++;
376  polybuffer.push_back(pos);
377 
378  // Guard: ensure prm_idx < last_prm
379  // I saw malformed gerber files with numCorners = number
380  // of coordinates instead of number of coordinates following the first point
381  if( prm_idx >= last_prm )
382  break;
383  }
384  // rotate polygon and move it to the actual position
385  // shape rotation:
386  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
387  {
388  RotatePoint( &polybuffer[ii], -rotation );
389  }
390 
391  // Move to current position:
392  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
393  {
394  polybuffer[ii] += curPos;
395  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
396  }
397 
399  }
400  break;
401 
402  case AMP_POLYGON:
403  /* Polygon, Primitive Code 5
404  * A polygon primitive is a regular polygon defined by the number of vertices n, the center point
405  * and the diameter of the circumscribed circle
406  */
407  /* Generated by an aperture macro declaration like:
408  * "5,1,0.6,0,0,0.5,25"
409  * type(5), exposure, vertices count, pox.x, pos.y, diameter, rotation
410  * type is not stored in parameters list, so the first parameter is exposure
411  */
412  curPos += mapPt( params[2].GetValue( tool ), params[3].GetValue( tool ), m_GerbMetric );
413  // Creates the shape:
414  ConvertShapeToPolygon( aParent, polybuffer );
415 
416  // rotate polygon and move it to the actual position
417  rotation = params[5].GetValue( tool ) * 10.0;
418  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
419  {
420  RotatePoint( &polybuffer[ii], -rotation );
421  polybuffer[ii] += curPos;
422  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
423  }
424 
426 
427  break;
428 
429  case AMP_EOF:
430  // not yet supported, waiting for you.
431  break;
432 
433  case AMP_UNKNOWN:
434  default:
435  break;
436  }
437 }
438 
439 
451  std::vector<wxPoint>& aBuffer )
452 {
453  D_CODE* tool = aParent->GetDcodeDescr();
454 
455  switch( primitive_id )
456  {
457  case AMP_CIRCLE:
458  {
459  /* Generated by an aperture macro declaration like:
460  * "1,1,0.3,0.5, 1.0*"
461  * type (1), exposure, diameter, pos.x, pos.y, <rotation>
462  * <rotation> is a optional parameter: rotation from origin.
463  * type is not stored in parameters list, so the first parameter is exposure
464  */
465  wxPoint center = mapPt( params[2].GetValue( tool ), params[3].GetValue( tool ), m_GerbMetric );
466  int radius = scaletoIU( params[1].GetValue( tool ), m_GerbMetric ) / 2;
467  wxPoint corner;
468  const int delta = 3600 / seg_per_circle; // rot angle in 0.1 degree
469 
470  for( int angle = 0; angle < 3600; angle += delta )
471  {
472  corner.x = radius;
473  corner.y = 0;
474  RotatePoint( &corner, angle );
475  corner += center;
476  aBuffer.push_back( corner );
477  }
478  }
479  break;
480 
481  case AMP_LINE2:
482  case AMP_LINE20: // Line with rectangle ends. (Width, start and end pos + rotation)
483  {
484  int width = scaletoIU( params[1].GetValue( tool ), m_GerbMetric );
485  wxPoint start = mapPt( params[2].GetValue( tool ),
486  params[3].GetValue( tool ), m_GerbMetric );
487  wxPoint end = mapPt( params[4].GetValue( tool ),
488  params[5].GetValue( tool ), m_GerbMetric );
489  wxPoint delta = end - start;
490  int len = KiROUND( EuclideanNorm( delta ) );
491 
492  // To build the polygon, we must create a horizontal polygon starting to "start"
493  // and rotate it to have the end point to "end"
494  wxPoint currpt;
495  currpt.y += width / 2; // Upper left
496  aBuffer.push_back( currpt );
497  currpt.x = len; // Upper right
498  aBuffer.push_back( currpt );
499  currpt.y -= width; // lower right
500  aBuffer.push_back( currpt );
501  currpt.x = 0; // lower left
502  aBuffer.push_back( currpt );
503 
504  // Rotate rectangle and move it to the actual start point
505  double angle = ArcTangente( delta.y, delta.x );
506 
507  for( unsigned ii = 0; ii < 4; ii++ )
508  {
509  RotatePoint( &aBuffer[ii], -angle );
510  aBuffer[ii] += start;
511  }
512  }
513  break;
514 
515  case AMP_LINE_CENTER:
516  {
517  wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ), m_GerbMetric );
518  wxPoint pos = mapPt( params[3].GetValue( tool ), params[4].GetValue( tool ), m_GerbMetric );
519 
520  // Build poly:
521  pos.x -= size.x / 2;
522  pos.y -= size.y / 2; // Lower left
523  aBuffer.push_back( pos );
524  pos.y += size.y; // Upper left
525  aBuffer.push_back( pos );
526  pos.x += size.x; // Upper right
527  aBuffer.push_back( pos );
528  pos.y -= size.y; // lower right
529  aBuffer.push_back( pos );
530  }
531  break;
532 
533  case AMP_LINE_LOWER_LEFT:
534  {
535  wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ), m_GerbMetric );
536  wxPoint lowerLeft = mapPt( params[3].GetValue( tool ), params[4].GetValue(
537  tool ), m_GerbMetric );
538 
539  // Build poly:
540  aBuffer.push_back( lowerLeft );
541  lowerLeft.y += size.y; // Upper left
542  aBuffer.push_back( lowerLeft );
543  lowerLeft.x += size.x; // Upper right
544  aBuffer.push_back( lowerLeft );
545  lowerLeft.y -= size.y; // lower right
546  aBuffer.push_back( lowerLeft );
547  }
548  break;
549 
550  case AMP_THERMAL:
551  {
552  // Only 1/4 of the full shape is built, because the other 3 shapes will be draw from this first
553  // rotated by 90, 180 and 270 deg.
554  // params = center.x (unused here), center.y (unused here), outside diam, inside diam, crosshair thickness
555  int outerRadius = scaletoIU( params[2].GetValue( tool ), m_GerbMetric ) / 2;
556  int innerRadius = scaletoIU( params[3].GetValue( tool ), m_GerbMetric ) / 2;
557 
558  // Safety checks to guarantee no divide-by-zero
559  outerRadius = std::max( 1, outerRadius );
560  innerRadius = std::max( 1, innerRadius );
561 
562  int halfthickness = scaletoIU( params[4].GetValue( tool ), m_GerbMetric ) / 2;
563  double angle_start = RAD2DECIDEG( asin( (double) halfthickness / innerRadius ) );
564 
565  // Draw shape in the first cadrant (X and Y > 0)
566  wxPoint pos, startpos;
567 
568  // Inner arc
569  startpos.x = innerRadius;
570  double angle_end = 900 - angle_start;
571  for( double angle = angle_start; angle < angle_end; angle += 100 )
572  {
573  pos = startpos;
574  RotatePoint( &pos, angle );
575  aBuffer.push_back( pos );
576  }
577 
578  // Last point
579  pos = startpos;
580  RotatePoint( &pos, angle_end );
581  aBuffer.push_back( pos );
582 
583  // outer arc
584  startpos.x = outerRadius;
585  startpos.y = 0;
586  angle_start = RAD2DECIDEG( asin( (double) halfthickness / outerRadius ) );
587  angle_end = 900 - angle_start;
588 
589  // First point, near Y axis, outer arc
590  for( double angle = angle_end; angle > angle_start; angle -= 100 )
591  {
592  pos = startpos;
593  RotatePoint( &pos, angle );
594  aBuffer.push_back( pos );
595  }
596 
597  // last point
598  pos = startpos;
599  RotatePoint( &pos, angle_start );
600  aBuffer.push_back( pos );
601 
602  aBuffer.push_back( aBuffer[0] ); // Close poly
603  }
604  break;
605 
606  case AMP_MOIRE: // A cross hair with n concentric circles. Only the cros is build as polygon
607  // because circles can be drawn easily
608  {
609  int crossHairThickness = scaletoIU( params[6].GetValue( tool ), m_GerbMetric );
610  int crossHairLength = scaletoIU( params[7].GetValue( tool ), m_GerbMetric );
611 
612  // Create cross. First create 1/4 of the shape.
613  // Others point are the same, totated by 90, 180 and 270 deg
614  wxPoint pos( crossHairThickness / 2, crossHairLength / 2 );
615  aBuffer.push_back( pos );
616  pos.y = crossHairThickness / 2;
617  aBuffer.push_back( pos );
618  pos.x = -crossHairLength / 2;
619  aBuffer.push_back( pos );
620  pos.y = -crossHairThickness / 2;
621  aBuffer.push_back( pos );
622 
623  // Copy the 4 shape, rotated by 90, 180 and 270 deg
624  for( int jj = 1; jj <= 3; jj ++ )
625  {
626  for( int ii = 0; ii < 4; ii++ )
627  {
628  pos = aBuffer[ii];
629  RotatePoint( &pos, jj*900 );
630  aBuffer.push_back( pos );
631  }
632  }
633  }
634  break;
635 
636  case AMP_OUTLINE:
637  // already is a polygon. Do nothing
638  break;
639 
640  case AMP_POLYGON: // Creates a regular polygon
641  {
642  int vertexcount = KiROUND( params[1].GetValue( tool ) );
643  int radius = scaletoIU( params[4].GetValue( tool ), m_GerbMetric ) / 2;
644  // rs274x said: vertex count = 3 ... 10, and the first corner is on the X axis
645  if( vertexcount < 3 )
646  vertexcount = 3;
647  if( vertexcount > 10 )
648  vertexcount = 10;
649  for( int ii = 0; ii <= vertexcount; ii++ )
650  {
651  wxPoint pos( radius, 0);
652  RotatePoint( &pos, ii * 3600 / vertexcount );
653  aBuffer.push_back( pos );
654  }
655  }
656  break;
657 
658  case AMP_COMMENT:
659  case AMP_UNKNOWN:
660  case AMP_EOF:
661  break;
662  }
663 }
664 
676 {
677  int dim = -1;
678  D_CODE* tool = aParent->GetDcodeDescr();
679 
680  switch( primitive_id )
681  {
682  case AMP_CIRCLE:
683  // params = exposure, diameter, pos.x, pos.y
684  dim = scaletoIU( params[1].GetValue( tool ), m_GerbMetric ); // Diameter
685  break;
686 
687  case AMP_LINE2:
688  case AMP_LINE20: // Line with rectangle ends. (Width, start and end pos + rotation)
689  dim = scaletoIU( params[1].GetValue( tool ), m_GerbMetric ); // linne width
690  break;
691 
692  case AMP_LINE_CENTER:
693  {
694  wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ), m_GerbMetric );
695  dim = std::min(size.x, size.y);
696  }
697  break;
698 
699  case AMP_LINE_LOWER_LEFT:
700  {
701  wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ), m_GerbMetric );
702  dim = std::min(size.x, size.y);
703  }
704  break;
705 
706  case AMP_THERMAL:
707  {
708  // Only 1/4 of the full shape is built, because the other 3 shapes will be draw from this first
709  // rotated by 90, 180 and 270 deg.
710  // params = center.x (unused here), center.y (unused here), outside diam, inside diam, crosshair thickness
711  dim = scaletoIU( params[2].GetValue( tool ), m_GerbMetric ) / 2; // Outer diam
712  }
713  break;
714 
715  case AMP_MOIRE: // A cross hair with n concentric circles.
716  dim = scaletoIU( params[7].GetValue( tool ), m_GerbMetric ); // = cross hair len
717  break;
718 
719  case AMP_OUTLINE: // a free polygon :
720  // dim = min side of the bounding box (this is a poor criteria, but what is a good criteria b?)
721  {
722  // exposure, corners count, corner1.x, corner.1y, ..., rotation
723  // note: corners count is the count of corners following corner1
724  int numPoints = (int) params[1].GetValue( tool );
725  // Read points. numPoints does not include the starting point, so add 1.
726  // and calculate the bounding box;
727  wxSize pos_min, pos_max, pos;
728  int prm_idx = 2; // params[2] is the first X coordinate
729  int last_prm = params.size() - 1;
730 
731  for( int i = 0; i<= numPoints; ++i )
732  {
733  pos.x = scaletoIU( params[prm_idx].GetValue( tool ), m_GerbMetric );
734  prm_idx++;
735  pos.y = scaletoIU( params[prm_idx].GetValue( tool ), m_GerbMetric );
736  prm_idx++;
737  if( i == 0 )
738  pos_min = pos_max = pos;
739  else
740  {
741  // upper right corner:
742  if( pos_min.x > pos.x )
743  pos_min.x = pos.x;
744  if( pos_min.y > pos.y )
745  pos_min.y = pos.y;
746  // lower left corner:
747  if( pos_max.x < pos.x )
748  pos_max.x = pos.x;
749  if( pos_max.y < pos.y )
750  pos_max.y = pos.y;
751  }
752 
753  // Guard: ensure prm_idx < last_prm (last prm is orientation)
754  // I saw malformed gerber files with numCorners = number
755  // of coordinates instead of number of coordinates following the first point
756  if( prm_idx >= last_prm )
757  break;
758  }
759  // calculate dim
760  wxSize size;
761  size.x = pos_max.x - pos_min.x;
762  size.y = pos_max.y - pos_min.y;
763  dim = std::min( size.x, size.y );
764  }
765  break;
766 
767  case AMP_POLYGON: // Regular polygon
768  dim = scaletoIU( params[4].GetValue( tool ), m_GerbMetric ) / 2; // Radius
769  break;
770 
771  case AMP_COMMENT:
772  case AMP_UNKNOWN:
773  case AMP_EOF:
774  break;
775  }
776  return dim;
777 }
778 
779 
781  wxPoint aShapePos )
782 {
783  SHAPE_POLY_SET holeBuffer;
784  bool hasHole = false;
785 
787 
788  for( AM_PRIMITIVES::iterator prim_macro = primitives.begin();
789  prim_macro != primitives.end(); ++prim_macro )
790  {
791  if( prim_macro->primitive_id == AMP_COMMENT )
792  continue;
793 
794  if( prim_macro->IsAMPrimitiveExposureOn( aParent ) )
795  prim_macro->DrawBasicShape( aParent, m_shape, aShapePos );
796  else
797  {
798  prim_macro->DrawBasicShape( aParent, holeBuffer, aShapePos );
799 
800  if( holeBuffer.OutlineCount() ) // we have a new hole in shape: remove the hole
801  {
803  holeBuffer.RemoveAllContours();
804  hasHole = true;
805  }
806  }
807  }
808 
809  // If a hole is defined inside a polygon, we must fracture the polygon
810  // to be able to drawn it (i.e link holes by overlapping edges)
811  if( hasHole )
813 
814  m_boundingBox = EDA_RECT( wxPoint( 0, 0 ), wxSize( 1, 1 ) );
815  auto bb = m_shape.BBox();
816  wxPoint center( bb.Centre().x, bb.Centre().y );
817  m_boundingBox.Move( aParent->GetABPosition( center ) );
818  m_boundingBox.Inflate( bb.GetWidth() / 2, bb.GetHeight() / 2 );
819 
820  return &m_shape;
821 }
822 
823 
824 /*
825  * Function DrawApertureMacroShape
826  * Draw the primitive shape for flashed items.
827  * When an item is flashed, this is the shape of the item
828  */
830  EDA_RECT* aClipBox, wxDC* aDC,
831  COLOR4D aColor,
832  wxPoint aShapePos, bool aFilledShape )
833 {
834  SHAPE_POLY_SET* shapeBuffer = GetApertureMacroShape( aParent, aShapePos );
835 
836  if( shapeBuffer->OutlineCount() == 0 )
837  return;
838 
839  for( int ii = 0; ii < shapeBuffer->OutlineCount(); ii++ )
840  {
841  SHAPE_LINE_CHAIN& poly = shapeBuffer->Outline( ii );
842 
843  GRClosedPoly( aClipBox, aDC, poly.PointCount(), (wxPoint*) &poly.CPoint( 0 ), aFilledShape,
844  aColor, aColor );
845  }
846 }
847 
859 {
860  int dim = -1;
861  for( AM_PRIMITIVES::iterator prim_macro = primitives.begin();
862  prim_macro != primitives.end(); ++prim_macro )
863  {
864  int pdim = prim_macro->GetShapeDim( aParent );
865  if( dim < pdim )
866  dim = pdim;
867  }
868 
869  return dim;
870 }
871 
872 
883 double APERTURE_MACRO::GetLocalParam( const D_CODE* aDcode, unsigned aParamId ) const
884 {
885  // find parameter descr.
886  const AM_PARAM * param = NULL;
887 
888  for( unsigned ii = 0; ii < m_localparamStack.size(); ii ++ )
889  {
890  if( m_localparamStack[ii].GetIndex() == aParamId )
891  {
892  param = &m_localparamStack[ii];
893  break;
894  }
895  }
896 
897  if ( param == NULL ) // not found
898  return 0.0;
899 
900  // Evaluate parameter
901  double value = param->GetValue( aDcode );
902 
903  return value;
904 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:134
bool m_GerbMetric
Definition: am_primitive.h:97
double GetValue(const D_CODE *aDcode) const
Definition: am_param.cpp:74
void Move(const wxPoint &aMoveVector)
Function Move moves the rectangle by the aMoveVector.
Definition: eda_rect.cpp:51
D_CODE * GetDcodeDescr() const
Function GetDcodeDescr returns the GetDcodeDescr of this object, or NULL.
int OutlineCount() const
Returns the number of outlines in the set
void DrawBasicShape(const GERBER_DRAW_ITEM *aParent, SHAPE_POLY_SET &aShapeBuffer, wxPoint aShapePos)
Function drawBasicShape Draw (in fact generate the actual polygonal shape of) the primitive shape of ...
void DrawApertureMacroShape(GERBER_DRAW_ITEM *aParent, EDA_RECT *aClipBox, wxDC *aDC, COLOR4D aColor, wxPoint aShapePos, bool aFilledShape)
Function DrawApertureMacroShape Draw the primitive shape for flashed items.
bool IsAMPrimitiveExposureOn(const GERBER_DRAW_ITEM *aParent) const
Function IsAMPrimitiveExposureOn.
double RAD2DECIDEG(double rad)
Definition: trigo.h:225
EDA_RECT m_boundingBox
The bounding box of the item, calculated by GetApertureMacroShape.
Definition: am_primitive.h:176
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:208
int PointCount() const
Function PointCount()
double GetLocalParam(const D_CODE *aDcode, unsigned aParamId) const
function GetLocalParam Usually, parameters are defined inside the aperture primitive using immediate ...
int GetShapeDim(const GERBER_DRAW_ITEM *aParent)
GetShapeDim Calculate a value that can be used to evaluate the size of text when displaying the D-Cod...
AM_PARAMS m_localparamStack
Definition: am_primitive.h:173
int scaletoIU(double aCoord, bool isMetric)
Function scaletoIU converts a distance given in floating point to our internal units.
const VECTOR2I & CPoint(int aIndex) const
Function Point()
void ConvertShapeToPolygon(const GERBER_DRAW_ITEM *aParent, std::vector< wxPoint > &aBuffer)
Function ConvertShapeToPolygon convert a shape to an equivalent polygon.
wxPoint GetABPosition(const wxPoint &aXYPosition) const
Function GetABPosition returns the image position of aPosition for this object.
SHAPE_POLY_SET * GetApertureMacroShape(const GERBER_DRAW_ITEM *aParent, wxPoint aShapePos)
Function GetApertureMacroShape Calculate the primitive shape for flashed items.
#define NULL
SHAPE_POLY_SET.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Returns the reference to aIndex-th outline in the set
AM_PARAM holds a parameter value for an "aperture macro" as defined within standard RS274X.
Definition: am_param.h:286
#define TO_POLY_SHAPE
const int seg_per_circle
static wxPoint mapPt(double x, double y, bool isMetric)
Function mapPt translates a point from the aperture macro coordinate system to our deci-mils coordina...
void Fracture(POLYGON_MODE aFastMode)
Converts a set of polygons with holes to a singe outline with "slits"/"fractures" connecting the oute...
void TransformCircleToPolygon(SHAPE_POLY_SET &aCornerBuffer, wxPoint aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc)
Function TransformCircleToPolygon convert a circle to a polygon, using multiple straight lines.
SHAPE_POLY_SET m_shape
The shape of the item, calculated by GetApertureMacroShape.
Definition: am_primitive.h:175
AM_PRIMITIVES primitives
A sequence of AM_PRIMITIVEs.
Definition: am_primitive.h:165
D_CODE holds a gerber DCODE (also called Aperture) definition.
Definition: dcode.h:82
SHAPE_LINE_CHAIN.
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
void RemoveAllContours()
Removes all outlines & holes (clears) the polygon set.
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
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:68
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Performs boolean polyset difference For aFastMode meaning, see function booleanOp
double ArcTangente(int dy, int dx)
Definition: trigo.cpp:162
int GetShapeDim(GERBER_DRAW_ITEM *aParent)
Function GetShapeDim Calculate a value that can be used to evaluate the size of text when displaying ...
void GRClosedPoly(EDA_RECT *ClipBox, wxDC *DC, int n, const wxPoint *Points, bool Fill, COLOR4D Color, COLOR4D BgColor)
Function GRClosedPoly draws a closed polygon onto the drawing context aDC and optionally fills and/or...
Definition: gr_basic.cpp:550
const BOX2I BBox(int aClearance=0) const override
Function BBox()
AM_PARAMS params
A sequence of parameters used by.
Definition: am_primitive.h:95
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
Definition: eda_rect.cpp:363
void TransformRingToPolygon(SHAPE_POLY_SET &aCornerBuffer, wxPoint aCentre, int aRadius, int aWidth, int aError, ERROR_LOC aErrorLoc)
Function TransformRingToPolygon Creates a polygon from a ring Convert arcs to multiple straight segme...
AM_PRIMITIVE_ID primitive_id
The primitive type.
Definition: am_primitive.h:94
COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:100