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.

761 lines
24 KiB

6 years ago
  1. /**
  2. * @file rs274d.cpp
  3. * @brief functions to read the rs274d commands from a rs274d/rs274x file
  4. */
  5. /*
  6. * This program source code file is part of KiCad, a free EDA CAD application.
  7. *
  8. * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License
  12. * as published by the Free Software Foundation; either version 2
  13. * of the License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, you may find one here:
  22. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  23. * or you may search the http://www.gnu.org website for the version 2 license,
  24. * or you may write to the Free Software Foundation, Inc.,
  25. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  26. */
  27. #include <gerbview.h>
  28. #include <gerbview_frame.h>
  29. #include <trigo.h>
  30. #include <gerber_file_image.h>
  31. #include <X2_gerber_attributes.h>
  32. #include <cmath>
  33. /* Gerber: NOTES about some important commands found in RS274D and RS274X (G codes).
  34. * Some are now deprecated, but deprecated commands must be known by the Gerber reader
  35. * Gn =
  36. * G01 linear interpolation (linear trace)
  37. * G02, G20, G21 Circular interpolation, clockwise
  38. * G03, G30, G31 Circular interpolation, counterclockwise
  39. * G04 = comment. Since Sept 2014, file attributes and other X2 attributes can be found here
  40. * if the line starts by G04 #@!
  41. * G06 parabolic interpolation
  42. * G07 Cubic Interpolation
  43. * G10 linear interpolation (scale x10)
  44. * G11 linear interpolation (0.1x range)
  45. * G12 linear interpolation (0.01x scale)
  46. * G36 Start polygon mode (called a region, because the "polygon" can include arcs)
  47. * G37 Stop polygon mode (and close it)
  48. * G54 Selection Tool (outdated)
  49. * G60 linear interpolation (scale x100)
  50. * G70 Select Units = Inches
  51. * G71 Select Units = Millimeters
  52. * G74 enable 90 deg mode for arcs (CW or CCW)
  53. * G75 enable 360 degrees for arcs (CW or CCW)
  54. * G90 mode absolute coordinates
  55. *
  56. * X, Y
  57. * X and Y are followed by + or - and m + n digits (not separated)
  58. * m = integer part
  59. * n = part after the comma
  60. *ic formats: m = 2, n = 3 (size 2.3)
  61. * m = 3, n = 4 (size 3.4)
  62. * eg
  63. * GxxX00345Y-06123*
  64. *
  65. * Tools and D_CODES
  66. * Tool number (identification of shapes)
  67. * 10 to 999
  68. * D_CODES:
  69. * D01 ... D9 = command codes:
  70. * D01 = activating light (pen down) when placement
  71. * D02 = light extinction (pen up) when placement
  72. * D03 = Flash
  73. * D09 = VAPE Flash (I never see this command in Gerber file)
  74. * D51 = G54 preceded by -> Select VAPE
  75. *
  76. * D10 ... D999 = Identification Tool: tool selection
  77. */
  78. /* Local Functions (are lower case since they are private to this source file)
  79. **/
  80. /**
  81. * Initializes a given GBRITEM so that it can draw a circle which is filled and
  82. * has no pen border.
  83. *
  84. * @param aGbrItem The GBRITEM to fill in.
  85. * @param aAperture the associated type of aperture.
  86. * @param Dcode_index The DCODE value, like D14.
  87. * @param aPos The center point of the flash.
  88. * @param aSize The diameter of the round flash.
  89. * @param aLayerNegative set to true if the current layer is negative.
  90. */
  91. void fillFlashedGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
  92. APERTURE_T aAperture,
  93. int Dcode_index,
  94. const VECTOR2I& aPos,
  95. wxSize aSize,
  96. bool aLayerNegative )
  97. {
  98. aGbrItem->m_Size = aSize;
  99. aGbrItem->m_Start = aPos;
  100. aGbrItem->m_End = aGbrItem->m_Start;
  101. aGbrItem->m_DCode = Dcode_index;
  102. aGbrItem->SetLayerPolarity( aLayerNegative );
  103. aGbrItem->m_Flashed = true;
  104. aGbrItem->SetNetAttributes( aGbrItem->m_GerberImageFile->m_NetAttributeDict );
  105. switch( aAperture )
  106. {
  107. case APT_POLYGON: // flashed regular polygon
  108. aGbrItem->m_Shape = GBR_SPOT_POLY;
  109. break;
  110. case APT_CIRCLE:
  111. aGbrItem->m_Shape = GBR_SPOT_CIRCLE;
  112. aGbrItem->m_Size.y = aGbrItem->m_Size.x;
  113. break;
  114. case APT_OVAL:
  115. aGbrItem->m_Shape = GBR_SPOT_OVAL;
  116. break;
  117. case APT_RECT:
  118. aGbrItem->m_Shape = GBR_SPOT_RECT;
  119. break;
  120. case APT_MACRO:
  121. aGbrItem->m_Shape = GBR_SPOT_MACRO;
  122. // Cache the bounding box for aperture macros
  123. aGbrItem->GetDcodeDescr()->GetMacro()->GetApertureMacroShape( aGbrItem, aPos );
  124. break;
  125. }
  126. }
  127. /**
  128. * Initialize a given GBRITEM so that it can draw a linear D code.
  129. *
  130. * @param aGbrItem The GERBER_DRAW_ITEM to fill in.
  131. * @param Dcode_index The DCODE value, like D14.
  132. * @param aStart The starting point of the line.
  133. * @param aEnd The ending point of the line.
  134. * @param aPenSize The size of the flash. Note rectangular shapes are legal.
  135. * @param aLayerNegative set to true if the current layer is negative.
  136. */
  137. void fillLineGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
  138. int Dcode_index,
  139. const VECTOR2I& aStart,
  140. const VECTOR2I& aEnd,
  141. wxSize aPenSize,
  142. bool aLayerNegative )
  143. {
  144. aGbrItem->m_Flashed = false;
  145. aGbrItem->m_Size = aPenSize;
  146. aGbrItem->m_Start = aStart;
  147. aGbrItem->m_End = aEnd;
  148. aGbrItem->m_DCode = Dcode_index;
  149. aGbrItem->SetLayerPolarity( aLayerNegative );
  150. aGbrItem->SetNetAttributes( aGbrItem->m_GerberImageFile->m_NetAttributeDict );
  151. }
  152. /**
  153. * Initialize a given GBRITEM so that it can draw an arc G code.
  154. *
  155. * If multiquadrant == true : arc can be 0 to 360 degrees
  156. * and \a rel_center is the center coordinate relative to start point.
  157. *
  158. * If multiquadrant == false arc can be only 0 to 90 deg,
  159. * and only in the same quadrant :
  160. * <ul>
  161. * <li> absolute angle 0 to 90 (quadrant 1) or
  162. * <li> absolute angle 90 to 180 (quadrant 2) or
  163. * <li> absolute angle 180 to 270 (quadrant 3) or
  164. * <li> absolute angle 270 to 0 (quadrant 4)
  165. * </ul>
  166. *
  167. * @param aGbrItem is the GBRITEM to fill in.
  168. * @param Dcode_index is the DCODE value, like D14.
  169. * @param aStart is the starting point.
  170. * @param aEnd is the ending point.
  171. * @param aRelCenter is the center coordinate relative to start point,
  172. * given in ABSOLUTE VALUE and the sign of values x et y de rel_center
  173. * must be calculated from the previously given constraint: arc only in the same quadrant.
  174. * @param aClockwise true if arc must be created clockwise
  175. * @param aPenSize The size of the flash. Note rectangular shapes are legal.
  176. * @param aMultiquadrant set to true to create arcs up to 360 degrees,
  177. * false when arc is inside one quadrant
  178. * @param aLayerNegative set to true if the current layer is negative.
  179. */
  180. void fillArcGBRITEM( GERBER_DRAW_ITEM* aGbrItem, int Dcode_index, const VECTOR2I& aStart,
  181. const VECTOR2I& aEnd, const VECTOR2I& aRelCenter, wxSize aPenSize,
  182. bool aClockwise, bool aMultiquadrant, bool aLayerNegative )
  183. {
  184. VECTOR2I center, delta;
  185. aGbrItem->m_Shape = GBR_ARC;
  186. aGbrItem->m_Size = aPenSize;
  187. aGbrItem->m_Flashed = false;
  188. if( aGbrItem->m_GerberImageFile )
  189. aGbrItem->SetNetAttributes( aGbrItem->m_GerberImageFile->m_NetAttributeDict );
  190. if( aMultiquadrant )
  191. {
  192. center = aStart + aRelCenter;
  193. }
  194. else
  195. {
  196. // in single quadrant mode the relative coordinate aRelCenter is always >= 0
  197. // So we must recalculate the actual sign of aRelCenter.x and aRelCenter.y
  198. center = aRelCenter;
  199. // calculate arc end coordinate relative to the starting point,
  200. // because center is relative to the center point
  201. delta = aEnd - aStart;
  202. // now calculate the relative to aStart center position, for a draw function
  203. // that use trigonometric arc angle (or counter-clockwise)
  204. /* Quadrants:
  205. * Y
  206. * 2 | 1
  207. * -------X
  208. * 3 | 4
  209. * C = actual relative arc center, S = arc start (axis origin) E = relative arc end
  210. */
  211. if( (delta.x >= 0) && (delta.y >= 0) )
  212. {
  213. /* Quadrant 1 (trigo or cclockwise):
  214. * C | E
  215. * ---S---
  216. * 3 | 4
  217. */
  218. center.x = -center.x;
  219. }
  220. else if( (delta.x >= 0) && (delta.y < 0) )
  221. {
  222. /* Quadrant 4 (trigo or cclockwise):
  223. * 2 | C
  224. * ---S---
  225. * 3 | E
  226. */
  227. // Nothing to do
  228. }
  229. else if( (delta.x < 0) && (delta.y >= 0) )
  230. {
  231. /* Quadrant 2 (trigo or cclockwise):
  232. * E | 1
  233. * ---S---
  234. * C | 4
  235. */
  236. center.x = -center.x;
  237. center.y = -center.y;
  238. }
  239. else
  240. {
  241. /* Quadrant 3 (trigo or cclockwise):
  242. * 2 | 1
  243. * ---S---
  244. * E | C
  245. */
  246. center.y = -center.y;
  247. }
  248. // Due to your draw arc function, we need this:
  249. if( !aClockwise )
  250. center = - center;
  251. // Calculate actual arc center coordinate:
  252. center += aStart;
  253. }
  254. if( aClockwise )
  255. {
  256. aGbrItem->m_Start = aStart;
  257. aGbrItem->m_End = aEnd;
  258. }
  259. else
  260. {
  261. aGbrItem->m_Start = aEnd;
  262. aGbrItem->m_End = aStart;
  263. }
  264. aGbrItem->m_ArcCentre = center;
  265. aGbrItem->m_DCode = Dcode_index;
  266. aGbrItem->SetLayerPolarity( aLayerNegative );
  267. }
  268. /**
  269. * Create an arc G code when found in polygon outlines.
  270. *
  271. * If multiquadrant == true : arc can be 0 to 360 degrees and \a rel_center is the center
  272. * coordinate relative to start point. If not multiquadrant, the arc can be only 0 to 90 deg,
  273. * and only in the same quadrant:
  274. *
  275. * <ul>
  276. * <li> absolute angle 0 to 90 (quadrant 1) or
  277. * <li> absolute angle 90 to 180 (quadrant 2) or
  278. * <li> absolute angle 180 to 270 (quadrant 3) or
  279. * <li> absolute angle 270 to 0 (quadrant 4)
  280. * </ul>
  281. *
  282. * @param aGbrItem is the GBRITEM to fill in.
  283. * @param aStart is the starting point.
  284. * @param aEnd is the ending point.
  285. * @param rel_center is the center coordinate relative to start point,
  286. * given in ABSOLUTE VALUE and the sign of values x et y de rel_center
  287. * must be calculated from the previously given constraint: arc only in the
  288. * same quadrant.
  289. * @param aClockwise true if arc must be created clockwise
  290. * @param aMultiquadrant set to true to create arcs up to 360 deg or
  291. * false when arc is inside one quadrant
  292. * @param aLayerNegative set to true if the current layer is negative
  293. */
  294. static void fillArcPOLY( GERBER_DRAW_ITEM* aGbrItem, const VECTOR2I& aStart, const VECTOR2I& aEnd,
  295. const VECTOR2I& rel_center, bool aClockwise, bool aMultiquadrant,
  296. bool aLayerNegative )
  297. {
  298. /* in order to calculate arc parameters, we use fillArcGBRITEM
  299. * so we muse create a dummy track and use its geometric parameters
  300. */
  301. static GERBER_DRAW_ITEM dummyGbrItem( nullptr );
  302. aGbrItem->SetLayerPolarity( aLayerNegative );
  303. fillArcGBRITEM( &dummyGbrItem, 0, aStart, aEnd, rel_center, wxSize( 0, 0 ),
  304. aClockwise, aMultiquadrant, aLayerNegative );
  305. aGbrItem->SetNetAttributes( aGbrItem->m_GerberImageFile->m_NetAttributeDict );
  306. VECTOR2I center;
  307. center = dummyGbrItem.m_ArcCentre;
  308. // Calculate coordinates relative to arc center;
  309. VECTOR2I start = dummyGbrItem.m_Start - center;
  310. VECTOR2I end = dummyGbrItem.m_End - center;
  311. /* Calculate angle arc
  312. * angle is trigonometrical (counter-clockwise),
  313. * and axis is the X,Y gerber coordinates
  314. */
  315. EDA_ANGLE start_angle( start );
  316. EDA_ANGLE end_angle( end );
  317. // dummyTrack has right geometric parameters, but
  318. // fillArcGBRITEM calculates arc parameters for a draw function that expects
  319. // start_angle < end_angle. So ensure this is the case here:
  320. // Due to the fact atan2 returns angles between -180 to + 180 degrees,
  321. // this is not always the case ( a modulo 360.0 degrees can be lost )
  322. //
  323. // Note also an arc with same start and end angle is a circle (360 deg arc)
  324. // in gerber files
  325. if( start_angle >= end_angle )
  326. end_angle += ANGLE_360;
  327. EDA_ANGLE arc_angle = start_angle - end_angle;
  328. // Approximate arc by 36 segments per 360 degree
  329. EDA_ANGLE increment_angle = ANGLE_360 / 36;
  330. int count = std::abs( arc_angle.AsDegrees() / increment_angle.AsDegrees() );
  331. if( aGbrItem->m_Polygon.OutlineCount() == 0 )
  332. aGbrItem->m_Polygon.NewOutline();
  333. // calculate polygon corners
  334. // when arc is counter-clockwise, dummyGbrItem arc goes from end to start
  335. // and we must always create a polygon from start to end.
  336. for( int ii = 0; ii <= count; ii++ )
  337. {
  338. EDA_ANGLE rot;
  339. VECTOR2I end_arc = start;
  340. if( aClockwise )
  341. rot = increment_angle * ii;
  342. else
  343. rot = increment_angle * ( count - ii );
  344. if( ii < count )
  345. RotatePoint( end_arc, -rot );
  346. else // last point
  347. end_arc = aClockwise ? end : start;
  348. aGbrItem->m_Polygon.Append( end_arc + center );
  349. }
  350. }
  351. int GERBER_FILE_IMAGE::CodeNumber( char*& aText )
  352. {
  353. int retval;
  354. char* endptr;
  355. errno = 0;
  356. retval = strtol( aText + 1, &endptr, 10 );
  357. if( endptr == aText || errno != 0 )
  358. return 0;
  359. wxCHECK_MSG( retval < std::numeric_limits<int>::max(), 0, _( "Invalid Code Number" ) );
  360. aText = endptr;
  361. return static_cast<int>( retval );
  362. }
  363. bool GERBER_FILE_IMAGE::Execute_G_Command( char*& text, int G_command )
  364. {
  365. switch( G_command )
  366. {
  367. case GC_PHOTO_MODE: // can starts a D03 flash command: redundant, can be safely ignored.
  368. break;
  369. case GC_LINEAR_INTERPOL_1X:
  370. m_Iterpolation = GERB_INTERPOL_LINEAR_1X;
  371. break;
  372. case GC_CIRCLE_NEG_INTERPOL:
  373. m_Iterpolation = GERB_INTERPOL_ARC_NEG;
  374. break;
  375. case GC_CIRCLE_POS_INTERPOL:
  376. m_Iterpolation = GERB_INTERPOL_ARC_POS;
  377. break;
  378. case GC_COMMENT:
  379. // Skip comment, but only if the line does not start by "G04 #@! "
  380. // which is a metadata, i.e. a X2 command inside the comment.
  381. // this comment is called a "structured comment"
  382. if( strncmp( text, " #@! ", 5 ) == 0 )
  383. {
  384. text += 5;
  385. // The string starting at text is the same as the X2 attribute,
  386. // but a X2 attribute ends by '%'. So we build the X2 attribute string
  387. std::string x2buf;
  388. while( *text && (*text != '*') )
  389. {
  390. x2buf += *text;
  391. text++;
  392. }
  393. // add the end of X2 attribute string
  394. x2buf += "*%";
  395. x2buf += '\0';
  396. char* cptr = (char*)x2buf.data();
  397. int code_command = ReadXCommandID( cptr );
  398. ExecuteRS274XCommand( code_command, nullptr, 0, cptr );
  399. }
  400. while( *text && (*text != '*') )
  401. text++;
  402. break;
  403. case GC_SELECT_TOOL:
  404. {
  405. int D_commande = CodeNumber( text );
  406. if( D_commande < FIRST_DCODE )
  407. return false;
  408. if( D_commande > (TOOLS_MAX_COUNT - 1) )
  409. D_commande = TOOLS_MAX_COUNT - 1;
  410. m_Current_Tool = D_commande;
  411. D_CODE* pt_Dcode = GetDCODE( D_commande );
  412. if( pt_Dcode )
  413. pt_Dcode->m_InUse = true;
  414. break;
  415. }
  416. case GC_SPECIFY_INCHES:
  417. m_GerbMetric = false; // false = Inches, true = metric
  418. break;
  419. case GC_SPECIFY_MILLIMETERS:
  420. m_GerbMetric = true; // false = Inches, true = metric
  421. break;
  422. case GC_TURN_OFF_360_INTERPOL: // disable Multi cadran arc and Arc interpol
  423. m_360Arc_enbl = false;
  424. m_Iterpolation = GERB_INTERPOL_LINEAR_1X; // not sure it should be done
  425. m_AsArcG74G75Cmd = true;
  426. break;
  427. case GC_TURN_ON_360_INTERPOL:
  428. m_360Arc_enbl = true;
  429. m_AsArcG74G75Cmd = true;
  430. break;
  431. case GC_SPECIFY_ABSOLUES_COORD:
  432. m_Relative = false; // false = absolute Coord, true = relative
  433. // Coord
  434. break;
  435. case GC_SPECIFY_RELATIVEES_COORD:
  436. m_Relative = true; // false = absolute Coord, true = relative
  437. // Coord
  438. break;
  439. case GC_TURN_ON_POLY_FILL:
  440. m_PolygonFillMode = true;
  441. m_Exposure = false;
  442. break;
  443. case GC_TURN_OFF_POLY_FILL:
  444. if( m_Exposure && GetLastItemInList() ) // End of polygon
  445. {
  446. GERBER_DRAW_ITEM * gbritem = GetLastItemInList();
  447. if( gbritem->m_Polygon.VertexCount() )
  448. gbritem->m_Polygon.Append( gbritem->m_Polygon.CVertex( 0 ) );
  449. StepAndRepeatItem( *gbritem );
  450. }
  451. m_Exposure = false;
  452. m_PolygonFillMode = false;
  453. m_PolygonFillModeState = 0;
  454. m_Iterpolation = GERB_INTERPOL_LINEAR_1X; // not sure it should be done
  455. break;
  456. case GC_MOVE: // Non existent
  457. default:
  458. {
  459. wxString msg;
  460. msg.Printf( wxT( "G%0.2d command not handled" ), G_command );
  461. AddMessageToList( msg );
  462. return false;
  463. }
  464. }
  465. return true;
  466. }
  467. bool GERBER_FILE_IMAGE::Execute_DCODE_Command( char*& text, int D_commande )
  468. {
  469. wxSize size( 15, 15 );
  470. APERTURE_T aperture = APT_CIRCLE;
  471. GERBER_DRAW_ITEM* gbritem;
  472. int dcode = 0;
  473. D_CODE* tool = nullptr;
  474. wxString msg;
  475. if( D_commande >= FIRST_DCODE ) // This is a "Set tool" command
  476. {
  477. if( D_commande > (TOOLS_MAX_COUNT - 1) )
  478. D_commande = TOOLS_MAX_COUNT - 1;
  479. // remember which tool is selected, nothing is done with it in this
  480. // call
  481. m_Current_Tool = D_commande;
  482. D_CODE* pt_Dcode = GetDCODE( D_commande );
  483. if( pt_Dcode )
  484. pt_Dcode->m_InUse = true;
  485. else
  486. m_Has_MissingDCode = true;
  487. return true;
  488. }
  489. else // D_commande = 0..9: this is a pen command (usually D1, D2 or D3)
  490. {
  491. m_Last_Pen_Command = D_commande;
  492. }
  493. if( m_PolygonFillMode ) // Enter a polygon description:
  494. {
  495. switch( D_commande )
  496. {
  497. case 1: // code D01 Draw line, exposure ON
  498. if( !m_Exposure ) // Start a new polygon outline:
  499. {
  500. m_Exposure = true;
  501. gbritem = new GERBER_DRAW_ITEM( this );
  502. AddItemToList( gbritem );
  503. gbritem->m_Shape = GBR_POLYGON;
  504. gbritem->m_Flashed = false;
  505. gbritem->m_DCode = 0; // No DCode for a Polygon (Region in Gerber dialect)
  506. if( gbritem->m_GerberImageFile )
  507. {
  508. gbritem->SetNetAttributes( gbritem->m_GerberImageFile->m_NetAttributeDict );
  509. gbritem->m_AperFunction = gbritem->m_GerberImageFile->m_AperFunction;
  510. }
  511. }
  512. switch( m_Iterpolation )
  513. {
  514. case GERB_INTERPOL_ARC_NEG:
  515. case GERB_INTERPOL_ARC_POS:
  516. // Before any arc command, a G74 or G75 command must be set.
  517. // Otherwise the Gerber file is invalid
  518. if( !m_AsArcG74G75Cmd )
  519. {
  520. AddMessageToList( _( "Invalid Gerber file: missing G74 or G75 arc command" ) );
  521. // Disable further warning messages:
  522. m_AsArcG74G75Cmd = true;
  523. }
  524. gbritem = GetLastItemInList();
  525. fillArcPOLY( gbritem, m_PreviousPos,
  526. m_CurrentPos, m_IJPos,
  527. ( m_Iterpolation == GERB_INTERPOL_ARC_NEG ) ? false : true,
  528. m_360Arc_enbl, GetLayerParams().m_LayerNegative );
  529. break;
  530. default:
  531. gbritem = GetLastItemInList();
  532. gbritem->m_Start = m_PreviousPos; // m_Start is used as temporary storage
  533. if( gbritem->m_Polygon.OutlineCount() == 0 )
  534. {
  535. gbritem->m_Polygon.NewOutline();
  536. gbritem->m_Polygon.Append( VECTOR2I( gbritem->m_Start ) );
  537. }
  538. gbritem->m_End = m_CurrentPos; // m_End is used as temporary storage
  539. gbritem->m_Polygon.Append( VECTOR2I( gbritem->m_End ) );
  540. break;
  541. }
  542. m_PreviousPos = m_CurrentPos;
  543. m_PolygonFillModeState = 1;
  544. break;
  545. case 2: // code D2: exposure OFF (i.e. "move to")
  546. if( m_Exposure && GetLastItemInList() ) // End of polygon
  547. {
  548. gbritem = GetLastItemInList();
  549. gbritem->m_Polygon.Append( gbritem->m_Polygon.CVertex( 0 ) );
  550. StepAndRepeatItem( *gbritem );
  551. }
  552. m_Exposure = false;
  553. m_PreviousPos = m_CurrentPos;
  554. m_PolygonFillModeState = 0;
  555. break;
  556. default:
  557. return false;
  558. }
  559. }
  560. else
  561. {
  562. switch( D_commande )
  563. {
  564. case 1: // code D01 Draw line, exposure ON
  565. m_Exposure = true;
  566. tool = GetDCODE( m_Current_Tool );
  567. if( tool )
  568. {
  569. size = tool->m_Size;
  570. dcode = tool->m_Num_Dcode;
  571. aperture = tool->m_Shape;
  572. }
  573. switch( m_Iterpolation )
  574. {
  575. case GERB_INTERPOL_LINEAR_1X:
  576. gbritem = new GERBER_DRAW_ITEM( this );
  577. AddItemToList( gbritem );
  578. fillLineGBRITEM( gbritem, dcode, m_PreviousPos,
  579. m_CurrentPos, size, GetLayerParams().m_LayerNegative );
  580. StepAndRepeatItem( *gbritem );
  581. break;
  582. case GERB_INTERPOL_ARC_NEG:
  583. case GERB_INTERPOL_ARC_POS:
  584. gbritem = new GERBER_DRAW_ITEM( this );
  585. AddItemToList( gbritem );
  586. if( m_LastCoordIsIJPos )
  587. {
  588. fillArcGBRITEM( gbritem, dcode, m_PreviousPos,
  589. m_CurrentPos, m_IJPos, size,
  590. ( m_Iterpolation == GERB_INTERPOL_ARC_NEG ) ?
  591. false : true, m_360Arc_enbl, GetLayerParams().m_LayerNegative );
  592. m_LastCoordIsIJPos = false;
  593. }
  594. else
  595. {
  596. fillLineGBRITEM( gbritem, dcode, m_PreviousPos,
  597. m_CurrentPos, size, GetLayerParams().m_LayerNegative );
  598. }
  599. StepAndRepeatItem( *gbritem );
  600. break;
  601. default:
  602. msg.Printf( wxT( "RS274D: DCODE Command: interpol error (type %X)" ),
  603. m_Iterpolation );
  604. AddMessageToList( msg );
  605. break;
  606. }
  607. m_PreviousPos = m_CurrentPos;
  608. break;
  609. case 2: // code D2: exposure OFF (i.e. "move to")
  610. m_Exposure = false;
  611. m_PreviousPos = m_CurrentPos;
  612. break;
  613. case 3: // code D3: flash aperture
  614. tool = GetDCODE( m_Current_Tool );
  615. if( tool )
  616. {
  617. size = tool->m_Size;
  618. dcode = tool->m_Num_Dcode;
  619. aperture = tool->m_Shape;
  620. }
  621. gbritem = new GERBER_DRAW_ITEM( this );
  622. AddItemToList( gbritem );
  623. fillFlashedGBRITEM( gbritem, aperture, dcode, m_CurrentPos,
  624. size, GetLayerParams().m_LayerNegative );
  625. StepAndRepeatItem( *gbritem );
  626. m_PreviousPos = m_CurrentPos;
  627. break;
  628. default:
  629. return false;
  630. }
  631. }
  632. return true;
  633. }