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.

1017 lines
31 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 disable 360 degrees circular interpolation (return to 90 deg mode)
  35. * and circular interpolation (return t linear)
  36. * G75 enable 360 degrees circular interpolation
  37. * G90 mode absolute coordinates
  38. *
  39. * X, Y
  40. * X and Y are followed by + or - and m + n digits (not separated)
  41. * m = integer part
  42. * n = part after the comma
  43. * Classic formats: m = 2, n = 3 (size 2.3)
  44. * m = 3, n = 4 (size 3.4)
  45. * eg
  46. * GxxX00345Y-06123*
  47. *
  48. * Tools and D_CODES
  49. * Tool number (identification of shapes)
  50. * 10 to 999
  51. * D_CODES:
  52. * D01 ... D9 = command codes:
  53. * D01 = activating light (pen down) when placement
  54. * D02 = light extinction (pen up) when placement
  55. * D03 = Flash
  56. * D09 = VAPE Flash (I never see this command in gerber file)
  57. * D51 = G54 preceded by -> Select VAPE
  58. *
  59. * D10 ... D999 = Identification Tool: tool selection
  60. */
  61. // Photoplot actions:
  62. #define GERB_ACTIVE_DRAW 1 // Activate light (lower pen)
  63. #define GERB_STOP_DRAW 2 // Extinguish light (lift pen)
  64. #define GERB_FLASH 3 // Flash
  65. static wxPoint LastPosition;
  66. /* Local Functions (are lower case since they are private to this source file)
  67. **/
  68. /**
  69. * Function fillFlashedGBRITEM
  70. * initializes a given GBRITEM so that it can draw a circle which is filled and
  71. * has no pen border.
  72. *
  73. * @param aGbrItem The GBRITEM to fill in.
  74. * @param aAperture the associated type of aperture
  75. * @param Dcode_index The DCODE value, like D14
  76. * @param aLayer The layer index to set into the GBRITEM
  77. * @param aPos The center point of the flash
  78. * @param aSize The diameter of the round flash
  79. * @param aLayerNegative = true if the current layer is negative
  80. * @param aImageNegative = true if the current image is negative
  81. */
  82. static void fillFlashedGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
  83. APERTURE_T aAperture,
  84. int Dcode_index,
  85. int aLayer,
  86. const wxPoint& aPos,
  87. wxSize aSize,
  88. bool aLayerNegative,
  89. bool aImageNegative )
  90. {
  91. aGbrItem->SetLayer( aLayer );
  92. aGbrItem->m_Size = aSize;
  93. aGbrItem->m_Start = aPos;
  94. NEGATE( aGbrItem->m_Start.y );
  95. aGbrItem->m_End = aGbrItem->m_Start;
  96. aGbrItem->m_DCode = Dcode_index;
  97. aGbrItem->m_LayerNegative = aLayerNegative;
  98. aGbrItem->m_ImageNegative = aImageNegative;
  99. aGbrItem->m_Flashed = true;
  100. switch( aAperture )
  101. {
  102. case APT_POLYGON: // flashed regular polygon
  103. aGbrItem->m_Shape = GBR_SPOT_POLY;
  104. break;
  105. case APT_LINE: // Should not be used.
  106. case APT_CIRCLE:
  107. aGbrItem->m_Shape = GBR_SPOT_CIRCLE;
  108. aGbrItem->m_Size.y = aGbrItem->m_Size.x;
  109. break;
  110. case APT_OVAL:
  111. aGbrItem->m_Shape = GBR_SPOT_OVAL;
  112. break;
  113. case APT_RECT:
  114. aGbrItem->m_Shape = GBR_SPOT_RECT;
  115. break;
  116. case APT_MACRO:
  117. aGbrItem->m_Shape = GBR_SPOT_MACRO;
  118. break;
  119. }
  120. bool isDark = !(aGbrItem->m_LayerNegative ^ aGbrItem->m_ImageNegative);
  121. /* isDark is true if flash is positive and should use a drawing
  122. * color other than the background color, else use the background color
  123. * when drawing so that an erasure happens.
  124. */
  125. if( !isDark )
  126. {
  127. aGbrItem->m_Flags |= DRAW_ERASED;
  128. }
  129. }
  130. /**
  131. * Function fillLineGBRITEM
  132. * initializes a given GBRITEM so that it can draw a linear D code.
  133. *
  134. * @param aGbrItem The GERBER_DRAW_ITEM to fill in.
  135. * @param Dcode_index The DCODE value, like D14
  136. * @param aLayer The layer index to set into the GBRITEM
  137. * @param aPos The center point of the flash
  138. * @param aDiameter The diameter of the round flash
  139. * @param aLayerNegative = true if the current layer is negative
  140. * @param aImageNegative = true if the current image is negative
  141. */
  142. static void fillLineGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
  143. int Dcode_index,
  144. int aLayer,
  145. const wxPoint& aStart,
  146. const wxPoint& aEnd,
  147. int aWidth,
  148. bool aLayerNegative,
  149. bool aImageNegative )
  150. {
  151. aGbrItem->SetLayer( aLayer );
  152. aGbrItem->m_Flashed = false;
  153. aGbrItem->m_Size.x = aGbrItem->m_Size.y = aWidth;
  154. aGbrItem->m_Start = aStart;
  155. NEGATE( aGbrItem->m_Start.y );
  156. aGbrItem->m_End = aEnd;
  157. NEGATE( aGbrItem->m_End.y );
  158. aGbrItem->m_DCode = Dcode_index;
  159. aGbrItem->m_LayerNegative = aLayerNegative;
  160. aGbrItem->m_ImageNegative = aImageNegative;
  161. bool isDark = !(aGbrItem->m_LayerNegative ^ aGbrItem->m_ImageNegative);
  162. /* isDark is true if flash is positive and should use a drawing
  163. * color other than the background color, else use the background color
  164. * when drawing so that an erasure happens.
  165. */
  166. if( !isDark )
  167. {
  168. aGbrItem->m_Flags |= DRAW_ERASED;
  169. }
  170. }
  171. /**
  172. * Function fillArcGBRITEM
  173. * initializes a given GBRITEM so that it can draw an arc G code.
  174. * <p>
  175. * if multiquadrant == true : arc can be 0 to 360 degrees
  176. * and \a rel_center is the center coordinate relative to start point.
  177. * <p>
  178. * if multiquadrant == false arc can be only 0 to 90 deg,
  179. * and only in the same quadrant :
  180. * <ul>
  181. * <li> absolute angle 0 to 90 (quadrant 1) or
  182. * <li> absolute angle 90 to 180 (quadrant 2) or
  183. * <li> absolute angle 180 to 270 (quadrant 3) or
  184. * <li> absolute angle 270 to 0 (quadrant 4)
  185. * </ul><p>
  186. * @param GERBER_DRAW_ITEM is the GBRITEM to fill in.
  187. * @param Dcode_index is the DCODE value, like D14
  188. * @param aLayer is the layer index to set into the GBRITEM
  189. * @param aStart is the starting point
  190. * @param aEnd is the ending point
  191. * @param rel_center is the center coordinate relative to start point,
  192. * given in ABSOLUTE VALUE and the sign of values x et y de rel_center
  193. * must be calculated from the previously given constraint: arc only in the
  194. * same quadrant.
  195. * @param aDiameter The diameter of the round flash
  196. * @param aWidth is the pen width.
  197. * @param aLayerNegative = true if the current layer is negative
  198. * @param aImageNegative = true if the current image is negative
  199. */
  200. static void fillArcGBRITEM( GERBER_DRAW_ITEM* aGbrItem, int Dcode_index, int aLayer,
  201. const wxPoint& aStart, const wxPoint& aEnd,
  202. const wxPoint& rel_center, int aWidth,
  203. bool clockwise, bool multiquadrant,
  204. bool aLayerNegative,
  205. bool aImageNegative )
  206. {
  207. wxPoint center, delta;
  208. aGbrItem->m_Shape = GBR_ARC;
  209. aGbrItem->SetLayer( aLayer );
  210. aGbrItem->m_Size.x = aGbrItem->m_Size.y = aWidth;
  211. aGbrItem->m_Flashed = false;
  212. if( multiquadrant )
  213. {
  214. center.x = aStart.x + rel_center.x;
  215. center.y = aStart.y + rel_center.y;
  216. if( clockwise )
  217. {
  218. aGbrItem->m_Start = aStart;
  219. aGbrItem->m_End = aEnd;
  220. }
  221. else
  222. {
  223. aGbrItem->m_Start = aEnd;
  224. aGbrItem->m_End = aStart;
  225. }
  226. }
  227. else
  228. {
  229. center = rel_center;
  230. delta = aEnd - aStart;
  231. if( (delta.x >= 0) && (delta.y >= 0) )
  232. {
  233. // Quadrant 2
  234. }
  235. else if( (delta.x >= 0) && (delta.y < 0) )
  236. {
  237. // Quadrant 1
  238. center.y = -center.y;
  239. }
  240. else if( (delta.x < 0) && (delta.y >= 0) )
  241. {
  242. // Quadrant 4
  243. center.x = -center.x;
  244. }
  245. else
  246. {
  247. // Quadrant 3
  248. center.x = -center.x;
  249. center.y = -center.y;
  250. }
  251. center.x += aStart.x;
  252. center.y += aStart.y;
  253. if( clockwise )
  254. {
  255. aGbrItem->m_Start = aStart;
  256. aGbrItem->m_End = aEnd;
  257. }
  258. else
  259. {
  260. aGbrItem->m_Start = aEnd;
  261. aGbrItem->m_End = aStart;
  262. }
  263. }
  264. aGbrItem->m_DCode = Dcode_index;
  265. aGbrItem->m_ArcCentre = center;
  266. NEGATE( aGbrItem->m_Start.y );
  267. NEGATE( aGbrItem->m_End.y );
  268. NEGATE( aGbrItem->m_ArcCentre.y );
  269. aGbrItem->m_LayerNegative = aLayerNegative;
  270. aGbrItem->m_ImageNegative = aImageNegative;
  271. bool isDark = !(aGbrItem->m_LayerNegative ^ aGbrItem->m_ImageNegative);
  272. /* isDark is true if flash is positive and should use a drawing
  273. * color other than the background color, else use the background color
  274. * when drawing so that an erasure happens.
  275. */
  276. if( !isDark )
  277. {
  278. aGbrItem->m_Flags |= DRAW_ERASED;
  279. }
  280. }
  281. /**
  282. * Function fillArcPOLY
  283. * creates an arc G code when found in poly outlines.
  284. * <p>
  285. * if multiquadrant == true : arc can be 0 to 360 degrees
  286. * and \a rel_center is the center coordinate relative to start point.
  287. * <p>
  288. * if multiquadrant == false arc can be only 0 to 90 deg,
  289. * and only in the same quadrant :
  290. * <ul>
  291. * <li> absolute angle 0 to 90 (quadrant 1) or
  292. * <li> absolute angle 90 to 180 (quadrant 2) or
  293. * <li> absolute angle 180 to 270 (quadrant 3) or
  294. * <li> absolute angle 270 to 0 (quadrant 4)
  295. * </ul><p>
  296. * @param aPcb is the board.
  297. * @param aLayer is the layer index to set into the GBRITEM
  298. * @param aStart is the starting point
  299. * @param aEnd is the ending point
  300. * @param rel_center is the center coordinate relative to start point,
  301. * given in ABSOLUTE VALUE and the sign of values x et y de rel_center
  302. * must be calculated from the previously given constraint: arc only in the
  303. * same quadrant.
  304. * @param aDiameter The diameter of the round flash
  305. * @param aWidth is the pen width.
  306. * @param aLayerNegative = true if the current layer is negative
  307. * @param aImageNegative = true if the current image is negative
  308. */
  309. static void fillArcPOLY( BOARD* aPcb, GERBER_DRAW_ITEM* aGbrItem,
  310. const wxPoint& aStart, const wxPoint& aEnd,
  311. const wxPoint& rel_center,
  312. bool clockwise, bool multiquadrant,
  313. bool aLayerNegative,
  314. bool aImageNegative )
  315. {
  316. /* in order to calculate arc parameters, we use fillArcGBRITEM
  317. * so we muse create a dummy track and use its geometric parameters
  318. */
  319. static GERBER_DRAW_ITEM dummyGbrItem( NULL );
  320. aGbrItem->m_LayerNegative = aLayerNegative;
  321. aGbrItem->m_ImageNegative = aImageNegative;
  322. bool isDark = !(aGbrItem->m_LayerNegative ^ aGbrItem->m_ImageNegative);
  323. /* isDark is true if flash is positive and should use a drawing
  324. * color other than the background color, else use the background color
  325. * when drawing so that an erasure happens.
  326. */
  327. if( !isDark )
  328. {
  329. aGbrItem->m_Flags |= DRAW_ERASED;
  330. }
  331. fillArcGBRITEM( &dummyGbrItem, 0, 0,
  332. aStart, aEnd, rel_center, 0,
  333. clockwise, multiquadrant, aLayerNegative, aImageNegative );
  334. // dummyTrack has right geometric parameters, and has its Y coordinates negated (to match the pcbnew Y axis).
  335. // Approximate arc by 36 segments per 360 degree
  336. const int increment_angle = 360 / 36;
  337. wxPoint center;
  338. center = dummyGbrItem.m_ArcCentre;
  339. // Calculate relative coordinates;
  340. wxPoint start = dummyGbrItem.m_Start - center;
  341. wxPoint end = dummyGbrItem.m_End - center;
  342. /* Calculate angle arc
  343. * angle is here clockwise because Y axis is reversed
  344. */
  345. double start_angle = atan2( (double) start.y, (double) start.x );
  346. start_angle = 180 * start_angle / M_PI;
  347. double end_angle = atan2( (double) end.y, (double) end.x );
  348. end_angle = 180 * end_angle / M_PI;
  349. double angle = start_angle - end_angle;
  350. // D( printf( " >>>> st %d,%d angle %f, end %d,%d angle %f delta %f\n",
  351. // start.x, start.y, start_angle, end.x, end.y, end_angle, angle ) );
  352. if( !clockwise )
  353. {
  354. EXCHG( start, end );
  355. D( printf( " >>>> reverse arc\n" ) );
  356. }
  357. // Normalize angle
  358. while( angle > 360.0 )
  359. angle -= 360.0;
  360. while( angle < 0.0 )
  361. angle += 360.0;
  362. int count = (int) ( angle / increment_angle );
  363. if( count <= 0 )
  364. count = 1;
  365. // D( printf( " >>>> angle %f, cnt %d sens %d\n", angle, count, clockwise ) );
  366. // calculate segments
  367. wxPoint start_arc = start;
  368. for( int ii = 1; ii <= count; ii++ )
  369. {
  370. wxPoint end_arc = start;
  371. int rot = 10 * ii * increment_angle; // rot is in 0.1 deg
  372. if( ii < count )
  373. {
  374. if( clockwise )
  375. RotatePoint( &end_arc, rot );
  376. else
  377. RotatePoint( &end_arc, -rot );
  378. }
  379. else
  380. end_arc = end;
  381. // D( printf( " >> Add arc %d rot %d, edge poly item %d,%d to %d,%d\n",
  382. // ii, rot, start_arc.x, start_arc.y,end_arc.x, end_arc.y ); )
  383. if( aGbrItem->m_PolyCorners.size() == 0 )
  384. aGbrItem->m_PolyCorners.push_back( start_arc + center );
  385. aGbrItem->m_PolyCorners.push_back( end_arc + center );
  386. start_arc = end_arc;
  387. }
  388. }
  389. /* These routines read the text string point from Text.
  390. * After use, advanced Text the beginning of the sequence unread
  391. */
  392. wxPoint GERBER::ReadXYCoord( char*& Text )
  393. {
  394. wxPoint pos = m_CurrentPos;
  395. int type_coord = 0, current_coord, nbchar;
  396. bool is_float = false;
  397. char* text;
  398. char line[256];
  399. if( m_Relative )
  400. pos.x = pos.y = 0;
  401. else
  402. pos = m_CurrentPos;
  403. if( Text == NULL )
  404. return pos;
  405. text = line;
  406. while( *Text )
  407. {
  408. if( (*Text == 'X') || (*Text == 'Y') )
  409. {
  410. type_coord = *Text;
  411. Text++;
  412. text = line;
  413. nbchar = 0;
  414. while( IsNumber( *Text ) )
  415. {
  416. if( *Text == '.' )
  417. is_float = true;
  418. *(text++) = *(Text++);
  419. if( (*Text >= '0') && (*Text <='9') )
  420. nbchar++;
  421. }
  422. *text = 0;
  423. if( is_float )
  424. {
  425. if( m_GerbMetric )
  426. current_coord = wxRound( atof( line ) / 0.00254 );
  427. else
  428. current_coord = wxRound( atof( line ) * PCB_INTERNAL_UNIT );
  429. }
  430. else
  431. {
  432. int fmt_scale =
  433. (type_coord == 'X') ? m_FmtScale.x : m_FmtScale.y;
  434. if( m_NoTrailingZeros )
  435. {
  436. int min_digit =
  437. (type_coord == 'X') ? m_FmtLen.x : m_FmtLen.y;
  438. while( nbchar < min_digit )
  439. {
  440. *(text++) = '0';
  441. nbchar++;
  442. }
  443. *text = 0;
  444. }
  445. current_coord = atoi( line );
  446. double real_scale = 1.0;
  447. if( fmt_scale < 0 || fmt_scale > 9 )
  448. fmt_scale = 4;
  449. double scale_list[10] =
  450. {
  451. 10000.0, 1000.0, 100.0, 10.0,
  452. 1,
  453. 0.1, 0.01, 0.001, 0.0001,0.00001
  454. };
  455. real_scale = scale_list[fmt_scale];
  456. if( m_GerbMetric )
  457. real_scale = real_scale / 25.4;
  458. current_coord = wxRound( current_coord * real_scale );
  459. }
  460. if( type_coord == 'X' )
  461. pos.x = current_coord;
  462. else if( type_coord == 'Y' )
  463. pos.y = current_coord;
  464. continue;
  465. }
  466. else
  467. break;
  468. }
  469. if( m_Relative )
  470. {
  471. pos.x += m_CurrentPos.x;
  472. pos.y += m_CurrentPos.y;
  473. }
  474. m_CurrentPos = pos;
  475. return pos;
  476. }
  477. /* Returns the current coordinate type pointed to by InnJnn Text (InnnnJmmmm)
  478. * These coordinates are relative, so if coordinate is absent, it's value
  479. * defaults to 0
  480. */
  481. wxPoint GERBER::ReadIJCoord( char*& Text )
  482. {
  483. wxPoint pos( 0, 0 );
  484. int type_coord = 0, current_coord, nbchar;
  485. bool is_float = false;
  486. char* text;
  487. char line[256];
  488. if( Text == NULL )
  489. return pos;
  490. text = line;
  491. while( *Text )
  492. {
  493. if( (*Text == 'I') || (*Text == 'J') )
  494. {
  495. type_coord = *Text;
  496. Text++;
  497. text = line;
  498. nbchar = 0;
  499. while( IsNumber( *Text ) )
  500. {
  501. if( *Text == '.' )
  502. is_float = true;
  503. *(text++) = *(Text++);
  504. if( (*Text >= '0') && (*Text <='9') )
  505. nbchar++;
  506. }
  507. *text = 0;
  508. if( is_float )
  509. {
  510. if( m_GerbMetric )
  511. current_coord = wxRound( atof( line ) / 0.00254 );
  512. else
  513. current_coord = wxRound( atof( line ) * PCB_INTERNAL_UNIT );
  514. }
  515. else
  516. {
  517. int fmt_scale =
  518. (type_coord == 'I') ? m_FmtScale.x : m_FmtScale.y;
  519. if( m_NoTrailingZeros )
  520. {
  521. int min_digit =
  522. (type_coord == 'I') ? m_FmtLen.x : m_FmtLen.y;
  523. while( nbchar < min_digit )
  524. {
  525. *(text++) = '0';
  526. nbchar++;
  527. }
  528. *text = 0;
  529. }
  530. current_coord = atoi( line );
  531. double real_scale = 1.0;
  532. if( fmt_scale < 0 || fmt_scale > 9 )
  533. fmt_scale = 4; // select scale 1.0
  534. double scale_list[10] =
  535. {
  536. 10000.0, 1000.0, 100.0, 10.0,
  537. 1,
  538. 0.1, 0.01, 0.001, 0.0001,0.00001
  539. };
  540. real_scale = scale_list[fmt_scale];
  541. if( m_GerbMetric )
  542. real_scale = real_scale / 25.4;
  543. current_coord = wxRound( current_coord * real_scale );
  544. }
  545. if( type_coord == 'I' )
  546. pos.x = current_coord;
  547. else if( type_coord == 'J' )
  548. pos.y = current_coord;
  549. continue;
  550. }
  551. else
  552. break;
  553. }
  554. m_IJPos = pos;
  555. return pos;
  556. }
  557. /* Read the Gnn sequence and returns the value nn.
  558. */
  559. int GERBER::ReturnGCodeNumber( char*& Text )
  560. {
  561. int ii = 0;
  562. char* text;
  563. char line[1024];
  564. if( Text == NULL )
  565. return 0;
  566. Text++;
  567. text = line;
  568. while( IsNumber( *Text ) )
  569. {
  570. *(text++) = *(Text++);
  571. }
  572. *text = 0;
  573. ii = atoi( line );
  574. return ii;
  575. }
  576. /* Get the sequence Dnn and returns the value nn
  577. */
  578. int GERBER::ReturnDCodeNumber( char*& Text )
  579. {
  580. int ii = 0;
  581. char* text;
  582. char line[1024];
  583. if( Text == NULL )
  584. return 0;
  585. Text++;
  586. text = line;
  587. while( IsNumber( *Text ) )
  588. *(text++) = *(Text++);
  589. *text = 0;
  590. ii = atoi( line );
  591. return ii;
  592. }
  593. bool GERBER::Execute_G_Command( char*& text, int G_commande )
  594. {
  595. // D( printf( "%22s: G_CODE<%d>\n", __func__, G_commande ); )
  596. switch( G_commande )
  597. {
  598. case GC_PHOTO_MODE: // can starts a D03 flash command: redundant, can
  599. // be safely ignored
  600. break;
  601. case GC_LINEAR_INTERPOL_1X:
  602. m_Iterpolation = GERB_INTERPOL_LINEAR_1X;
  603. break;
  604. case GC_CIRCLE_NEG_INTERPOL:
  605. m_Iterpolation = GERB_INTERPOL_ARC_NEG;
  606. break;
  607. case GC_CIRCLE_POS_INTERPOL:
  608. m_Iterpolation = GERB_INTERPOL_ARC_POS;
  609. break;
  610. case GC_COMMENT:
  611. text = NULL;
  612. break;
  613. case GC_LINEAR_INTERPOL_10X:
  614. m_Iterpolation = GERB_INTERPOL_LINEAR_10X;
  615. break;
  616. case GC_LINEAR_INTERPOL_0P1X:
  617. m_Iterpolation = GERB_INTERPOL_LINEAR_01X;
  618. break;
  619. case GC_LINEAR_INTERPOL_0P01X:
  620. m_Iterpolation = GERB_INTERPOL_LINEAR_001X;
  621. break;
  622. case GC_SELECT_TOOL:
  623. {
  624. int D_commande = ReturnDCodeNumber( text );
  625. if( D_commande < FIRST_DCODE )
  626. return false;
  627. if( D_commande > (TOOLS_MAX_COUNT - 1) )
  628. D_commande = TOOLS_MAX_COUNT - 1;
  629. m_Current_Tool = D_commande;
  630. D_CODE* pt_Dcode = GetDCODE( D_commande, false );
  631. if( pt_Dcode )
  632. pt_Dcode->m_InUse = true;
  633. break;
  634. }
  635. case GC_SPECIFY_INCHES:
  636. m_GerbMetric = false; // false = Inches, true = metric
  637. break;
  638. case GC_SPECIFY_MILLIMETERS:
  639. m_GerbMetric = true; // false = Inches, true = metric
  640. break;
  641. case GC_TURN_OFF_360_INTERPOL: // disable Multi cadran arc and Arc interpol
  642. m_360Arc_enbl = false;
  643. m_Iterpolation = GERB_INTERPOL_LINEAR_1X;
  644. break;
  645. case GC_TURN_ON_360_INTERPOL:
  646. m_360Arc_enbl = true;
  647. break;
  648. case GC_SPECIFY_ABSOLUES_COORD:
  649. m_Relative = false; // false = absolute Coord, true = relative
  650. // Coord
  651. break;
  652. case GC_SPECIFY_RELATIVEES_COORD:
  653. m_Relative = true; // false = absolute Coord, true = relative
  654. // Coord
  655. break;
  656. case GC_TURN_ON_POLY_FILL:
  657. m_PolygonFillMode = true;
  658. break;
  659. case GC_TURN_OFF_POLY_FILL:
  660. m_PolygonFillMode = false;
  661. m_PolygonFillModeState = 0;
  662. break;
  663. case GC_MOVE: // Non existent
  664. default:
  665. {
  666. wxString msg; msg.Printf( wxT( "G%0.2d command not handled" ),
  667. G_commande );
  668. DisplayError( NULL, msg );
  669. return false;
  670. }
  671. }
  672. return true;
  673. }
  674. /**
  675. * Function scale
  676. * converts a distance given in floating point to our deci-mils
  677. */
  678. int scale( double aCoord, bool isMetric )
  679. {
  680. int ret;
  681. if( isMetric )
  682. ret = wxRound( aCoord / 0.00254 );
  683. else
  684. ret = wxRound( aCoord * PCB_INTERNAL_UNIT );
  685. return ret;
  686. }
  687. /**
  688. * Function mapPt
  689. * translates a point from the aperture macro coordinate system to our
  690. * deci-mils coordinate system.
  691. * @return wxPoint - The gerbview coordinate system vector.
  692. */
  693. wxPoint mapPt( double x, double y, bool isMetric )
  694. {
  695. wxPoint ret( scale( x, isMetric ), scale( y, isMetric ) );
  696. return ret;
  697. }
  698. bool GERBER::Execute_DCODE_Command( WinEDA_GerberFrame* frame, char*& text, int D_commande )
  699. {
  700. wxSize size( 15, 15 );
  701. APERTURE_T aperture = APT_CIRCLE;
  702. GERBER_DRAW_ITEM* gbritem;
  703. BOARD* pcb = frame->GetBoard();
  704. int activeLayer = frame->GetScreen()->m_Active_Layer;
  705. int dcode = 0;
  706. D_CODE* tool = NULL;
  707. wxString msg;
  708. // D( printf( "%22s: D_CODE<%d>\n", __func__, D_commande ); )
  709. if( D_commande >= FIRST_DCODE ) // This is a "Set tool" command
  710. {
  711. if( D_commande > (TOOLS_MAX_COUNT - 1) )
  712. D_commande = TOOLS_MAX_COUNT - 1;
  713. // remember which tool is selected, nothing is done with it in this
  714. // call
  715. m_Current_Tool = D_commande;
  716. D_CODE* pt_Dcode = GetDCODE( D_commande, false );
  717. if( pt_Dcode )
  718. pt_Dcode->m_InUse = true;
  719. return true;
  720. }
  721. else // D_commande = 0..9: this is a pen command (usually D1, D2 or D3)
  722. {
  723. m_Last_Pen_Command = D_commande;
  724. }
  725. if( m_PolygonFillMode ) // Enter a polygon description:
  726. {
  727. switch( D_commande )
  728. {
  729. case 1: // code D01 Draw line, exposure ON
  730. if( !m_Exposure )
  731. {
  732. m_Exposure = true;
  733. gbritem = new GERBER_DRAW_ITEM( pcb );
  734. pcb->m_Drawings.Append( gbritem );
  735. gbritem->m_Shape = GBR_POLYGON;
  736. gbritem->SetLayer( activeLayer );
  737. gbritem->m_Flashed = false;
  738. gbritem->m_UnitsMetric = m_GerbMetric;
  739. }
  740. switch( m_Iterpolation )
  741. {
  742. case GERB_INTERPOL_ARC_NEG:
  743. case GERB_INTERPOL_ARC_POS:
  744. gbritem = (GERBER_DRAW_ITEM*)( pcb->m_Drawings.GetLast() );
  745. // D( printf( "Add arc poly %d,%d to %d,%d fill %d interpol %d 360_enb %d\n",
  746. // m_PreviousPos.x, m_PreviousPos.y, m_CurrentPos.x,
  747. // m_CurrentPos.y, m_PolygonFillModeState,
  748. // m_Iterpolation, m_360Arc_enbl ); )
  749. fillArcPOLY( pcb, gbritem, m_PreviousPos,
  750. m_CurrentPos, m_IJPos,
  751. ( m_Iterpolation == GERB_INTERPOL_ARC_NEG ) ? false : true,
  752. m_360Arc_enbl, m_LayerNegative, m_ImageNegative );
  753. break;
  754. default:
  755. gbritem = (GERBER_DRAW_ITEM*)( pcb->m_Drawings.GetLast() );
  756. // D( printf( "Add poly edge %d,%d to %d,%d fill %d\n",
  757. // m_PreviousPos.x, m_PreviousPos.y,
  758. // m_CurrentPos.x, m_CurrentPos.y, m_Iterpolation ); )
  759. gbritem->m_Start = m_PreviousPos; // m_Start is used as temporary storage
  760. NEGATE( gbritem->m_Start.y );
  761. if( gbritem->m_PolyCorners.size() == 0 )
  762. gbritem->m_PolyCorners.push_back( gbritem->m_Start );
  763. gbritem->m_End = m_CurrentPos; // m_End is used as temporary storage
  764. NEGATE( gbritem->m_End.y );
  765. gbritem->m_PolyCorners.push_back( gbritem->m_End );
  766. // Set the erasure flag of gbritem if a negative polygon.
  767. if( !m_PolygonFillModeState )
  768. {
  769. if( m_LayerNegative ^ m_ImageNegative )
  770. gbritem->m_Flags |= DRAW_ERASED;
  771. }
  772. break;
  773. }
  774. m_PreviousPos = m_CurrentPos;
  775. m_PolygonFillModeState = 1;
  776. break;
  777. case 2: // code D2: exposure OFF (i.e. "move to")
  778. m_Exposure = false;
  779. m_PreviousPos = m_CurrentPos;
  780. m_PolygonFillModeState = 0;
  781. break;
  782. default:
  783. return false;
  784. }
  785. }
  786. else
  787. {
  788. switch( D_commande )
  789. {
  790. case 1: // code D01 Draw line, exposure ON
  791. m_Exposure = true;
  792. tool = GetDCODE( m_Current_Tool, false );
  793. if( tool )
  794. {
  795. size = tool->m_Size;
  796. dcode = tool->m_Num_Dcode;
  797. aperture = tool->m_Shape;
  798. }
  799. switch( m_Iterpolation )
  800. {
  801. case GERB_INTERPOL_LINEAR_1X:
  802. gbritem = new GERBER_DRAW_ITEM( pcb );
  803. gbritem->m_UnitsMetric = m_GerbMetric;
  804. pcb->m_Drawings.Append( gbritem );
  805. // D( printf( "Add line %d,%d to %d,%d\n",
  806. // m_PreviousPos.x, m_PreviousPos.y,
  807. // m_CurrentPos.x, m_CurrentPos.y ); )
  808. fillLineGBRITEM( gbritem, dcode, activeLayer, m_PreviousPos,
  809. m_CurrentPos, size.x, m_LayerNegative, m_ImageNegative );
  810. break;
  811. case GERB_INTERPOL_LINEAR_01X:
  812. case GERB_INTERPOL_LINEAR_001X:
  813. case GERB_INTERPOL_LINEAR_10X:
  814. wxBell();
  815. break;
  816. case GERB_INTERPOL_ARC_NEG:
  817. case GERB_INTERPOL_ARC_POS:
  818. gbritem = new GERBER_DRAW_ITEM( pcb );
  819. gbritem->m_UnitsMetric = m_GerbMetric;
  820. pcb->m_Drawings.Append( gbritem );
  821. // D( printf( "Add arc %d,%d to %d,%d center %d, %d interpol %d 360_enb %d\n",
  822. // m_PreviousPos.x, m_PreviousPos.y, m_CurrentPos.x,
  823. // m_CurrentPos.y, m_IJPos.x,
  824. // m_IJPos.y, m_Iterpolation, m_360Arc_enbl ); )
  825. fillArcGBRITEM( gbritem, dcode, activeLayer, m_PreviousPos,
  826. m_CurrentPos, m_IJPos, size.x,
  827. ( m_Iterpolation == GERB_INTERPOL_ARC_NEG ) ?
  828. false : true, m_360Arc_enbl,
  829. m_LayerNegative, m_ImageNegative );
  830. break;
  831. default:
  832. msg.Printf( wxT( "Execute_DCODE_Command: interpol error (type %X)" ),
  833. m_Iterpolation );
  834. DisplayError( frame, msg );
  835. break;
  836. }
  837. m_PreviousPos = m_CurrentPos;
  838. break;
  839. case 2: // code D2: exposure OFF (i.e. "move to")
  840. m_Exposure = false;
  841. // D( printf( "Move to %d,%d to %d,%d\n",
  842. // m_PreviousPos.x, m_PreviousPos.y,
  843. // m_CurrentPos.x, m_CurrentPos.y ); )
  844. m_PreviousPos = m_CurrentPos;
  845. break;
  846. case 3: // code D3: flash aperture
  847. tool = GetDCODE( m_Current_Tool, false );
  848. if( tool )
  849. {
  850. size = tool->m_Size;
  851. dcode = tool->m_Num_Dcode;
  852. aperture = tool->m_Shape;
  853. }
  854. gbritem = new GERBER_DRAW_ITEM( pcb );
  855. gbritem->m_UnitsMetric = m_GerbMetric;
  856. pcb->m_Drawings.Append( gbritem );
  857. // D( printf( "Add flashed dcode %d layer %d at %d %d\n", dcode, activeLayer,
  858. // m_CurrentPos.x, m_CurrentPos.y ); )
  859. fillFlashedGBRITEM( gbritem, aperture,
  860. dcode, activeLayer, m_CurrentPos,
  861. size, m_LayerNegative, m_ImageNegative );
  862. m_PreviousPos = m_CurrentPos;
  863. break;
  864. default:
  865. return false;
  866. }
  867. }
  868. return true;
  869. }