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.

386 lines
14 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 1992-2019 Jean-Pierre Charras jp.charras at wanadoo.fr
  5. * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. #include <gerbview.h>
  25. #include <gerbview_frame.h>
  26. #include <gerber_file_image.h>
  27. #include <macros.h>
  28. #include <X2_gerber_attributes.h>
  29. #include <algorithm>
  30. #include <map>
  31. #include <core/arraydim.h>
  32. /**
  33. * Function scaletoIU
  34. * converts a distance given in floating point to our internal units
  35. */
  36. extern int scaletoIU( double aCoord, bool isMetric ); // defined it rs274d_read_XY_and_IJ_coordinates.cpp
  37. /* Format Gerber: NOTES:
  38. * Tools and D_CODES
  39. * tool number (identification of shapes)
  40. * 1 to 999
  41. *
  42. * D_CODES:
  43. * D01 ... D9 = action codes:
  44. * D01 = activating light (lower pen) when di placement
  45. * D02 = light extinction (lift pen) when di placement
  46. * D03 Flash
  47. * D09 = VAPE Flash
  48. * D10 ... = Identification Tool (Opening)
  49. *
  50. * For tools:
  51. * DCode min = D10
  52. * DCode max = 999
  53. */
  54. GERBER_LAYER::GERBER_LAYER()
  55. {
  56. ResetDefaultValues();
  57. }
  58. GERBER_LAYER::~GERBER_LAYER()
  59. {
  60. }
  61. void GERBER_LAYER::ResetDefaultValues()
  62. {
  63. m_LayerName = wxT( "no name" ); // Layer name from the LN command
  64. m_LayerNegative = false; // true = Negative Layer
  65. m_StepForRepeat.x = m_StepForRepeat.y = 0; // X and Y offsets for Step and Repeat command
  66. m_XRepeatCount = 1; // The repeat count on X axis
  67. m_YRepeatCount = 1; // The repeat count on Y axis
  68. m_StepForRepeatMetric = false; // false = Inches, true = metric
  69. }
  70. GERBER_FILE_IMAGE::GERBER_FILE_IMAGE( int aLayer ) :
  71. EDA_ITEM( nullptr, GERBER_IMAGE_T )
  72. {
  73. m_GraphicLayer = aLayer; // Graphic layer Number
  74. m_PositiveDrawColor = WHITE; // The color used to draw positive items for this image
  75. m_Selected_Tool = 0;
  76. m_FileFunction = nullptr; // file function parameters
  77. ResetDefaultValues();
  78. for( unsigned ii = 0; ii < arrayDim( m_Aperture_List ); ii++ )
  79. m_Aperture_List[ii] = nullptr;
  80. }
  81. GERBER_FILE_IMAGE::~GERBER_FILE_IMAGE()
  82. {
  83. for( GERBER_DRAW_ITEM* item : GetItems() )
  84. delete item;
  85. m_drawings.clear();
  86. for( unsigned ii = 0; ii < arrayDim( m_Aperture_List ); ii++ )
  87. delete m_Aperture_List[ii];
  88. delete m_FileFunction;
  89. }
  90. D_CODE* GERBER_FILE_IMAGE::GetDCODEOrCreate( int aDCODE, bool aCreateIfNoExist )
  91. {
  92. unsigned ndx = aDCODE - FIRST_DCODE;
  93. if( ndx < (unsigned) arrayDim( m_Aperture_List ) )
  94. {
  95. // lazily create the D_CODE if it does not exist.
  96. if( aCreateIfNoExist )
  97. {
  98. if( m_Aperture_List[ndx] == nullptr )
  99. m_Aperture_List[ndx] = new D_CODE( ndx + FIRST_DCODE );
  100. }
  101. return m_Aperture_List[ndx];
  102. }
  103. return nullptr;
  104. }
  105. D_CODE* GERBER_FILE_IMAGE::GetDCODE( int aDCODE ) const
  106. {
  107. unsigned ndx = aDCODE - FIRST_DCODE;
  108. if( ndx < (unsigned) arrayDim( m_Aperture_List ) )
  109. return m_Aperture_List[ndx];
  110. return nullptr;
  111. }
  112. APERTURE_MACRO* GERBER_FILE_IMAGE::FindApertureMacro( const APERTURE_MACRO& aLookup )
  113. {
  114. APERTURE_MACRO_SET::iterator iter = m_aperture_macros.find( aLookup );
  115. if( iter != m_aperture_macros.end() )
  116. {
  117. APERTURE_MACRO* pam = (APERTURE_MACRO*) &(*iter);
  118. return pam;
  119. }
  120. return nullptr; // not found
  121. }
  122. void GERBER_FILE_IMAGE::ResetDefaultValues()
  123. {
  124. m_InUse = false;
  125. m_GBRLayerParams.ResetDefaultValues();
  126. m_FileName.Empty();
  127. m_ImageName = wxEmptyString; // Image name from the IN command (deprecated)
  128. m_ImageNegative = false; // true = Negative image
  129. m_IsX2_file = false; // true only if a %TF, %TA or %TD command
  130. delete m_FileFunction; // file function parameters
  131. m_FileFunction = nullptr;
  132. m_MD5_value.Empty(); // MD5 value found in a %TF.MD5 command
  133. m_PartString.Empty(); // string found in a %TF.Part command
  134. m_hasNegativeItems = -1; // set to uninitialized
  135. m_ImageJustifyOffset = VECTOR2I( 0, 0 ); // Image justify Offset
  136. m_ImageJustifyXCenter = false; // Image Justify Center on X axis (default = false)
  137. m_ImageJustifyYCenter = false; // Image Justify Center on Y axis (default = false)
  138. m_GerbMetric = false; // false = Inches (default), true = metric
  139. m_Relative = false; // false = absolute Coord,
  140. // true = relative Coord
  141. m_NoTrailingZeros = false; // true: trailing zeros deleted
  142. m_ImageOffset.x = m_ImageOffset.y = 0; // Coord Offset, from IO command
  143. m_ImageRotation = 0; // Allowed 0, 90, 180, 270 (in degree)
  144. m_LocalRotation = 0.0; // Layer rotation from RO command (in 0.1 degree)
  145. m_Offset.x = 0;
  146. m_Offset.y = 0; // Coord Offset, from OF command
  147. m_Scale.x = m_Scale.y = 1.0; // scale (A and B) this layer
  148. m_MirrorA = false; // true: mirror / axe A (default = X)
  149. m_MirrorB = false; // true: mirror / axe B (default = Y)
  150. m_SwapAxis = false; // false if A = X, B = Y; true if A =Y, B = Y
  151. m_Has_DCode = false; // true = DCodes in file
  152. // false = no DCode-> perhaps deprecated RS274D file
  153. m_Has_MissingDCode = false; // true = some D_Codes are used, but not defined
  154. // perhaps deprecated RS274D file
  155. m_FmtScale.x = m_FmtScale.y = 4; // Initialize default format to 3.4 => 4
  156. m_FmtLen.x = m_FmtLen.y = 3 + 4; // Initialize default format len = 3+4
  157. m_Iterpolation = GERB_INTERPOL_LINEAR_1X; // Linear, 90 arc, Circ.
  158. m_360Arc_enbl = true; // 360 deg circular mode (G75) selected as default
  159. // interpolation disable
  160. m_AsArcG74G75Cmd = false; // false until a G74 or G75 command is found
  161. m_Current_Tool = 0; // Current Dcode selected
  162. m_CommandState = 0; // State of the current command
  163. m_CurrentPos.x = m_CurrentPos.y = 0; // current specified coord
  164. m_PreviousPos.x = m_PreviousPos.y = 0; // last specified coord
  165. m_IJPos.x = m_IJPos.y = 0; // current centre coord for
  166. // plot arcs & circles
  167. m_LastCoordIsIJPos = false; // True only after a IJ coordinate is read
  168. m_ArcRadius = 0; // radius of arcs in circular interpol (given by A## command).
  169. // in command like X##Y##A##
  170. m_LastArcDataType = ARC_INFO_TYPE_NONE; // Extra coordinate info type for arcs
  171. // (radius or IJ center coord)
  172. m_LineNum = 0; // line number in file being read
  173. m_Current_File = nullptr; // Gerber file to read
  174. m_PolygonFillMode = false;
  175. m_PolygonFillModeState = 0;
  176. m_Selected_Tool = 0;
  177. m_Last_Pen_Command = 0;
  178. m_Exposure = false;
  179. }
  180. /* Function HasNegativeItems
  181. * return true if at least one item must be drawn in background color
  182. * used to optimize screen refresh
  183. */
  184. bool GERBER_FILE_IMAGE::HasNegativeItems()
  185. {
  186. if( m_hasNegativeItems < 0 ) // negative items are not yet searched: find them if any
  187. {
  188. if( m_ImageNegative ) // A negative layer is expected having always negative objects.
  189. {
  190. m_hasNegativeItems = 1;
  191. }
  192. else
  193. {
  194. m_hasNegativeItems = 0;
  195. for( GERBER_DRAW_ITEM* item : GetItems() )
  196. {
  197. if( item->GetLayer() != m_GraphicLayer )
  198. continue;
  199. if( item->HasNegativeItems() )
  200. {
  201. m_hasNegativeItems = 1;
  202. break;
  203. }
  204. }
  205. }
  206. }
  207. return m_hasNegativeItems == 1;
  208. }
  209. int GERBER_FILE_IMAGE::GetDcodesCount()
  210. {
  211. int count = 0;
  212. for( unsigned ii = 0; ii < arrayDim( m_Aperture_List ); ii++ )
  213. {
  214. if( m_Aperture_List[ii] )
  215. {
  216. if( m_Aperture_List[ii]->m_InUse || m_Aperture_List[ii]->m_Defined )
  217. ++count;
  218. }
  219. }
  220. return count;
  221. }
  222. /**
  223. * Function StepAndRepeatItem
  224. * Gerber format has a command Step an Repeat
  225. * This function must be called when reading a gerber file and
  226. * after creating a new gerber item that must be repeated
  227. * (i.e when m_XRepeatCount or m_YRepeatCount are > 1)
  228. * @param aItem = the item to repeat
  229. */
  230. void GERBER_FILE_IMAGE::StepAndRepeatItem( const GERBER_DRAW_ITEM& aItem )
  231. {
  232. if( GetLayerParams().m_XRepeatCount < 2 && GetLayerParams().m_YRepeatCount < 2 )
  233. return; // Nothing to repeat
  234. // Duplicate item:
  235. for( int ii = 0; ii < GetLayerParams().m_XRepeatCount; ii++ )
  236. {
  237. for( int jj = 0; jj < GetLayerParams().m_YRepeatCount; jj++ )
  238. {
  239. // the first gerber item already exists (this is the template)
  240. // create duplicate only if ii or jj > 0
  241. if( jj == 0 && ii == 0 )
  242. continue;
  243. GERBER_DRAW_ITEM* dupItem = new GERBER_DRAW_ITEM( aItem );
  244. VECTOR2I move_vector;
  245. move_vector.x = scaletoIU( ii * GetLayerParams().m_StepForRepeat.x,
  246. GetLayerParams().m_StepForRepeatMetric );
  247. move_vector.y = scaletoIU( jj * GetLayerParams().m_StepForRepeat.y,
  248. GetLayerParams().m_StepForRepeatMetric );
  249. dupItem->MoveXY( move_vector );
  250. AddItemToList( dupItem );
  251. }
  252. }
  253. }
  254. /**
  255. * Function DisplayImageInfo
  256. * has knowledge about the frame and how and where to put status information
  257. * about this object into the frame's message panel.
  258. * Display info about Image Parameters.
  259. * These parameters are valid for the entire file, and must set only once
  260. * (If more than once, only the last value is used)
  261. * Some are deprecated
  262. */
  263. void GERBER_FILE_IMAGE::DisplayImageInfo( GERBVIEW_FRAME* aMainFrame )
  264. {
  265. wxString msg;
  266. aMainFrame->ClearMsgPanel();
  267. // Display the Gerber variant (X1 / X2
  268. aMainFrame->AppendMsgPanel( _( "Format" ), m_IsX2_file ? wxT( "X2" ) : wxT( "X1" ) );
  269. // Display Image name (Image specific). IM command (Image Name) is deprecated
  270. // So non empty image name is very rare, probably never found
  271. if( !m_ImageName.IsEmpty() )
  272. aMainFrame->AppendMsgPanel( _( "Image name" ), m_ImageName );
  273. // Display graphic layer number used to draw this Image
  274. // (not a Gerber parameter but is also image specific)
  275. msg.Printf( wxT( "%d" ), m_GraphicLayer + 1 );
  276. aMainFrame->AppendMsgPanel( _( "Graphic layer" ), msg );
  277. // Display Image rotation (Image specific)
  278. msg.Printf( wxT( "%d" ), m_ImageRotation );
  279. aMainFrame->AppendMsgPanel( _( "Img Rot." ), msg );
  280. // Display Image polarity (Image specific)
  281. msg = m_ImageNegative ? _("Negative") : _("Normal");
  282. aMainFrame->AppendMsgPanel( _( "Polarity" ), msg );
  283. // Display Image justification and offset for justification (Image specific)
  284. msg = m_ImageJustifyXCenter ? _("Center") : _("Normal");
  285. aMainFrame->AppendMsgPanel( _( "X Justify" ), msg );
  286. msg = m_ImageJustifyYCenter ? _("Center") : _("Normal");
  287. aMainFrame->AppendMsgPanel( _( "Y Justify" ), msg );
  288. msg.Printf( wxT( "X=%s Y=%s" ),
  289. aMainFrame->MessageTextFromValue( m_ImageJustifyOffset.x ),
  290. aMainFrame->MessageTextFromValue( m_ImageJustifyOffset.y ) );
  291. aMainFrame->AppendMsgPanel( _( "Image Justify Offset" ), msg );
  292. }
  293. void GERBER_FILE_IMAGE::RemoveAttribute( X2_ATTRIBUTE& aAttribute )
  294. {
  295. /* Called when a %TD command is found
  296. * Remove the attribute specified by the %TD command.
  297. * is no attribute, all current attributes specified by the %TO and the %TA
  298. * commands are cleared.
  299. * if a attribute name is specified (for instance %TD.CN*%) is specified,
  300. * only this attribute is cleared
  301. */
  302. wxString cmd = aAttribute.GetPrm( 0 );
  303. m_NetAttributeDict.ClearAttribute( &cmd );
  304. if( cmd.IsEmpty() || cmd == wxT( ".AperFunction" ) )
  305. m_AperFunction.Clear();
  306. }
  307. INSPECT_RESULT GERBER_FILE_IMAGE::Visit( INSPECTOR inspector, void* testData,
  308. const std::vector<KICAD_T>& aScanTypes )
  309. {
  310. for( KICAD_T scanType : aScanTypes )
  311. {
  312. if( scanType == GERBER_DRAW_ITEM_T )
  313. {
  314. if( IterateForward( GetItems(), inspector, testData, { scanType } ) == INSPECT_RESULT::QUIT )
  315. return INSPECT_RESULT::QUIT;
  316. }
  317. }
  318. return INSPECT_RESULT::CONTINUE;
  319. }