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 
38 #include <gerbview.h>
39 #include <gerber_file_image.h>
40 
41 
42 
47 extern int scaletoIU( double aCoord, bool isMetric ); // defined it rs274d_read_XY_and_IJ_coordiantes.cpp
48 
55 static wxPoint mapPt( double x, double y, bool isMetric )
56 {
57  wxPoint ret( scaletoIU( x, isMetric ), scaletoIU( y, isMetric ) );
58 
59  return ret;
60 }
61 
62 
64 {
65  /*
66  * Some but not all primitives use the first parameter as an exposure control.
67  * Others are always ON.
68  * In a aperture macro shape, a basic primitive with exposure off is a hole in the shape
69  * it is NOT a negative shape
70  */
71  wxASSERT( params.size() );
72 
73  switch( primitive_id )
74  {
75  case AMP_CIRCLE:
76  case AMP_LINE2:
77  case AMP_LINE20:
78  case AMP_LINE_CENTER:
80  case AMP_OUTLINE:
81  case AMP_POLYGON:
82  // All have an exposure parameter and can return a value (0 or 1)
83  return params[0].GetValue( aParent->GetDcodeDescr() ) != 0;
84  break;
85 
86  case AMP_THERMAL: // Exposure is always on
87  case AMP_MOIRE: // Exposure is always on
88  case AMP_EOF:
89  case AMP_UNKNOWN:
90  default:
91  return 1; // All have no exposure parameter and are always 0N return true
92  break;
93  }
94 }
95 
96 // TODO(snh): Remove hard coded count
97 const int seg_per_circle = 64; // Number of segments to approximate a circle
98 
100  SHAPE_POLY_SET& aShapeBuffer,
101  wxPoint aShapePos )
102 {
103  #define TO_POLY_SHAPE { aShapeBuffer.NewOutline(); \
104  for( unsigned jj = 0; jj < polybuffer.size(); jj++ )\
105  aShapeBuffer.Append( polybuffer[jj].x, polybuffer[jj].y );\
106  aShapeBuffer.Append( polybuffer[0].x, polybuffer[0].y );}
107 
108  // Draw the primitive shape for flashed items.
109  static std::vector<wxPoint> polybuffer; // create a static buffer to avoid a lot of memory reallocation
110  polybuffer.clear();
111 
112  wxPoint curPos = aShapePos;
113  D_CODE* tool = aParent->GetDcodeDescr();
114  double rotation;
115 
116  switch( primitive_id )
117  {
118  case AMP_CIRCLE: // Circle, given diameter and position
119  {
120  /* Generated by an aperture macro declaration like:
121  * "1,1,0.3,0.5, 1.0*"
122  * type (1), exposure, diameter, pos.x, pos.y, <rotation>
123  * <rotation> is a optional parameter: rotation from origin.
124  * type is not stored in parameters list, so the first parameter is exposure
125  */
126  ConvertShapeToPolygon( aParent, polybuffer );
127 
128  // shape rotation (if any):
129  if( params.size() >= 5 )
130  {
131  rotation = params[4].GetValue( tool ) * 10.0;
132 
133  if( rotation != 0)
134  {
135  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
136  RotatePoint( &polybuffer[ii], -rotation );
137  }
138  }
139 
140 
141  // Move to current position:
142  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
143  {
144  polybuffer[ii] += curPos;
145  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
146  }
147 
149  }
150  break;
151 
152  case AMP_LINE2:
153  case AMP_LINE20: // Line with rectangle ends. (Width, start and end pos + rotation)
154  {
155  /* Vector Line, Primitive Code 20.
156  * A vector line is a rectangle defined by its line width, start and end points.
157  * The line ends are rectangular.
158  */
159  /* Generated by an aperture macro declaration like:
160  * "2,1,0.3,0,0, 0.5, 1.0,-135*"
161  * type (2), exposure, width, start.x, start.y, end.x, end.y, rotation
162  * type is not stored in parameters list, so the first parameter is exposure
163  */
164  ConvertShapeToPolygon( aParent, polybuffer );
165 
166  // shape rotation:
167  rotation = params[6].GetValue( tool ) * 10.0;
168 
169  if( rotation != 0)
170  {
171  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
172  RotatePoint( &polybuffer[ii], -rotation );
173  }
174 
175  // Move to current position:
176  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
177  {
178  polybuffer[ii] += curPos;
179  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
180  }
181 
183  }
184  break;
185 
186  case AMP_LINE_CENTER:
187  {
188  /* Center Line, Primitive Code 21
189  * A center line primitive is a rectangle defined by its width, height, and center point
190  */
191  /* Generated by an aperture macro declaration like:
192  * "21,1,0.3,0.03,0,0,-135*"
193  * type (21), exposure, ,width, height, center pos.x, center pos.y, rotation
194  * type is not stored in parameters list, so the first parameter is exposure
195  */
196  ConvertShapeToPolygon( aParent, polybuffer );
197 
198  // shape rotation:
199  rotation = params[5].GetValue( tool ) * 10.0;
200 
201  if( rotation != 0 )
202  {
203  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
204  RotatePoint( &polybuffer[ii], -rotation );
205  }
206 
207  // Move to current position:
208  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
209  {
210  polybuffer[ii] += curPos;
211  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
212  }
213 
215  }
216  break;
217 
218  case AMP_LINE_LOWER_LEFT:
219  {
220  /* Generated by an aperture macro declaration like:
221  * "22,1,0.3,0.03,0,0,-135*"
222  * type (22), exposure, ,width, height, corner pos.x, corner pos.y, rotation
223  * type is not stored in parameters list, so the first parameter is exposure
224  */
225  ConvertShapeToPolygon( aParent, polybuffer );
226 
227  // shape rotation:
228  rotation = params[5].GetValue( tool ) * 10.0;
229  if( rotation != 0)
230  {
231  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
232  RotatePoint( &polybuffer[ii], -rotation );
233  }
234 
235  // Move to current position:
236  for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
237  {
238  polybuffer[ii] += curPos;
239  polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
240  }
241 
243  }
244  break;
245 
246  case AMP_THERMAL:
247  {
248  /* Generated by an aperture macro declaration like:
249  * "7, 0,0,1.0,0.3,0.01,-13*"
250  * type (7), center.x , center.y, outside diam, inside diam, crosshair thickness, rotation
251  * type is not stored in parameters list, so the first parameter is center.x
252  *
253  * The thermal primitive is a ring (annulus) interrupted by four gaps. Exposure is always on.
254  */
255  std::vector<wxPoint> subshape_poly;
256  curPos += mapPt( params[0].GetValue( tool ), params[1].GetValue( tool ), m_GerbMetric );
257  ConvertShapeToPolygon( aParent, subshape_poly );
258 
259  // shape rotation:
260  rotation = params[5].GetValue( tool ) * 10.0;
261 
262  // Because a thermal shape has 4 identical sub-shapes, only one is created in subshape_poly.
263  // We must draw 4 sub-shapes rotated by 90 deg
264  for( int ii = 0; ii < 4; ii++ )
265  {
266  polybuffer = subshape_poly;
267  double sub_rotation = rotation + 900 * ii;
268 
269  for( unsigned jj = 0; jj < polybuffer.size(); jj++ )
270  RotatePoint( &polybuffer[jj], -sub_rotation );
271 
272  // Move to current position:
273  for( unsigned jj = 0; jj < polybuffer.size(); jj++ )
274  {
275  polybuffer[jj] += curPos;
276  polybuffer[jj] = aParent->GetABPosition( polybuffer[jj] );
277  }
278 
280  }
281  }
282  break;
283 
284  case AMP_MOIRE:
285  {
286  /* Moir�, Primitive Code 6
287  * The moir� primitive is a cross hair centered on concentric rings (annuli).
288  * Exposure is always on.
289  */
290  curPos += mapPt( params[0].GetValue( tool ), params[1].GetValue( tool ),
291  m_GerbMetric );
292 
293  /* Generated by an aperture macro declaration like:
294  * "6,0,0,0.125,.01,0.01,3,0.003,0.150,0"
295  * type(6), pos.x, pos.y, diam, penwidth, gap, circlecount, crosshair thickness, crosshaire len, rotation
296  * type is not stored in parameters list, so the first parameter is pos.x
297  */
298  int outerDiam = scaletoIU( params[2].GetValue( tool ), m_GerbMetric );
299  int penThickness = scaletoIU( params[3].GetValue( tool ), m_GerbMetric );
300  int gap = scaletoIU( params[4].GetValue( tool ), m_GerbMetric );
301  int numCircles = KiROUND( params[5].GetValue( tool ) );
302 
303  // Draw circles:
304  wxPoint center = aParent->GetABPosition( curPos );
305  // adjust outerDiam by this on each nested circle
306  int diamAdjust = (gap + penThickness) * 2;
307 
308  for( int i = 0; i < numCircles; ++i, outerDiam -= diamAdjust )
309  {
310  if( outerDiam <= 0 )
311  break;
312 
313  // Note: outerDiam is the outer diameter of the ring.
314  // the ring graphic diameter is (outerDiam - penThickness)
315  if( outerDiam <= penThickness )
316  { // No room to draw a ring (no room for the hole):
317  // draw a circle instead (with no hole), with the right diameter
318  TransformCircleToPolygon( aShapeBuffer, center, outerDiam / 2, ARC_HIGH_DEF );
319  }
320  else
321  TransformRingToPolygon( aShapeBuffer, center, ( outerDiam - penThickness ) / 2,
322  ARC_HIGH_DEF, 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:123
bool m_GerbMetric
Definition: am_primitive.h:98
double GetValue(const D_CODE *aDcode) const
Definition: am_param.cpp:70
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 TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, wxPoint aCenter, int aRadius, int aError)
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)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:115
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:215
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...
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:229
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 ...
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:556
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.
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.
double ArcTangente(int dy, int dx)
Definition: trigo.cpp:183
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.
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
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)
size_t i
Definition: json11.cpp:597
void RemoveAllContours()
Removes all outlines & holes (clears) the polygon set.
Class EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
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 ...
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.
#define min(a, b)
Definition: auxiliary.h:85
AM_PRIMITIVE_ID primitive_id
The primitive type.
Definition: am_primitive.h:95
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39