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-2019 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 <fctsys.h>
31 #include <common.h>
32 #include <macros.h>
33 #include <trigo.h>
34 #include <convert_to_biu.h>
36 #include <gr_basic.h>
37 #include <math/util.h> // for KiROUND
38 
39 #include <gerbview.h>
40 #include <gerber_file_image.h>
41 
42 
43 
48 extern int scaletoIU( double aCoord, bool isMetric ); // defined it rs274d_read_XY_and_IJ_coordiantes.cpp
49 
56 static wxPoint mapPt( double x, double y, bool isMetric )
57 {
58  wxPoint ret( scaletoIU( x, isMetric ), scaletoIU( y, isMetric ) );
59 
60  return ret;
61 }
62 
63 
65 {
66  /*
67  * Some but not all primitives use the first parameter as an exposure control.
68  * Others are always ON.
69  * In a aperture macro shape, a basic primitive with exposure off is a hole in the shape
70  * it is NOT a negative shape
71  */
72  wxASSERT( params.size() );
73 
74  switch( primitive_id )
75  {
76  case AMP_CIRCLE:
77  case AMP_LINE2:
78  case AMP_LINE20:
79  case AMP_LINE_CENTER:
81  case AMP_OUTLINE:
82  case AMP_POLYGON:
83  // All have an exposure parameter and can return a value (0 or 1)
84  return params[0].GetValue( aParent->GetDcodeDescr() ) != 0;
85  break;
86 
87  case AMP_THERMAL: // Exposure is always on
88  case AMP_MOIRE: // Exposure is always on
89  case AMP_EOF:
90  case AMP_UNKNOWN:
91  default:
92  return 1; // All have no exposure parameter and are always 0N return true
93  break;
94  }
95 }
96 
97 // TODO(snh): Remove hard coded count
98 const int seg_per_circle = 64; // Number of segments to approximate a circle
99 
101  SHAPE_POLY_SET& aShapeBuffer,
102  wxPoint aShapePos )
103 {
104  #define TO_POLY_SHAPE { aShapeBuffer.NewOutline(); \
105  for( unsigned jj = 0; jj < polybuffer.size(); jj++ )\
106  aShapeBuffer.Append( polybuffer[jj].x, polybuffer[jj].y );\
107  aShapeBuffer.Append( polybuffer[0].x, polybuffer[0].y );}
108 
109  // Draw the primitive shape for flashed items.
110  static std::vector<wxPoint> polybuffer; // create a static buffer to avoid a lot of memory reallocation
111  polybuffer.clear();
112 
113  wxPoint curPos = aShapePos;
114  D_CODE* tool = aParent->GetDcodeDescr();
115  double rotation;
116 
117  switch( primitive_id )
118  {
119  case AMP_CIRCLE: // Circle, given diameter and position
120  {
121  /* Generated by an aperture macro declaration like:
122  * "1,1,0.3,0.5, 1.0*"
123  * type (1), exposure, diameter, pos.x, pos.y, <rotation>
124  * <rotation> is a optional parameter: rotation from origin.
125  * type is not stored in parameters list, so the first parameter is exposure
126  */
127  ConvertShapeToPolygon( aParent, polybuffer );
128 
129  // shape rotation (if any):
130  if( params.size() >= 5 )
131  {
132  rotation = params[4].GetValue( tool ) * 10.0;
133 
134  if( rotation != 0)
135  {
136  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
137  RotatePoint( &polybuffer[ii], -rotation );
138  }
139  }
140 
141 
142  // Move to current position:
143  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
144  {
145  polybuffer[ii] += curPos;
146  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
147  }
148 
150  }
151  break;
152 
153  case AMP_LINE2:
154  case AMP_LINE20: // Line with rectangle ends. (Width, start and end pos + rotation)
155  {
156  /* Vector Line, Primitive Code 20.
157  * A vector line is a rectangle defined by its line width, start and end points.
158  * The line ends are rectangular.
159  */
160  /* Generated by an aperture macro declaration like:
161  * "2,1,0.3,0,0, 0.5, 1.0,-135*"
162  * type (2), exposure, width, start.x, start.y, end.x, end.y, rotation
163  * type is not stored in parameters list, so the first parameter is exposure
164  */
165  ConvertShapeToPolygon( aParent, polybuffer );
166 
167  // shape rotation:
168  rotation = params[6].GetValue( tool ) * 10.0;
169 
170  if( rotation != 0)
171  {
172  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
173  RotatePoint( &polybuffer[ii], -rotation );
174  }
175 
176  // Move to current position:
177  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
178  {
179  polybuffer[ii] += curPos;
180  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
181  }
182 
184  }
185  break;
186 
187  case AMP_LINE_CENTER:
188  {
189  /* Center Line, Primitive Code 21
190  * A center line primitive is a rectangle defined by its width, height, and center point
191  */
192  /* Generated by an aperture macro declaration like:
193  * "21,1,0.3,0.03,0,0,-135*"
194  * type (21), exposure, ,width, height, center pos.x, center pos.y, rotation
195  * type is not stored in parameters list, so the first parameter is exposure
196  */
197  ConvertShapeToPolygon( aParent, polybuffer );
198 
199  // shape rotation:
200  rotation = params[5].GetValue( tool ) * 10.0;
201 
202  if( rotation != 0 )
203  {
204  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
205  RotatePoint( &polybuffer[ii], -rotation );
206  }
207 
208  // Move to current position:
209  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
210  {
211  polybuffer[ii] += curPos;
212  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
213  }
214 
216  }
217  break;
218 
219  case AMP_LINE_LOWER_LEFT:
220  {
221  /* Generated by an aperture macro declaration like:
222  * "22,1,0.3,0.03,0,0,-135*"
223  * type (22), exposure, ,width, height, corner pos.x, corner pos.y, rotation
224  * type is not stored in parameters list, so the first parameter is exposure
225  */
226  ConvertShapeToPolygon( aParent, polybuffer );
227 
228  // shape rotation:
229  rotation = params[5].GetValue( tool ) * 10.0;
230  if( rotation != 0)
231  {
232  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
233  RotatePoint( &polybuffer[ii], -rotation );
234  }
235 
236  // Move to current position:
237  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
238  {
239  polybuffer[ii] += curPos;
240  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
241  }
242 
244  }
245  break;
246 
247  case AMP_THERMAL:
248  {
249  /* Generated by an aperture macro declaration like:
250  * "7, 0,0,1.0,0.3,0.01,-13*"
251  * type (7), center.x , center.y, outside diam, inside diam, crosshair thickness, rotation
252  * type is not stored in parameters list, so the first parameter is center.x
253  *
254  * The thermal primitive is a ring (annulus) interrupted by four gaps. Exposure is always on.
255  */
256  std::vector<wxPoint> subshape_poly;
257  curPos += mapPt( params[0].GetValue( tool ), params[1].GetValue( tool ), m_GerbMetric );
258  ConvertShapeToPolygon( aParent, subshape_poly );
259 
260  // shape rotation:
261  rotation = params[5].GetValue( tool ) * 10.0;
262 
263  // Because a thermal shape has 4 identical sub-shapes, only one is created in subshape_poly.
264  // We must draw 4 sub-shapes rotated by 90 deg
265  for( int ii = 0; ii < 4; ii++ )
266  {
267  polybuffer = subshape_poly;
268  double sub_rotation = rotation + 900 * ii;
269 
270  for( unsigned jj = 0; jj < polybuffer.size(); jj++ )
271  RotatePoint( &polybuffer[jj], -sub_rotation );
272 
273  // Move to current position:
274  for( unsigned jj = 0; jj < polybuffer.size(); jj++ )
275  {
276  polybuffer[jj] += curPos;
277  polybuffer[jj] = aParent->GetABPosition( polybuffer[jj] );
278  }
279 
281  }
282  }
283  break;
284 
285  case AMP_MOIRE:
286  {
287  /* Moir�, Primitive Code 6
288  * The moir� primitive is a cross hair centered on concentric rings (annuli).
289  * Exposure is always on.
290  */
291  curPos += mapPt( params[0].GetValue( tool ), params[1].GetValue( tool ),
292  m_GerbMetric );
293 
294  /* Generated by an aperture macro declaration like:
295  * "6,0,0,0.125,.01,0.01,3,0.003,0.150,0"
296  * type(6), pos.x, pos.y, diam, penwidth, gap, circlecount, crosshair thickness, crosshaire len, rotation
297  * type is not stored in parameters list, so the first parameter is pos.x
298  */
299  int outerDiam = scaletoIU( params[2].GetValue( tool ), m_GerbMetric );
300  int penThickness = scaletoIU( params[3].GetValue( tool ), m_GerbMetric );
301  int gap = scaletoIU( params[4].GetValue( tool ), m_GerbMetric );
302  int numCircles = KiROUND( params[5].GetValue( tool ) );
303 
304  // Draw circles:
305  wxPoint center = aParent->GetABPosition( curPos );
306  // adjust outerDiam by this on each nested circle
307  int diamAdjust = (gap + penThickness) * 2;
308 
309  for( int i = 0; i < numCircles; ++i, outerDiam -= diamAdjust )
310  {
311  if( outerDiam <= 0 )
312  break;
313 
314  // Note: outerDiam is the outer diameter of the ring.
315  // the ring graphic diameter is (outerDiam - penThickness)
316  if( outerDiam <= penThickness )
317  { // No room to draw a ring (no room for the hole):
318  // draw a circle instead (with no hole), with the right diameter
319  TransformCircleToPolygon( aShapeBuffer, center, outerDiam / 2, ARC_HIGH_DEF );
320  }
321  else
322  TransformRingToPolygon( aShapeBuffer, center, ( outerDiam - penThickness ) / 2,
323  ARC_HIGH_DEF, penThickness );
324  }
325 
326  // Draw the cross:
327  ConvertShapeToPolygon( aParent, polybuffer );
328 
329  rotation = params[8].GetValue( tool ) * 10.0;
330  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
331  {
332  // shape rotation:
333  RotatePoint( &polybuffer[ii], -rotation );
334  // Move to current position:
335  polybuffer[ii] += curPos;
336  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
337  }
338 
340  }
341  break;
342 
343  case AMP_OUTLINE:
344  {
345  /* Outline, Primitive Code 4
346  * An outline primitive is an area enclosed by an n-point polygon defined by its start point and n
347  * subsequent points. The outline must be closed, i.e. the last point must be equal to the start
348  * point. There must be at least one subsequent point (to close the outline).
349  * The outline of the primitive is actually the contour (see 2.6) that consists of linear segments
350  * only, so it must conform to all the requirements described for contours.
351  * Warning: Make no mistake: n is the number of subsequent points, being the number of
352  * vertices of the outline or one less than the number of coordinate pairs.
353  */
354  /* Generated by an aperture macro declaration like:
355  * "4,1,3,0.0,0.0,0.0,0.5,0.5,0.5,0.5,0.0,-25"
356  * type(4), exposure, corners count, corner1.x, corner.1y, ..., corner1.x, corner.1y, rotation
357  * type is not stored in parameters list, so the first parameter is exposure
358  */
359  // params[0] is the exposure and params[1] is the corners count after the first corner
360  int numCorners = (int) params[1].GetValue( tool );
361  // the shape rotation is the last param of list, after corners
362  int last_prm = params.size() - 1;
363  rotation = params[last_prm].GetValue( tool ) * 10.0;
364  wxPoint pos;
365 
366  // Read points.
367  // Note: numCorners is the polygon corner count, following the first corner
368  // * the polygon is always closed,
369  // * therefore the last XY coordinate is the same as the first
370  int prm_idx = 2; // params[2] is the first X coordinate
371  for( int i = 0; i <= numCorners; ++i )
372  {
373  pos.x = scaletoIU( params[prm_idx].GetValue( tool ), m_GerbMetric );
374  prm_idx++;
375  pos.y = scaletoIU( params[prm_idx].GetValue( tool ), m_GerbMetric );
376  prm_idx++;
377  polybuffer.push_back(pos);
378 
379  // Guard: ensure prm_idx < last_prm
380  // I saw malformed gerber files with numCorners = number
381  // of coordinates instead of number of coordinates following the first point
382  if( prm_idx >= last_prm )
383  break;
384  }
385  // rotate polygon and move it to the actual position
386  // shape rotation:
387  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
388  {
389  RotatePoint( &polybuffer[ii], -rotation );
390  }
391 
392  // Move to current position:
393  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
394  {
395  polybuffer[ii] += curPos;
396  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
397  }
398 
400  }
401  break;
402 
403  case AMP_POLYGON:
404  /* Polygon, Primitive Code 5
405  * A polygon primitive is a regular polygon defined by the number of vertices n, the center point
406  * and the diameter of the circumscribed circle
407  */
408  /* Generated by an aperture macro declaration like:
409  * "5,1,0.6,0,0,0.5,25"
410  * type(5), exposure, vertices count, pox.x, pos.y, diameter, rotation
411  * type is not stored in parameters list, so the first parameter is exposure
412  */
413  curPos += mapPt( params[2].GetValue( tool ), params[3].GetValue( tool ), m_GerbMetric );
414  // Creates the shape:
415  ConvertShapeToPolygon( aParent, polybuffer );
416 
417  // rotate polygon and move it to the actual position
418  rotation = params[5].GetValue( tool ) * 10.0;
419  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
420  {
421  RotatePoint( &polybuffer[ii], -rotation );
422  polybuffer[ii] += curPos;
423  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
424  }
425 
427 
428  break;
429 
430  case AMP_EOF:
431  // not yet supported, waiting for you.
432  break;
433 
434  case AMP_UNKNOWN:
435  default:
436  DBG( printf( "AM_PRIMITIVE::DrawBasicShape() err: unknown prim id %d\n",primitive_id) );
437  break;
438  }
439 }
440 
441 
453  std::vector<wxPoint>& aBuffer )
454 {
455  D_CODE* tool = aParent->GetDcodeDescr();
456 
457  switch( primitive_id )
458  {
459  case AMP_CIRCLE:
460  {
461  /* Generated by an aperture macro declaration like:
462  * "1,1,0.3,0.5, 1.0*"
463  * type (1), exposure, diameter, pos.x, pos.y, <rotation>
464  * <rotation> is a optional parameter: rotation from origin.
465  * type is not stored in parameters list, so the first parameter is exposure
466  */
467  wxPoint center = mapPt( params[2].GetValue( tool ), params[3].GetValue( tool ), m_GerbMetric );
468  int radius = scaletoIU( params[1].GetValue( tool ), m_GerbMetric ) / 2;
469  wxPoint corner;
470  const int delta = 3600 / seg_per_circle; // rot angle in 0.1 degree
471 
472  for( int angle = 0; angle < 3600; angle += delta )
473  {
474  corner.x = radius;
475  corner.y = 0;
476  RotatePoint( &corner, angle );
477  corner += center;
478  aBuffer.push_back( corner );
479  }
480  }
481  break;
482 
483  case AMP_LINE2:
484  case AMP_LINE20: // Line with rectangle ends. (Width, start and end pos + rotation)
485  {
486  int width = scaletoIU( params[1].GetValue( tool ), m_GerbMetric );
487  wxPoint start = mapPt( params[2].GetValue( tool ),
488  params[3].GetValue( tool ), m_GerbMetric );
489  wxPoint end = mapPt( params[4].GetValue( tool ),
490  params[5].GetValue( tool ), m_GerbMetric );
491  wxPoint delta = end - start;
492  int len = KiROUND( EuclideanNorm( delta ) );
493 
494  // To build the polygon, we must create a horizontal polygon starting to "start"
495  // and rotate it to have the end point to "end"
496  wxPoint currpt;
497  currpt.y += width / 2; // Upper left
498  aBuffer.push_back( currpt );
499  currpt.x = len; // Upper right
500  aBuffer.push_back( currpt );
501  currpt.y -= width; // lower right
502  aBuffer.push_back( currpt );
503  currpt.x = 0; // lower left
504  aBuffer.push_back( currpt );
505 
506  // Rotate rectangle and move it to the actual start point
507  double angle = ArcTangente( delta.y, delta.x );
508 
509  for( unsigned ii = 0; ii < 4; ii++ )
510  {
511  RotatePoint( &aBuffer[ii], -angle );
512  aBuffer[ii] += start;
513  }
514  }
515  break;
516 
517  case AMP_LINE_CENTER:
518  {
519  wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ), m_GerbMetric );
520  wxPoint pos = mapPt( params[3].GetValue( tool ), params[4].GetValue( tool ), m_GerbMetric );
521 
522  // Build poly:
523  pos.x -= size.x / 2;
524  pos.y -= size.y / 2; // Lower left
525  aBuffer.push_back( pos );
526  pos.y += size.y; // Upper left
527  aBuffer.push_back( pos );
528  pos.x += size.x; // Upper right
529  aBuffer.push_back( pos );
530  pos.y -= size.y; // lower right
531  aBuffer.push_back( pos );
532  }
533  break;
534 
535  case AMP_LINE_LOWER_LEFT:
536  {
537  wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ), m_GerbMetric );
538  wxPoint lowerLeft = mapPt( params[3].GetValue( tool ), params[4].GetValue(
539  tool ), m_GerbMetric );
540 
541  // Build poly:
542  aBuffer.push_back( lowerLeft );
543  lowerLeft.y += size.y; // Upper left
544  aBuffer.push_back( lowerLeft );
545  lowerLeft.x += size.x; // Upper right
546  aBuffer.push_back( lowerLeft );
547  lowerLeft.y -= size.y; // lower right
548  aBuffer.push_back( lowerLeft );
549  }
550  break;
551 
552  case AMP_THERMAL:
553  {
554  // Only 1/4 of the full shape is built, because the other 3 shapes will be draw from this first
555  // rotated by 90, 180 and 270 deg.
556  // params = center.x (unused here), center.y (unused here), outside diam, inside diam, crosshair thickness
557  int outerRadius = scaletoIU( params[2].GetValue( tool ), m_GerbMetric ) / 2;
558  int innerRadius = scaletoIU( params[3].GetValue( tool ), m_GerbMetric ) / 2;
559 
560  // Safety checks to guarantee no divide-by-zero
561  outerRadius = std::max( 1, outerRadius );
562  innerRadius = std::max( 1, innerRadius );
563 
564  int halfthickness = scaletoIU( params[4].GetValue( tool ), m_GerbMetric ) / 2;
565  double angle_start = RAD2DECIDEG( asin( (double) halfthickness / innerRadius ) );
566 
567  // Draw shape in the first cadrant (X and Y > 0)
568  wxPoint pos, startpos;
569 
570  // Inner arc
571  startpos.x = innerRadius;
572  double angle_end = 900 - angle_start;
573  for( double angle = angle_start; angle < angle_end; angle += 100 )
574  {
575  pos = startpos;
576  RotatePoint( &pos, angle );
577  aBuffer.push_back( pos );
578  }
579 
580  // Last point
581  pos = startpos;
582  RotatePoint( &pos, angle_end );
583  aBuffer.push_back( pos );
584 
585  // outer arc
586  startpos.x = outerRadius;
587  startpos.y = 0;
588  angle_start = RAD2DECIDEG( asin( (double) halfthickness / outerRadius ) );
589  angle_end = 900 - angle_start;
590 
591  // First point, near Y axis, outer arc
592  for( double angle = angle_end; angle > angle_start; angle -= 100 )
593  {
594  pos = startpos;
595  RotatePoint( &pos, angle );
596  aBuffer.push_back( pos );
597  }
598 
599  // last point
600  pos = startpos;
601  RotatePoint( &pos, angle_start );
602  aBuffer.push_back( pos );
603 
604  aBuffer.push_back( aBuffer[0] ); // Close poly
605  }
606  break;
607 
608  case AMP_MOIRE: // A cross hair with n concentric circles. Only the cros is build as polygon
609  // because circles can be drawn easily
610  {
611  int crossHairThickness = scaletoIU( params[6].GetValue( tool ), m_GerbMetric );
612  int crossHairLength = scaletoIU( params[7].GetValue( tool ), m_GerbMetric );
613 
614  // Create cross. First create 1/4 of the shape.
615  // Others point are the same, totated by 90, 180 and 270 deg
616  wxPoint pos( crossHairThickness / 2, crossHairLength / 2 );
617  aBuffer.push_back( pos );
618  pos.y = crossHairThickness / 2;
619  aBuffer.push_back( pos );
620  pos.x = -crossHairLength / 2;
621  aBuffer.push_back( pos );
622  pos.y = -crossHairThickness / 2;
623  aBuffer.push_back( pos );
624 
625  // Copy the 4 shape, rotated by 90, 180 and 270 deg
626  for( int jj = 1; jj <= 3; jj ++ )
627  {
628  for( int ii = 0; ii < 4; ii++ )
629  {
630  pos = aBuffer[ii];
631  RotatePoint( &pos, jj*900 );
632  aBuffer.push_back( pos );
633  }
634  }
635  }
636  break;
637 
638  case AMP_OUTLINE:
639  // already is a polygon. Do nothing
640  break;
641 
642  case AMP_POLYGON: // Creates a regular polygon
643  {
644  int vertexcount = KiROUND( params[1].GetValue( tool ) );
645  int radius = scaletoIU( params[4].GetValue( tool ), m_GerbMetric ) / 2;
646  // rs274x said: vertex count = 3 ... 10, and the first corner is on the X axis
647  if( vertexcount < 3 )
648  vertexcount = 3;
649  if( vertexcount > 10 )
650  vertexcount = 10;
651  for( int ii = 0; ii <= vertexcount; ii++ )
652  {
653  wxPoint pos( radius, 0);
654  RotatePoint( &pos, ii * 3600 / vertexcount );
655  aBuffer.push_back( pos );
656  }
657  }
658  break;
659 
660  case AMP_COMMENT:
661  case AMP_UNKNOWN:
662  case AMP_EOF:
663  break;
664  }
665 }
666 
678 {
679  int dim = -1;
680  D_CODE* tool = aParent->GetDcodeDescr();
681 
682  switch( primitive_id )
683  {
684  case AMP_CIRCLE:
685  // params = exposure, diameter, pos.x, pos.y
686  dim = scaletoIU( params[1].GetValue( tool ), m_GerbMetric ); // Diameter
687  break;
688 
689  case AMP_LINE2:
690  case AMP_LINE20: // Line with rectangle ends. (Width, start and end pos + rotation)
691  dim = scaletoIU( params[1].GetValue( tool ), m_GerbMetric ); // linne width
692  break;
693 
694  case AMP_LINE_CENTER:
695  {
696  wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ), m_GerbMetric );
697  dim = std::min(size.x, size.y);
698  }
699  break;
700 
701  case AMP_LINE_LOWER_LEFT:
702  {
703  wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ), m_GerbMetric );
704  dim = std::min(size.x, size.y);
705  }
706  break;
707 
708  case AMP_THERMAL:
709  {
710  // Only 1/4 of the full shape is built, because the other 3 shapes will be draw from this first
711  // rotated by 90, 180 and 270 deg.
712  // params = center.x (unused here), center.y (unused here), outside diam, inside diam, crosshair thickness
713  dim = scaletoIU( params[2].GetValue( tool ), m_GerbMetric ) / 2; // Outer diam
714  }
715  break;
716 
717  case AMP_MOIRE: // A cross hair with n concentric circles.
718  dim = scaletoIU( params[7].GetValue( tool ), m_GerbMetric ); // = cross hair len
719  break;
720 
721  case AMP_OUTLINE: // a free polygon :
722  // dim = min side of the bounding box (this is a poor criteria, but what is a good criteria b?)
723  {
724  // exposure, corners count, corner1.x, corner.1y, ..., rotation
725  // note: corners count is the count of corners following corner1
726  int numPoints = (int) params[1].GetValue( tool );
727  // Read points. numPoints does not include the starting point, so add 1.
728  // and calculate the bounding box;
729  wxSize pos_min, pos_max, pos;
730  int prm_idx = 2; // params[2] is the first X coordinate
731  int last_prm = params.size() - 1;
732 
733  for( int i = 0; i<= numPoints; ++i )
734  {
735  pos.x = scaletoIU( params[prm_idx].GetValue( tool ), m_GerbMetric );
736  prm_idx++;
737  pos.y = scaletoIU( params[prm_idx].GetValue( tool ), m_GerbMetric );
738  prm_idx++;
739  if( i == 0 )
740  pos_min = pos_max = pos;
741  else
742  {
743  // upper right corner:
744  if( pos_min.x > pos.x )
745  pos_min.x = pos.x;
746  if( pos_min.y > pos.y )
747  pos_min.y = pos.y;
748  // lower left corner:
749  if( pos_max.x < pos.x )
750  pos_max.x = pos.x;
751  if( pos_max.y < pos.y )
752  pos_max.y = pos.y;
753  }
754 
755  // Guard: ensure prm_idx < last_prm (last prm is orientation)
756  // I saw malformed gerber files with numCorners = number
757  // of coordinates instead of number of coordinates following the first point
758  if( prm_idx >= last_prm )
759  break;
760  }
761  // calculate dim
762  wxSize size;
763  size.x = pos_max.x - pos_min.x;
764  size.y = pos_max.y - pos_min.y;
765  dim = std::min( size.x, size.y );
766  }
767  break;
768 
769  case AMP_POLYGON: // Regular polygon
770  dim = scaletoIU( params[4].GetValue( tool ), m_GerbMetric ) / 2; // Radius
771  break;
772 
773  case AMP_COMMENT:
774  case AMP_UNKNOWN:
775  case AMP_EOF:
776  break;
777  }
778  return dim;
779 }
780 
781 
783  wxPoint aShapePos )
784 {
785  SHAPE_POLY_SET holeBuffer;
786  bool hasHole = false;
787 
789 
790  for( AM_PRIMITIVES::iterator prim_macro = primitives.begin();
791  prim_macro != primitives.end(); ++prim_macro )
792  {
793  if( prim_macro->primitive_id == AMP_COMMENT )
794  continue;
795 
796  if( prim_macro->IsAMPrimitiveExposureOn( aParent ) )
797  prim_macro->DrawBasicShape( aParent, m_shape, aShapePos );
798  else
799  {
800  prim_macro->DrawBasicShape( aParent, holeBuffer, aShapePos );
801 
802  if( holeBuffer.OutlineCount() ) // we have a new hole in shape: remove the hole
803  {
805  holeBuffer.RemoveAllContours();
806  hasHole = true;
807  }
808  }
809  }
810 
811  // If a hole is defined inside a polygon, we must fracture the polygon
812  // to be able to drawn it (i.e link holes by overlapping edges)
813  if( hasHole )
815 
816  m_boundingBox = EDA_RECT( wxPoint( 0, 0 ), wxSize( 1, 1 ) );
817  auto bb = m_shape.BBox();
818  wxPoint center( bb.Centre().x, bb.Centre().y );
819  m_boundingBox.Move( aParent->GetABPosition( center ) );
820  m_boundingBox.Inflate( bb.GetWidth() / 2, bb.GetHeight() / 2 );
821 
822  return &m_shape;
823 }
824 
825 
826 /*
827  * Function DrawApertureMacroShape
828  * Draw the primitive shape for flashed items.
829  * When an item is flashed, this is the shape of the item
830  */
832  EDA_RECT* aClipBox, wxDC* aDC,
833  COLOR4D aColor,
834  wxPoint aShapePos, bool aFilledShape )
835 {
836  SHAPE_POLY_SET* shapeBuffer = GetApertureMacroShape( aParent, aShapePos );
837 
838  if( shapeBuffer->OutlineCount() == 0 )
839  return;
840 
841  for( int ii = 0; ii < shapeBuffer->OutlineCount(); ii++ )
842  {
843  SHAPE_LINE_CHAIN& poly = shapeBuffer->Outline( ii );
844 
845  GRClosedPoly( aClipBox, aDC, poly.PointCount(), (wxPoint*) &poly.CPoint( 0 ), aFilledShape,
846  aColor, aColor );
847  }
848 }
849 
861 {
862  int dim = -1;
863  for( AM_PRIMITIVES::iterator prim_macro = primitives.begin();
864  prim_macro != primitives.end(); ++prim_macro )
865  {
866  int pdim = prim_macro->GetShapeDim( aParent );
867  if( dim < pdim )
868  dim = pdim;
869  }
870 
871  return dim;
872 }
873 
874 
885 double APERTURE_MACRO::GetLocalParam( const D_CODE* aDcode, unsigned aParamId ) const
886 {
887  // find parameter descr.
888  const AM_PARAM * param = NULL;
889 
890  for( unsigned ii = 0; ii < m_localparamStack.size(); ii ++ )
891  {
892  if( m_localparamStack[ii].GetIndex() == aParamId )
893  {
894  param = &m_localparamStack[ii];
895  break;
896  }
897  }
898 
899  if ( param == NULL ) // not found
900  return 0.0;
901 
902  // Evaluate parameter
903  double value = param->GetValue( aDcode );
904 
905  return value;
906 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:128
bool m_GerbMetric
Definition: am_primitive.h:98
double GetValue(const D_CODE *aDcode) const
Definition: am_param.cpp:71
void Move(const wxPoint &aMoveVector)
Function Move moves the rectangle by the aMoveVector.
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:219
EDA_RECT m_boundingBox
The bounding box of the item, calculated by GetApertureMacroShape.
Definition: am_primitive.h:177
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:174
This file contains miscellaneous commonly used macros and functions.
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...
SHAPE_POLY_SET m_shape
The shape of the item, calculated by GetApertureMacroShape.
Definition: am_primitive.h:176
AM_PRIMITIVES primitives
A sequence of AM_PRIMITIVEs.
Definition: am_primitive.h:166
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.
void TransformCircleToPolygon(SHAPE_POLY_SET &aCornerBuffer, wxPoint aCenter, int aRadius, int aError)
Function TransformCircleToPolygon convert a circle to a polygon, using multiple straight lines.
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
The common library.
void TransformRingToPolygon(SHAPE_POLY_SET &aCornerBuffer, wxPoint aCentre, int aRadius, int aError, int aWidth)
Function TransformRingToPolygon Creates a polygon from a ring Convert arcs to multiple straight segme...
#define DBG(x)
Definition: fctsys.h:33
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:554
const BOX2I BBox(int aClearance=0) const override
Function BBox()
AM_PARAMS params
A sequence of parameters used by.
Definition: am_primitive.h:96
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
AM_PRIMITIVE_ID primitive_id
The primitive type.
Definition: am_primitive.h:95
COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:99