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