You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1345 lines
45 KiB

  1. /********************/
  2. /**** rs274d.cpp ****/
  3. /********************/
  4. #include "fctsys.h"
  5. #include "polygons_defs.h"
  6. #include "common.h"
  7. #include "confirm.h"
  8. #include "macros.h"
  9. #include "gerbview.h"
  10. #include "pcbplot.h"
  11. #include "trigo.h"
  12. #include "protos.h"
  13. #include "class_gerber_draw_item.h"
  14. #include <math.h>
  15. #define IsNumber( x ) ( ( ( (x) >= '0' ) && ( (x) <='9' ) ) \
  16. || ( (x) == '-' ) || ( (x) == '+' ) || ( (x) == '.' ) )
  17. /* Gerber: NOTES about some important commands found in RS274D and RS274X (G codes):
  18. * Gn =
  19. * G01 linear interpolation (right trace)
  20. * G02, G20, G21 Circular interpolation, meaning trig <0
  21. * G03, G30, G31 Circular interpolation, meaning trigo> 0
  22. * G04 = comment
  23. * G06 parabolic interpolation
  24. * G07 Cubic Interpolation
  25. * G10 linear interpolation (scale x10)
  26. * G11 linear interpolation (0.1x range)
  27. * G12 linear interpolation (0.01x scale)
  28. * G36 Start polygon mode
  29. * G37 Stop polygon mode (and close it)
  30. * G54 Selection Tool
  31. * G60 linear interpolation (scale x100)
  32. * G70 Select Units = Inches
  33. * G71 Select Units = Millimeters
  34. * G74 circular interpolation removes 360 degree (arc draw mode) finishing by G01
  35. * G75 circular interpolation on 360 degree
  36. * G90 mode absolute coordinates
  37. *
  38. * X, Y
  39. * X and Y are followed by + or - and m + n digits (not separated)
  40. * m = integer part
  41. * n = part after the comma
  42. * Classic formats: m = 2, n = 3 (size 2.3)
  43. * m = 3, n = 4 (size 3.4)
  44. * eg
  45. * GxxX00345Y-06123*
  46. *
  47. * Tools and D_CODES
  48. * Tool number (identification of shapes)
  49. * 10 to 999
  50. * D_CODES:
  51. * D01 ... D9 = command codes:
  52. * D01 = activating light (pen down) when placement
  53. * D02 = light extinction (pen up) when placement
  54. * D03 = Flash
  55. * D09 = VAPE Flash (I never see this command in gerber file)
  56. * D51 = G54 preceded by -> Select VAPE
  57. *
  58. * D10 ... D999 = Identification Tool: tool selection
  59. */
  60. // Photoplot actions:
  61. #define GERB_ACTIVE_DRAW 1 // Activate light (lower pen)
  62. #define GERB_STOP_DRAW 2 // Extinguish light (lift pen)
  63. #define GERB_FLASH 3 // Flash
  64. static wxPoint LastPosition;
  65. /* Local Functions (are lower case since they are private to this source file)
  66. **/
  67. /**
  68. * Function fillCircularGBRITEM
  69. * initializes a given GBRITEM so that it can draw a circle which is not filled
  70. * and
  71. * has a given pen width (\a aPenWidth ).
  72. *
  73. * @param aGbrItem The GBRITEM to fill in.
  74. * @param Dcode_index The DCODE value, like D14
  75. * @param aLayer The layer index to set into the GBRITEM
  76. * @param aPos The center point of the flash
  77. * @param aDiameter The diameter of the round flash
  78. * @param aPenWidth The width of the pen used to draw the circle's
  79. * circumference.
  80. * @param isDark True if flash is positive and should use a drawing
  81. * color other than the background color, else use the background color
  82. * when drawing so that an erasure happens.
  83. */
  84. static void fillCircularGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
  85. int Dcode_index,
  86. int aLayer,
  87. const wxPoint& aPos,
  88. int aDiameter,
  89. int aPenWidth,
  90. bool isDark )
  91. {
  92. aGbrItem->m_Shape = GBR_CIRCLE;
  93. aGbrItem->m_Size.x = aGbrItem->m_Size.y = aPenWidth;
  94. aGbrItem->SetLayer( aLayer );
  95. aGbrItem->m_DCode = Dcode_index;
  96. // When drawing a GBRITEM with shape GBR_CIRCLE, the hypotenuse (i.e. distance)
  97. // between the Start and End points gives the radius of the circle.
  98. aGbrItem->m_Start = aGbrItem->m_End = aPos;
  99. aGbrItem->m_End.x += max( 0, (aDiameter + 1) / 2 );
  100. NEGATE( aGbrItem->m_Start.y );
  101. NEGATE( aGbrItem->m_End.y );
  102. if( !isDark )
  103. {
  104. aGbrItem->m_Flags |= DRAW_ERASED;
  105. }
  106. }
  107. /**
  108. * Function fillRoundFlashGBRITEM
  109. * initializes a given GBRITEM so that it can draw a circle which is filled and
  110. * has no pen border.
  111. *
  112. * @param aGbrItem The GBRITEM to fill in.
  113. * @param Dcode_index The DCODE value, like D14
  114. * @param aLayer The layer index to set into the GBRITEM
  115. * @param aPos The center point of the flash
  116. * @param aDiameter The diameter of the round flash
  117. * @param isDark True if flash is positive and should use a drawing
  118. * color other than the background color, else use the background color
  119. * when drawing so that an erasure happens.
  120. */
  121. static void fillRoundFlashGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
  122. int Dcode_index,
  123. int aLayer,
  124. const wxPoint& aPos,
  125. int aDiameter,
  126. bool isDark )
  127. {
  128. aGbrItem->SetLayer( aLayer );
  129. aGbrItem->m_Size.x = aGbrItem->m_Size.y = aDiameter;
  130. aGbrItem->m_Start = aPos;
  131. NEGATE( aGbrItem->m_Start.y );
  132. aGbrItem->m_End = aGbrItem->m_Start;
  133. aGbrItem->m_DCode = Dcode_index;
  134. aGbrItem->m_Shape = GBR_SPOT_CIRCLE;
  135. aGbrItem->m_Flashed = true;
  136. if( !isDark )
  137. {
  138. aGbrItem->m_Flags |= DRAW_ERASED;
  139. }
  140. }
  141. /**
  142. * Function fillOvalOrRectFlashGBRITEM
  143. * initializes a given GBRITEM so that it can draw an oval or rectangular
  144. * filled rectangle.
  145. *
  146. * @param aGbrItem The GERBER_DRAW_ITEM to fill in.
  147. * @param Dcode_index The DCODE value, like D14
  148. * @param aLayer The layer index to set into the GBRITEM
  149. * @param aPos The center point of the rectangle
  150. * @param aSize The size of the flash
  151. * @param aShape What type of flash, GBR_SPOT_OVALE or GBR_SPOT_RECT
  152. * @param isDark True if flash is positive and should use a drawing
  153. * color other than the background color, else use the background color
  154. * when drawing so that an erasure happens.
  155. */
  156. static void fillOvalOrRectFlashGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
  157. int Dcode_index,
  158. int aLayer,
  159. const wxPoint& aPos,
  160. const wxSize& aSize,
  161. int aShape,
  162. bool isDark )
  163. {
  164. aGbrItem->SetLayer( aLayer );
  165. aGbrItem->m_Flashed = true;
  166. aGbrItem->m_Size = aSize;
  167. aGbrItem->m_Start = aPos;
  168. NEGATE( aGbrItem->m_Start.y );
  169. aGbrItem->m_End = aGbrItem->m_Start;
  170. aGbrItem->m_DCode = Dcode_index;
  171. aGbrItem->m_Shape = aShape;
  172. if( !isDark )
  173. {
  174. aGbrItem->m_Flags |= DRAW_ERASED;
  175. }
  176. }
  177. /**
  178. * Function fillLineGBRITEM
  179. * initializes a given GBRITEM so that it can draw a linear D code.
  180. *
  181. * @param aGbrItem The GERBER_DRAW_ITEM to fill in.
  182. * @param Dcode_index The DCODE value, like D14
  183. * @param aLayer The layer index to set into the GBRITEM
  184. * @param aPos The center point of the flash
  185. * @param aDiameter The diameter of the round flash
  186. * @param isDark True if flash is positive and should use a drawing
  187. * color other than the background color, else use the background color
  188. * when drawing so that an erasure happens.
  189. */
  190. static void fillLineGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
  191. int Dcode_index,
  192. int aLayer,
  193. const wxPoint& aStart,
  194. const wxPoint& aEnd,
  195. int aWidth,
  196. bool isDark )
  197. {
  198. aGbrItem->SetLayer( aLayer );
  199. aGbrItem->m_Flashed = false;
  200. aGbrItem->m_Size.x = aGbrItem->m_Size.y = aWidth;
  201. aGbrItem->m_Start = aStart;
  202. NEGATE( aGbrItem->m_Start.y );
  203. aGbrItem->m_End = aEnd;
  204. NEGATE( aGbrItem->m_End.y );
  205. aGbrItem->m_DCode = Dcode_index;
  206. if( !isDark )
  207. {
  208. aGbrItem->m_Flags |= DRAW_ERASED;
  209. }
  210. }
  211. /**
  212. * Function fillArcGBRITEM
  213. * initializes a given GBRITEM so that it can draw an arc G code.
  214. * <p>
  215. * if multiquadrant == true : arc can be 0 to 360 degrees
  216. * and \a rel_center is the center coordinate relative to start point.
  217. * <p>
  218. * if multiquadrant == false arc can be only 0 to 90 deg,
  219. * and only in the same quadrant :
  220. * <ul>
  221. * <li> absolute angle 0 to 90 (quadrant 1) or
  222. * <li> absolute angle 90 to 180 (quadrant 2) or
  223. * <li> absolute angle 180 to 270 (quadrant 3) or
  224. * <li> absolute angle 270 to 0 (quadrant 4)
  225. * </ul><p>
  226. * @param GERBER_DRAW_ITEM is the GBRITEM to fill in.
  227. * @param Dcode_index is the DCODE value, like D14
  228. * @param aLayer is the layer index to set into the GBRITEM
  229. * @param aStart is the starting point
  230. * @param aEnd is the ending point
  231. * @param rel_center is the center coordinate relative to start point,
  232. * given in ABSOLUTE VALUE and the sign of values x et y de rel_center
  233. * must be calculated from the previously given constraint: arc only in the
  234. * same quadrant.
  235. * @param aDiameter The diameter of the round flash
  236. * @param aWidth is the pen width.
  237. * @param isDark True if flash is positive and should use a drawing
  238. * color other than the background color, else use the background color
  239. * when drawing so that an erasure happens.
  240. */
  241. static void fillArcGBRITEM( GERBER_DRAW_ITEM* aGbrItem, int Dcode_index, int aLayer,
  242. const wxPoint& aStart, const wxPoint& aEnd,
  243. const wxPoint& rel_center, int aWidth,
  244. bool clockwise, bool multiquadrant, bool isDark )
  245. {
  246. wxPoint center, delta;
  247. aGbrItem->m_Shape = GBR_ARC;
  248. aGbrItem->SetLayer( aLayer );
  249. aGbrItem->m_Size.x = aGbrItem->m_Size.y = aWidth;
  250. aGbrItem->m_Flashed = false;
  251. if( multiquadrant )
  252. {
  253. center.x = aStart.x + rel_center.x;
  254. center.y = aStart.y + rel_center.y;
  255. if( clockwise )
  256. {
  257. aGbrItem->m_Start = aStart;
  258. aGbrItem->m_End = aEnd;
  259. }
  260. else
  261. {
  262. aGbrItem->m_Start = aEnd;
  263. aGbrItem->m_End = aStart;
  264. }
  265. }
  266. else
  267. {
  268. center = rel_center;
  269. delta = aEnd - aStart;
  270. if( (delta.x >= 0) && (delta.y >= 0) )
  271. {
  272. // Quadrant 2
  273. }
  274. else if( (delta.x >= 0) && (delta.y < 0) )
  275. {
  276. // Quadrant 1
  277. center.y = -center.y;
  278. }
  279. else if( (delta.x < 0) && (delta.y >= 0) )
  280. {
  281. // Quadrant 4
  282. center.x = -center.x;
  283. }
  284. else
  285. {
  286. // Quadrant 3
  287. center.x = -center.x;
  288. center.y = -center.y;
  289. }
  290. center.x += aStart.x;
  291. center.y += aStart.y;
  292. if( clockwise )
  293. {
  294. aGbrItem->m_Start = aStart;
  295. aGbrItem->m_End = aEnd;
  296. }
  297. else
  298. {
  299. aGbrItem->m_Start = aEnd;
  300. aGbrItem->m_End = aStart;
  301. }
  302. }
  303. aGbrItem->m_DCode = Dcode_index;
  304. aGbrItem->m_ArcCentre = center;
  305. NEGATE( aGbrItem->m_Start.y );
  306. NEGATE( aGbrItem->m_End.y );
  307. NEGATE( aGbrItem->m_ArcCentre.y );
  308. if( !isDark )
  309. {
  310. aGbrItem->m_Flags |= DRAW_ERASED;
  311. }
  312. }
  313. /**
  314. * Function fillArcPOLY
  315. * creates an arc G code when found in poly outlines.
  316. * <p>
  317. * if multiquadrant == true : arc can be 0 to 360 degrees
  318. * and \a rel_center is the center coordinate relative to start point.
  319. * <p>
  320. * if multiquadrant == false arc can be only 0 to 90 deg,
  321. * and only in the same quadrant :
  322. * <ul>
  323. * <li> absolute angle 0 to 90 (quadrant 1) or
  324. * <li> absolute angle 90 to 180 (quadrant 2) or
  325. * <li> absolute angle 180 to 270 (quadrant 3) or
  326. * <li> absolute angle 270 to 0 (quadrant 4)
  327. * </ul><p>
  328. * @param aPcb is the board.
  329. * @param aLayer is the layer index to set into the GBRITEM
  330. * @param aStart is the starting point
  331. * @param aEnd is the ending point
  332. * @param rel_center is the center coordinate relative to start point,
  333. * given in ABSOLUTE VALUE and the sign of values x et y de rel_center
  334. * must be calculated from the previously given constraint: arc only in the
  335. * same quadrant.
  336. * @param aDiameter The diameter of the round flash
  337. * @param aWidth is the pen width.
  338. * @param isDark True if flash is positive and should use a drawing
  339. * color other than the background color, else use the background color
  340. * when drawing so that an erasure happens.
  341. */
  342. static void fillArcPOLY( BOARD* aPcb, GERBER_DRAW_ITEM* aGrbrItem,
  343. const wxPoint& aStart, const wxPoint& aEnd,
  344. const wxPoint& rel_center,
  345. bool clockwise, bool multiquadrant, bool isDark )
  346. {
  347. /* in order to calculate arc parameters, we use fillArcGBRITEM
  348. * so we muse create a dummy track and use its geometric parameters
  349. */
  350. static GERBER_DRAW_ITEM dummyGbrItem( NULL );
  351. fillArcGBRITEM( &dummyGbrItem, 0, 0,
  352. aStart, aEnd, rel_center, 0,
  353. clockwise, multiquadrant, isDark );
  354. // dummyTrack has right geometric parameters, and has its Y coordinates negated (to match the pcbnew Y axis).
  355. // Approximate arc by 36 segments per 360 degree
  356. const int increment_angle = 360 / 36;
  357. wxPoint center;
  358. center = dummyGbrItem.m_ArcCentre;
  359. // Calculate relative coordinates;
  360. wxPoint start = dummyGbrItem.m_Start - center;
  361. wxPoint end = dummyGbrItem.m_End - center;
  362. /* Calculate angle arc
  363. * angle is here clockwise because Y axis is reversed
  364. */
  365. double start_angle = atan2( (double) start.y, (double) start.x );
  366. start_angle = 180 * start_angle / M_PI;
  367. double end_angle = atan2( (double) end.y, (double) end.x );
  368. end_angle = 180 * end_angle / M_PI;
  369. double angle = start_angle - end_angle;
  370. // D( printf( " >>>> st %d,%d angle %f, end %d,%d angle %f delta %f\n",
  371. // start.x, start.y, start_angle, end.x, end.y, end_angle, angle ) );
  372. if( !clockwise )
  373. {
  374. EXCHG( start, end );
  375. D( printf( " >>>> reverse arc\n" ) );
  376. }
  377. // Normalize angle
  378. while( angle > 360.0 )
  379. angle -= 360.0;
  380. while( angle < 0.0 )
  381. angle += 360.0;
  382. int count = (int) ( angle / increment_angle );
  383. if( count <= 0 )
  384. count = 1;
  385. // D( printf( " >>>> angle %f, cnt %d sens %d\n", angle, count, clockwise ) );
  386. // calculate segments
  387. wxPoint start_arc = start;
  388. for( int ii = 1; ii <= count; ii++ )
  389. {
  390. wxPoint end_arc = start;
  391. int rot = 10 * ii * increment_angle; // rot is in 0.1 deg
  392. if( ii < count )
  393. {
  394. if( clockwise )
  395. RotatePoint( &end_arc, rot );
  396. else
  397. RotatePoint( &end_arc, -rot );
  398. }
  399. else
  400. end_arc = end;
  401. // D( printf( " >> Add arc %d rot %d, edge poly item %d,%d to %d,%d\n",
  402. // ii, rot, start_arc.x, start_arc.y,end_arc.x, end_arc.y ); )
  403. if( aGrbrItem->m_PolyCorners.size() == 0 )
  404. aGrbrItem->m_PolyCorners.push_back( start_arc + center );
  405. aGrbrItem->m_PolyCorners.push_back( end_arc + center );
  406. if( !isDark )
  407. {
  408. aGrbrItem->m_Flags |= DRAW_ERASED;
  409. }
  410. start_arc = end_arc;
  411. }
  412. }
  413. /* These routines read the text string point from Text.
  414. * After use, advanced Text the beginning of the sequence unread
  415. */
  416. wxPoint GERBER::ReadXYCoord( char*& Text )
  417. {
  418. wxPoint pos = m_CurrentPos;
  419. int type_coord = 0, current_coord, nbchar;
  420. bool is_float = false;
  421. char* text;
  422. char line[256];
  423. if( m_Relative )
  424. pos.x = pos.y = 0;
  425. else
  426. pos = m_CurrentPos;
  427. if( Text == NULL )
  428. return pos;
  429. text = line;
  430. while( *Text )
  431. {
  432. if( (*Text == 'X') || (*Text == 'Y') )
  433. {
  434. type_coord = *Text;
  435. Text++;
  436. text = line;
  437. nbchar = 0;
  438. while( IsNumber( *Text ) )
  439. {
  440. if( *Text == '.' )
  441. is_float = true;
  442. *(text++) = *(Text++);
  443. if( (*Text >= '0') && (*Text <='9') )
  444. nbchar++;
  445. }
  446. *text = 0;
  447. if( is_float )
  448. {
  449. if( m_GerbMetric )
  450. current_coord = wxRound( atof( line ) / 0.00254 );
  451. else
  452. current_coord = wxRound( atof( line ) * PCB_INTERNAL_UNIT );
  453. }
  454. else
  455. {
  456. int fmt_scale =
  457. (type_coord == 'X') ? m_FmtScale.x : m_FmtScale.y;
  458. if( m_NoTrailingZeros )
  459. {
  460. int min_digit =
  461. (type_coord == 'X') ? m_FmtLen.x : m_FmtLen.y;
  462. while( nbchar < min_digit )
  463. {
  464. *(text++) = '0';
  465. nbchar++;
  466. }
  467. *text = 0;
  468. }
  469. current_coord = atoi( line );
  470. double real_scale = 1.0;
  471. if( fmt_scale < 0 || fmt_scale > 9 )
  472. fmt_scale = 4;
  473. double scale_list[10] =
  474. { 10000.0, 1000.0, 100.0, 10.0,
  475. 1,
  476. 0.1, 0.01, 0.001, 0.0001, 0.00001
  477. };
  478. real_scale = scale_list[fmt_scale];
  479. if( m_GerbMetric )
  480. real_scale = real_scale / 25.4;
  481. current_coord = wxRound( current_coord * real_scale );
  482. }
  483. if( type_coord == 'X' )
  484. pos.x = current_coord;
  485. else if( type_coord == 'Y' )
  486. pos.y = current_coord;
  487. continue;
  488. }
  489. else
  490. break;
  491. }
  492. if( m_Relative )
  493. {
  494. pos.x += m_CurrentPos.x;
  495. pos.y += m_CurrentPos.y;
  496. }
  497. m_CurrentPos = pos;
  498. return pos;
  499. }
  500. /* Returns the current coordinate type pointed to by InnJnn Text (InnnnJmmmm)
  501. * These coordinates are relative, so if coordinate is absent, it's value
  502. * defaults to 0
  503. */
  504. wxPoint GERBER::ReadIJCoord( char*& Text )
  505. {
  506. wxPoint pos( 0, 0 );
  507. int type_coord = 0, current_coord, nbchar;
  508. bool is_float = false;
  509. char* text;
  510. char line[256];
  511. if( Text == NULL )
  512. return pos;
  513. text = line;
  514. while( *Text )
  515. {
  516. if( (*Text == 'I') || (*Text == 'J') )
  517. {
  518. type_coord = *Text;
  519. Text++;
  520. text = line;
  521. nbchar = 0;
  522. while( IsNumber( *Text ) )
  523. {
  524. if( *Text == '.' )
  525. is_float = true;
  526. *(text++) = *(Text++);
  527. if( (*Text >= '0') && (*Text <='9') )
  528. nbchar++;
  529. }
  530. *text = 0;
  531. if( is_float )
  532. {
  533. if( m_GerbMetric )
  534. current_coord = wxRound( atof( line ) / 0.00254 );
  535. else
  536. current_coord = wxRound( atof( line ) * PCB_INTERNAL_UNIT );
  537. }
  538. else
  539. {
  540. int fmt_scale =
  541. (type_coord == 'I') ? m_FmtScale.x : m_FmtScale.y;
  542. if( m_NoTrailingZeros )
  543. {
  544. int min_digit =
  545. (type_coord == 'I') ? m_FmtLen.x : m_FmtLen.y;
  546. while( nbchar < min_digit )
  547. {
  548. *(text++) = '0';
  549. nbchar++;
  550. }
  551. *text = 0;
  552. }
  553. current_coord = atoi( line );
  554. double real_scale = 1.0;
  555. if( fmt_scale < 0 || fmt_scale > 9 )
  556. fmt_scale = 4; // select scale 1.0
  557. double scale_list[10] =
  558. { 10000.0, 1000.0, 100.0, 10.0,
  559. 1,
  560. 0.1, 0.01, 0.001, 0.0001, 0.00001
  561. };
  562. real_scale = scale_list[fmt_scale];
  563. if( m_GerbMetric )
  564. real_scale = real_scale / 25.4;
  565. current_coord = wxRound( current_coord * real_scale );
  566. }
  567. if( type_coord == 'I' )
  568. pos.x = current_coord;
  569. else if( type_coord == 'J' )
  570. pos.y = current_coord;
  571. continue;
  572. }
  573. else
  574. break;
  575. }
  576. m_IJPos = pos;
  577. return pos;
  578. }
  579. /* Read the Gnn sequence and returns the value nn.
  580. */
  581. int GERBER::ReturnGCodeNumber( char*& Text )
  582. {
  583. int ii = 0;
  584. char* text;
  585. char line[1024];
  586. if( Text == NULL )
  587. return 0;
  588. Text++;
  589. text = line;
  590. while( IsNumber( *Text ) )
  591. {
  592. *(text++) = *(Text++);
  593. }
  594. *text = 0;
  595. ii = atoi( line );
  596. return ii;
  597. }
  598. /* Get the sequence Dnn and returns the value nn
  599. */
  600. int GERBER::ReturnDCodeNumber( char*& Text )
  601. {
  602. int ii = 0;
  603. char* text;
  604. char line[1024];
  605. if( Text == NULL )
  606. return 0;
  607. Text++;
  608. text = line;
  609. while( IsNumber( *Text ) )
  610. *(text++) = *(Text++);
  611. *text = 0;
  612. ii = atoi( line );
  613. return ii;
  614. }
  615. bool GERBER::Execute_G_Command( char*& text, int G_commande )
  616. {
  617. D( printf( "%22s: G_CODE<%d>\n", __func__, G_commande ); )
  618. switch( G_commande )
  619. {
  620. case GC_PHOTO_MODE: // can starts a D03 flash command: redundant, can
  621. // be safely ignored
  622. break;
  623. case GC_LINEAR_INTERPOL_1X:
  624. m_Iterpolation = GERB_INTERPOL_LINEAR_1X;
  625. break;
  626. case GC_CIRCLE_NEG_INTERPOL:
  627. m_Iterpolation = GERB_INTERPOL_ARC_NEG;
  628. break;
  629. case GC_CIRCLE_POS_INTERPOL:
  630. m_Iterpolation = GERB_INTERPOL_ARC_POS;
  631. break;
  632. case GC_COMMENT:
  633. text = NULL;
  634. break;
  635. case GC_LINEAR_INTERPOL_10X:
  636. m_Iterpolation = GERB_INTERPOL_LINEAR_10X;
  637. break;
  638. case GC_LINEAR_INTERPOL_0P1X:
  639. m_Iterpolation = GERB_INTERPOL_LINEAR_01X;
  640. break;
  641. case GC_LINEAR_INTERPOL_0P01X:
  642. m_Iterpolation = GERB_INTERPOL_LINEAR_001X;
  643. break;
  644. case GC_SELECT_TOOL:
  645. {
  646. int D_commande = ReturnDCodeNumber( text );
  647. if( D_commande < FIRST_DCODE )
  648. return false;
  649. if( D_commande > (TOOLS_MAX_COUNT - 1) )
  650. D_commande = TOOLS_MAX_COUNT - 1;
  651. m_Current_Tool = D_commande;
  652. D_CODE* pt_Dcode = GetDCODE( D_commande, false );
  653. if( pt_Dcode )
  654. pt_Dcode->m_InUse = true;
  655. break;
  656. }
  657. case GC_SPECIFY_INCHES:
  658. m_GerbMetric = false; // false = Inches, true = metric
  659. break;
  660. case GC_SPECIFY_MILLIMETERS:
  661. m_GerbMetric = true; // false = Inches, true = metric
  662. break;
  663. case GC_TURN_OFF_360_INTERPOL:
  664. m_360Arc_enbl = false;
  665. break;
  666. case GC_TURN_ON_360_INTERPOL:
  667. m_360Arc_enbl = true;
  668. break;
  669. case GC_SPECIFY_ABSOLUES_COORD:
  670. m_Relative = false; // false = absolute Coord, true = relative
  671. // Coord
  672. break;
  673. case GC_SPECIFY_RELATIVEES_COORD:
  674. m_Relative = true; // false = absolute Coord, true = relative
  675. // Coord
  676. break;
  677. case GC_TURN_ON_POLY_FILL:
  678. m_PolygonFillMode = true;
  679. break;
  680. case GC_TURN_OFF_POLY_FILL:
  681. m_PolygonFillMode = false;
  682. m_PolygonFillModeState = 0;
  683. break;
  684. case GC_MOVE: // Non existent
  685. default:
  686. {
  687. wxString msg; msg.Printf( wxT( "G%0.2d command not handled" ),
  688. G_commande );
  689. DisplayError( NULL, msg );
  690. return false;
  691. }
  692. }
  693. return true;
  694. }
  695. /**
  696. * Function scale
  697. * converts a distance given in floating point to our deci-mils
  698. */
  699. int scale( double aCoord, bool isMetric )
  700. {
  701. int ret;
  702. if( isMetric )
  703. ret = wxRound( aCoord / 0.00254 );
  704. else
  705. ret = wxRound( aCoord * PCB_INTERNAL_UNIT );
  706. return ret;
  707. }
  708. /**
  709. * Function mapPt
  710. * translates a point from the aperture macro coordinate system to our
  711. * deci-mils coordinate system.
  712. * @return wxPoint - The gerbview coordinate system vector.
  713. */
  714. wxPoint mapPt( double x, double y, bool isMetric )
  715. {
  716. wxPoint ret( scale( x, isMetric ),
  717. scale( y, isMetric ) );
  718. return ret;
  719. }
  720. /**
  721. * Function mapExposure
  722. * translates the first parameter from an aperture macro into a current
  723. * exposure
  724. * setting.
  725. * @param curExposure A dynamic setting which can change throughout the
  726. * reading of the gerber file, and it indicates whether the current tool
  727. * is lit or not.
  728. * @param isNegative A dynamic setting which can change throughout the reading
  729. * of
  730. * the gerber file, and it indicates whether the current D codes are to
  731. * be interpreted as erasures or not.
  732. */
  733. static bool mapExposure( int param1, bool curExposure, bool isNegative )
  734. {
  735. bool exposure;
  736. switch( param1 )
  737. {
  738. case 0:
  739. exposure = false;
  740. break;
  741. default:
  742. case 1:
  743. exposure = true;
  744. break;
  745. case 2:
  746. exposure = !curExposure;
  747. }
  748. return exposure ^ isNegative;
  749. }
  750. bool GERBER::Execute_DCODE_Command( WinEDA_GerberFrame* frame, char*& text, int D_commande )
  751. {
  752. wxSize size( 15, 15 );
  753. APERTURE_T aperture = APT_CIRCLE;
  754. GERBER_DRAW_ITEM* gbritem;
  755. BOARD* pcb = frame->GetBoard();
  756. int activeLayer = frame->GetScreen()->m_Active_Layer;
  757. int dcode = 0;
  758. D_CODE* tool = NULL;
  759. wxString msg;
  760. D( printf( "%22s: D_CODE<%d>\n", __func__, D_commande ); )
  761. if( D_commande >= FIRST_DCODE ) // This is a "Set tool" command
  762. {
  763. if( D_commande > (TOOLS_MAX_COUNT - 1) )
  764. D_commande = TOOLS_MAX_COUNT - 1;
  765. // remember which tool is selected, nothing is done with it in this
  766. // call
  767. m_Current_Tool = D_commande;
  768. D_CODE* pt_Dcode = GetDCODE( D_commande, false );
  769. if( pt_Dcode )
  770. pt_Dcode->m_InUse = true;
  771. return true;
  772. }
  773. else // D_commande = 0..9: this is a pen command (usually D1, D2 or D3)
  774. {
  775. m_Last_Pen_Command = D_commande;
  776. }
  777. if( m_PolygonFillMode ) // Enter a polygon description:
  778. {
  779. switch( D_commande )
  780. {
  781. case 1: // code D01 Draw line, exposure ON
  782. if( !m_Exposure )
  783. {
  784. m_Exposure = true;
  785. gbritem = new GERBER_DRAW_ITEM( pcb );
  786. pcb->m_Drawings.Append( gbritem );
  787. gbritem->m_Shape = GBR_POLYGON;
  788. gbritem->SetLayer( activeLayer );
  789. gbritem->m_Flashed = false;
  790. gbritem->m_UnitsMetric = m_GerbMetric;
  791. }
  792. switch( m_Iterpolation )
  793. {
  794. case GERB_INTERPOL_ARC_NEG:
  795. case GERB_INTERPOL_ARC_POS:
  796. gbritem = (GERBER_DRAW_ITEM*)( pcb->m_Drawings.GetLast() );
  797. D( printf( "Add arc poly %d,%d to %d,%d fill %d interpol %d 360_enb %d\n",
  798. m_PreviousPos.x, m_PreviousPos.y, m_CurrentPos.x,
  799. m_CurrentPos.y, m_PolygonFillModeState, m_Iterpolation, m_360Arc_enbl ); )
  800. fillArcPOLY( pcb, gbritem, m_PreviousPos,
  801. m_CurrentPos, m_IJPos,
  802. ( m_Iterpolation == GERB_INTERPOL_ARC_NEG ) ?
  803. false : true, m_360Arc_enbl,
  804. !(m_LayerNegative ^ m_ImageNegative) );
  805. break;
  806. default:
  807. gbritem = (GERBER_DRAW_ITEM*)( pcb->m_Drawings.GetLast() );
  808. D( printf( "Add poly edge %d,%d to %d,%d fill %d\n",
  809. m_PreviousPos.x, m_PreviousPos.y,
  810. m_CurrentPos.x, m_CurrentPos.y, m_Iterpolation ); )
  811. gbritem->m_Start = m_PreviousPos; // m_Start is used as temporary storage
  812. NEGATE( gbritem->m_Start.y );
  813. if( gbritem->m_PolyCorners.size() == 0 )
  814. gbritem->m_PolyCorners.push_back( gbritem->m_Start );
  815. gbritem->m_End = m_CurrentPos; // m_End is used as temporary storage
  816. NEGATE( gbritem->m_End.y );
  817. gbritem->m_PolyCorners.push_back( gbritem->m_End );
  818. // Set the erasure flag of gbritem if a negative polygon.
  819. if( !m_PolygonFillModeState )
  820. {
  821. if( m_LayerNegative ^ m_ImageNegative )
  822. gbritem->m_Flags |= DRAW_ERASED;
  823. D( printf( "\nm_Flags=0x%08X\n", gbritem->m_Flags ); )
  824. }
  825. break;
  826. }
  827. m_PreviousPos = m_CurrentPos;
  828. m_PolygonFillModeState = 1;
  829. break;
  830. case 2: // code D2: exposure OFF (i.e. "move to")
  831. m_Exposure = false;
  832. m_PreviousPos = m_CurrentPos;
  833. m_PolygonFillModeState = 0;
  834. break;
  835. default:
  836. return false;
  837. }
  838. }
  839. else
  840. {
  841. switch( D_commande )
  842. {
  843. case 1: // code D01 Draw line, exposure ON
  844. m_Exposure = true;
  845. tool = GetDCODE( m_Current_Tool, false );
  846. if( tool )
  847. {
  848. size = tool->m_Size;
  849. dcode = tool->m_Num_Dcode;
  850. aperture = tool->m_Shape;
  851. }
  852. switch( m_Iterpolation )
  853. {
  854. case GERB_INTERPOL_LINEAR_1X:
  855. gbritem = new GERBER_DRAW_ITEM( pcb );
  856. gbritem->m_UnitsMetric = m_GerbMetric;
  857. pcb->m_Drawings.Append( gbritem );
  858. D( printf( "R:%p\n", gbritem ); )
  859. fillLineGBRITEM( gbritem, dcode, activeLayer, m_PreviousPos,
  860. m_CurrentPos, size.x,
  861. !(m_LayerNegative ^ m_ImageNegative) );
  862. break;
  863. case GERB_INTERPOL_LINEAR_01X:
  864. case GERB_INTERPOL_LINEAR_001X:
  865. case GERB_INTERPOL_LINEAR_10X:
  866. wxBell();
  867. break;
  868. case GERB_INTERPOL_ARC_NEG:
  869. case GERB_INTERPOL_ARC_POS:
  870. gbritem = new GERBER_DRAW_ITEM( pcb );
  871. gbritem->m_UnitsMetric = m_GerbMetric;
  872. pcb->m_Drawings.Append( gbritem );
  873. D( printf( "R:%p\n", gbritem ); )
  874. fillArcGBRITEM( gbritem, dcode, activeLayer, m_PreviousPos,
  875. m_CurrentPos, m_IJPos, size.x,
  876. ( m_Iterpolation == GERB_INTERPOL_ARC_NEG ) ?
  877. false : true, m_360Arc_enbl,
  878. !(m_LayerNegative ^ m_ImageNegative) );
  879. break;
  880. default:
  881. msg.Printf( wxT( "Execute_DCODE_Command: interpol error (type %X)" ),
  882. m_Iterpolation );
  883. DisplayError( frame, msg );
  884. break;
  885. }
  886. m_PreviousPos = m_CurrentPos;
  887. break;
  888. case 2: // code D2: exposure OFF (i.e. "move to")
  889. m_Exposure = false;
  890. m_PreviousPos = m_CurrentPos;
  891. break;
  892. case 3: // code D3: flash aperture
  893. tool = GetDCODE( m_Current_Tool, false );
  894. if( tool )
  895. {
  896. size = tool->m_Size;
  897. dcode = tool->m_Num_Dcode;
  898. aperture = tool->m_Shape;
  899. }
  900. switch( aperture )
  901. {
  902. case APT_POLYGON: // flashed regular polygon
  903. case APT_CIRCLE:
  904. gbritem = new GERBER_DRAW_ITEM( pcb );
  905. gbritem->m_UnitsMetric = m_GerbMetric;
  906. pcb->m_Drawings.Append( gbritem );
  907. D( printf( "R:%p\n", gbritem ); )
  908. fillRoundFlashGBRITEM( gbritem, dcode, activeLayer,
  909. m_CurrentPos, size.x,
  910. !(m_LayerNegative ^ m_ImageNegative) );
  911. if( aperture == APT_POLYGON )
  912. gbritem->m_Shape = GBR_SPOT_POLY;
  913. break;
  914. case APT_OVAL:
  915. case APT_RECT:
  916. gbritem = new GERBER_DRAW_ITEM( pcb );
  917. gbritem->m_UnitsMetric = m_GerbMetric;
  918. pcb->m_Drawings.Append( gbritem );
  919. D( printf( "R:%p\n", gbritem ); )
  920. fillOvalOrRectFlashGBRITEM( gbritem, dcode, activeLayer,
  921. m_CurrentPos, size,
  922. ( aperture == APT_RECT ) ?
  923. GBR_SPOT_RECT : GBR_SPOT_OVAL,
  924. !(m_LayerNegative ^ m_ImageNegative) );
  925. break;
  926. case APT_MACRO:
  927. {
  928. APERTURE_MACRO* macro = tool->GetMacro();
  929. wxASSERT( macro );
  930. #if 1
  931. gbritem = new GERBER_DRAW_ITEM( pcb );
  932. gbritem->m_UnitsMetric = m_GerbMetric;
  933. pcb->m_Drawings.Append( gbritem );
  934. fillRoundFlashGBRITEM( gbritem, dcode, activeLayer,
  935. m_CurrentPos, size.x,
  936. !(m_LayerNegative ^ m_ImageNegative) );
  937. gbritem->m_Shape = GBR_SPOT_MACRO;
  938. #else
  939. // split the macro primitives up into multiple normal GBRITEM
  940. // elements
  941. for( AM_PRIMITIVES::iterator p = macro->primitives.begin();
  942. p!=macro->primitives.end();
  943. ++p )
  944. {
  945. bool exposure;
  946. wxPoint curPos = m_CurrentPos;
  947. switch( p->primitive_id )
  948. {
  949. case AMP_CIRCLE:
  950. {
  951. exposure = mapExposure( p->GetExposure(), m_Exposure,
  952. m_ImageNegative );
  953. curPos += mapPt( p->params[2].GetValue( tool ),
  954. p->params[3].GetValue( tool ),
  955. m_GerbMetric );
  956. int diameter = scale( p->params[1].GetValue( tool ),
  957. m_GerbMetric );
  958. gbritem = new GERBER_DRAW_ITEM( pcb );
  959. pcb->m_Drawings.Append( gbritem );
  960. D( printf( "R:%p\n", gbritem ); )
  961. fillRoundFlashGBRITEM( gbritem, dcode, activeLayer,
  962. curPos, diameter, exposure );
  963. }
  964. break;
  965. case AMP_LINE2:
  966. case AMP_LINE20:
  967. {
  968. exposure = mapExposure(
  969. p->GetExposure(), m_Exposure, m_ImageNegative );
  970. int width = scale( p->params[1].GetValue( tool ),
  971. m_GerbMetric );
  972. wxPoint start = mapPt( p->params[2].GetValue( tool ),
  973. p->params[3].GetValue( tool ),
  974. m_GerbMetric );
  975. wxPoint end = mapPt( p->params[4].GetValue( tool ),
  976. p->params[5].GetValue( tool ),
  977. m_GerbMetric );
  978. if( start.x == end.x )
  979. {
  980. size.x = width;
  981. size.y = ABS( end.y - start.y ) + 1;
  982. }
  983. else
  984. {
  985. size.x = ABS( end.x - start.x ) + 1;
  986. size.y = width;
  987. }
  988. wxPoint midPoint( ( start.x + end.x ) / 2,
  989. ( start.y + end.y ) / 2 );
  990. curPos += midPoint;
  991. gbritem = new GERBER_DRAW_ITEM( pcb );
  992. pcb->m_Drawings.Append( gbritem );
  993. D( printf( "R:%p\n", gbritem ); )
  994. fillOvalOrRectFlashGBRITEM( gbritem, dcode, activeLayer,
  995. curPos, size, GBR_SPOT_RECT,
  996. exposure );
  997. }
  998. break;
  999. case AMP_LINE_CENTER:
  1000. {
  1001. exposure = mapExposure( p->GetExposure(), m_Exposure,
  1002. m_ImageNegative );
  1003. wxPoint msize = mapPt( p->params[1].GetValue( tool ),
  1004. p->params[2].GetValue( tool ),
  1005. m_GerbMetric );
  1006. size.x = msize.x;
  1007. size.y = msize.y;
  1008. curPos += mapPt( p->params[3].GetValue( tool ),
  1009. p->params[4].GetValue( tool ),
  1010. m_GerbMetric );
  1011. gbritem = new GERBER_DRAW_ITEM( pcb );
  1012. pcb->m_Drawings.Append( gbritem );
  1013. D( printf( "R:%p\n", gbritem ); )
  1014. fillOvalOrRectFlashGBRITEM( gbritem, dcode, activeLayer,
  1015. curPos, size, GBR_SPOT_RECT,
  1016. exposure );
  1017. }
  1018. break;
  1019. case AMP_LINE_LOWER_LEFT:
  1020. {
  1021. exposure = mapExposure(
  1022. p->GetExposure(), m_Exposure, m_ImageNegative );
  1023. wxPoint msize = mapPt( p->params[1].GetValue( tool ),
  1024. p->params[2].GetValue( tool ),
  1025. m_GerbMetric );
  1026. size.x = msize.x;
  1027. size.y = msize.y;
  1028. wxPoint lowerLeft = mapPt( p->params[3].GetValue( tool ),
  1029. p->params[4].GetValue( tool ),
  1030. m_GerbMetric );
  1031. curPos += lowerLeft;
  1032. // need the middle, so adjust from the lower left
  1033. curPos.y += size.y / 2;
  1034. curPos.x += size.x / 2;
  1035. gbritem = new GERBER_DRAW_ITEM( pcb );
  1036. pcb->m_Drawings.Append( gbritem );
  1037. D( printf( "R:%p\n", gbritem ); )
  1038. fillOvalOrRectFlashGBRITEM( gbritem, dcode, activeLayer,
  1039. curPos, size, GBR_SPOT_RECT,
  1040. exposure );
  1041. }
  1042. break;
  1043. case AMP_THERMAL:
  1044. {
  1045. int outerDiam = scale( p->params[2].GetValue( tool ),
  1046. m_GerbMetric );
  1047. int innerDiam = scale( p->params[3].GetValue( tool ),
  1048. m_GerbMetric );
  1049. curPos += mapPt( p->params[0].GetValue( tool ),
  1050. p->params[1].GetValue( tool ),
  1051. m_GerbMetric );
  1052. gbritem = new GERBER_DRAW_ITEM( pcb );
  1053. pcb->m_Drawings.Append( gbritem );
  1054. D( printf( "R:%p\n", gbritem ); )
  1055. fillRoundFlashGBRITEM( gbritem, dcode, activeLayer,
  1056. curPos, outerDiam,
  1057. !( m_LayerNegative ^ m_ImageNegative ) );
  1058. gbritem = new GERBER_DRAW_ITEM( pcb );
  1059. pcb->m_Drawings.Append( gbritem );
  1060. D( printf( "R:%p\n", gbritem ); )
  1061. fillRoundFlashGBRITEM( gbritem, dcode, activeLayer, curPos,
  1062. innerDiam,
  1063. ( m_LayerNegative ^ m_ImageNegative ) );
  1064. // @todo: draw the cross hairs, see page 23 of rs274
  1065. // spec. this might be done with two lines, thickness
  1066. // from params[4], and drawing
  1067. // darkness "(m_LayerNegative ^ m_ImageNegative)"
  1068. }
  1069. break;
  1070. case AMP_MOIRE:
  1071. {
  1072. curPos += mapPt( p->params[0].GetValue( tool ),
  1073. p->params[1].GetValue( tool ),
  1074. m_GerbMetric );
  1075. // e.g.: "6,0,0,0.125,.01,0.01,3,0.003,0.150,0"
  1076. int outerDiam = scale( p->params[2].GetValue( tool ),
  1077. m_GerbMetric );
  1078. int penThickness = scale( p->params[3].GetValue( tool ),
  1079. m_GerbMetric );
  1080. int gap = scale( p->params[4].GetValue( tool ),
  1081. m_GerbMetric );
  1082. int numCircles = (int) p->params[5].GetValue( tool );
  1083. int crossHairThickness =
  1084. scale( p->params[6].GetValue( tool ), m_GerbMetric );
  1085. int crossHairLength =
  1086. scale( p->params[7].GetValue( tool ), m_GerbMetric );
  1087. // ignore rotation, not supported
  1088. // adjust outerDiam by this on each nested circle
  1089. int diamAdjust = 2 * (gap + penThickness);
  1090. for( int i = 0; i < numCircles; ++i, outerDiam -= diamAdjust )
  1091. {
  1092. gbritem = new GERBER_DRAW_ITEM( pcb );
  1093. pcb->m_Drawings.Append( gbritem );
  1094. D( printf( "R:%p\n", gbritem ); )
  1095. fillCircularGBRITEM( gbritem, dcode, activeLayer,
  1096. curPos, outerDiam,
  1097. penThickness,
  1098. !( m_LayerNegative ^ m_ImageNegative ) );
  1099. }
  1100. gbritem = new GERBER_DRAW_ITEM( pcb );
  1101. pcb->m_Drawings.Append( gbritem );
  1102. D( printf( "R:%p\n", gbritem ); )
  1103. fillOvalOrRectFlashGBRITEM( gbritem, dcode, activeLayer,
  1104. curPos,
  1105. wxSize( crossHairThickness,
  1106. crossHairLength ),
  1107. GBR_SPOT_RECT,
  1108. !( m_LayerNegative ^ m_ImageNegative ) );
  1109. gbritem = new GERBER_DRAW_ITEM( pcb );
  1110. pcb->m_Drawings.Append( gbritem );
  1111. D( printf( "R:%p\n", gbritem ); )
  1112. // swap x and y in wxSize() for this one
  1113. fillOvalOrRectFlashGBRITEM( gbritem, dcode, activeLayer,
  1114. curPos,
  1115. wxSize( crossHairLength,
  1116. crossHairThickness ),
  1117. GBR_SPOT_RECT,
  1118. !( m_LayerNegative ^ m_ImageNegative ) );
  1119. }
  1120. break;
  1121. case AMP_OUTLINE:
  1122. #if defined(DEBUG)
  1123. {
  1124. int numPoints = (int) p->params[1].GetValue( tool );
  1125. printf( "AMP_OUTLINE:\n" );
  1126. printf( " exposure: %g\n", p->params[0].GetValue( tool ) );
  1127. printf( " # points: %d\n", numPoints );
  1128. // numPoints does not include the starting point, so add 1.
  1129. for( int i = 0; i<numPoints + 1; ++i )
  1130. {
  1131. printf( " [%d]: X=%g Y=%g\n", i,
  1132. p->params[i * 2 + 2 + 0].GetValue( tool ),
  1133. p->params[i * 2 + 2 + 1].GetValue( tool )
  1134. );
  1135. }
  1136. printf( " rotation: %g\n", p->params[numPoints * 2 + 4].GetValue( tool ) );
  1137. }
  1138. #endif
  1139. break;
  1140. case AMP_POLYGON:
  1141. case AMP_EOF:
  1142. default:
  1143. // not yet supported, waiting for you.
  1144. break;
  1145. }
  1146. }
  1147. #endif
  1148. }
  1149. break;
  1150. default:
  1151. break;
  1152. }
  1153. m_PreviousPos = m_CurrentPos;
  1154. break;
  1155. default:
  1156. return false;
  1157. }
  1158. }
  1159. return true;
  1160. }