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.

760 lines
24 KiB

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