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.

1416 lines
44 KiB

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