/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2010-2019 Jean-Pierre Charras jp.charras at wanadoo.fr * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, you may find one here: * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * or you may search the http://www.gnu.org website for the version 2 license, * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef GERBER_FILE_IMAGE_H #define GERBER_FILE_IMAGE_H #include #include #include #include #include #include #include typedef std::vector GERBER_DRAW_ITEMS; class GERBVIEW_FRAME; class D_CODE; /* Gerber files have different parameters to define units and how items must be plotted. * some are for the entire file, and other can change along a file. * In Gerber world: * an image is the entire gerber file and its "global" parameters * a layer (that is very different from a board layer) is just a sub set of a file that * have specific parameters * if a Image parameter is set more than once, only the last value is used * Some parameters can change along a file and are not layer specific: they are stored * in GERBER_ITEM items, when instanced. * * In GerbView, to handle these parameters, there are 2 classes: * GERBER_FILE_IMAGE : the main class containing most of parameters and data to plot a * graphic layer * Some of them can change along the file * There is one GERBER_FILE_IMAGE per file and one graphic layer per file or GERBER_FILE_IMAGE * GerbView does not read and merge 2 gerber file in one graphic layer: * I believe this is not possible due to the constraints in Image parameters. * GERBER_LAYER : containing the subset of parameters that is layer specific * A GERBER_FILE_IMAGE must include one GERBER_LAYER to define all parameters to plot a file. * But a GERBER_FILE_IMAGE can use more than one GERBER_LAYER. */ class GERBER_FILE_IMAGE; class X2_ATTRIBUTE; class X2_ATTRIBUTE_FILEFUNCTION; // For arcs, coordinates need 3 info: start point, end point and center or radius // In Excellon files it can be a A## value (radius) or I#J# center coordinates (like in gerber) // We need to know the last read type when reading a list of routing coordinates enum LAST_EXTRA_ARC_DATA_TYPE { ARC_INFO_TYPE_NONE, ARC_INFO_TYPE_CENTER, // last info is a IJ command: arc center is given ARC_INFO_TYPE_RADIUS, // last info is a A command: arc radius is given }; class GERBER_LAYER { public: GERBER_LAYER(); ~GERBER_LAYER(); private: void ResetDefaultValues(); friend class GERBER_FILE_IMAGE; public: // These parameters are layer specific: wxString m_LayerName; // Layer name, from LN * command bool m_LayerNegative; // true = Negative Layer: command LP wxRealPoint m_StepForRepeat; // X and Y offsets for Step and Repeat command int m_XRepeatCount; // The repeat count on X axis int m_YRepeatCount; // The repeat count on Y axis bool m_StepForRepeatMetric; // false = Inches, true = metric // needed here because repeated // gerber items can have coordinates // in different units than step parameters // and the actual coordinates calculation must handle this }; // size of a single line of text from a gerber file. // warning: some files can have *very long* lines, so the buffer must be large. #define GERBER_BUFZ 1000000 /** * Hold the image data and parameters for one gerber file and layer parameters. * * @todo: Move them in #GERBER_LAYER class. */ class GERBER_FILE_IMAGE : public EDA_ITEM { public: GERBER_FILE_IMAGE( int layer ); virtual ~GERBER_FILE_IMAGE(); wxString GetClass() const override { return wxT( "GERBER_FILE_IMAGE" ); } /** * @brief Performs a heuristics-based check of whether the file is an RS274 gerber file. * * Does not invoke the full parser. * * @param aFullFileName aFullFileName is the full filename of the gerber file. * @return True if RS274 file, false otherwise */ static bool TestFileIsRS274( const wxString& aFullFileName ); /** * Read and load a gerber file. * * If the file cannot be loaded, warning and information messages are stored in m_messagesList. * * @param aFullFileName The full filename of the Gerber file. * @return true if file loaded successfully, false if the gerber file was not loaded. */ bool LoadGerberFile( const wxString& aFullFileName ); const wxArrayString& GetMessages() const { return m_messagesList; } /** * @return the count of Dcode tools in use in the image */ int GetDcodesCount(); /** * Set all parameters to a default value, before reading a file */ virtual void ResetDefaultValues(); COLOR4D GetPositiveDrawColor() const { return m_PositiveDrawColor; } /** * @return a reference to the GERBER_DRAW_ITEMS deque list */ GERBER_DRAW_ITEMS& GetItems() { return m_drawings; } /** * @return the count of GERBER_DRAW_ITEMS in the image */ int GetItemsCount() { return m_drawings.size(); } /** * Add a new GERBER_DRAW_ITEM item to the drawings list * * @param aItem is the GERBER_DRAW_ITEM to add to list */ void AddItemToList( GERBER_DRAW_ITEM* aItem ) { m_drawings.push_back( aItem ); } /** * @return the last GERBER_DRAW_ITEM* item of the items list */ GERBER_DRAW_ITEM* GetLastItemInList() const { return m_drawings.back(); } /** * @return the current layers params. */ GERBER_LAYER& GetLayerParams() { return m_GBRLayerParams; } /** * @return true if at least one item must be drawn in background color used to optimize * screen refresh (when no items are in background color refresh can be faster). */ bool HasNegativeItems(); /** * Clear the message list. * * Call it before reading a Gerber file */ void ClearMessageList() { m_messagesList.Clear(); } /** * Add a message to the message list */ void AddMessageToList( const wxString& aMessage ) { m_messagesList.Add( aMessage ); } /** * Return the current coordinate type pointed to by XnnYnn Text (XnnnnYmmmm). * * @param aText is a pointer to the text to parse. * @param aExcellonMode = true to parse a Excellon drill file. * it forces truncation of a digit string to a maximum length because the exact coordinate * format is not always known. */ VECTOR2I ReadXYCoord( char*& aText, bool aExcellonMode = false ); /** * Return the current coordinate type pointed to by InnJnn Text (InnnnJmmmm) * * These coordinates are relative, so if coordinate is absent, its value * defaults to 0 */ VECTOR2I ReadIJCoord( char*& Text ); /** * Reads the next number and returns the value * @param aText Pointer to the input string vector * @return */ int CodeNumber( char*& aText ); /** * Return a pointer to the D_CODE within this GERBER for the given \a aDCODE. * * @param aDCODE The numeric value of the D_CODE to look up. * @param aCreateIfNoExist If true, then create the D_CODE if it does not * exist in list. * @return The one implied by the given \a aDCODE or NULL if the requested \a aDCODE is * out of range. */ D_CODE* GetDCODEOrCreate( int aDCODE, bool aCreateIfNoExist = true ); /** * Return a pointer to the D_CODE within this GERBER for the given \a aDCODE. * * @param aDCODE The numeric value of the D_CODE to look up. * @return The D code implied by the given \a aDCODE or NULL if the requested \a aDCODE is * out of range. */ D_CODE* GetDCODE( int aDCODE ) const; /** * Look up a previously read in aperture macro. * * @param aLookup A dummy APERTURE_MACRO with [only] the name field set. * @return the aperture macro with a matching name or NULL if not found. */ APERTURE_MACRO* FindApertureMacro( const APERTURE_MACRO& aLookup ); /** * Gerber format has a command Step an Repeat. * * This function must be called when reading a gerber file and * after creating a new gerber item that must be repeated * (i.e when m_XRepeatCount or m_YRepeatCount are > 1) * * @param aItem = the item to repeat */ void StepAndRepeatItem( const GERBER_DRAW_ITEM& aItem ); /** * Display information about image parameters in the status bar. * * @param aMainFrame The #GERBVIEW_FRAME to display messages. */ void DisplayImageInfo( GERBVIEW_FRAME* aMainFrame ); /** * Set the offset and rotation to draw a file image * Does not change any coordinate od draw items * @param aOffsetMM is the draw offset in millimeters * @param aRotation is the draw roation * draw transform order is rotation and after offset */ void SetDrawOffetAndRotation( VECTOR2D aOffsetMM, EDA_ANGLE aRotation ); /** * Called when a %TD command is found the Gerber file * * Remove the attribute specified by the %TD command. * is no attribute, all current attributes specified by the %TO and the %TA * commands are cleared. * if a attribute name is specified (for instance %TD.CN*%) is specified, * only this attribute is cleared * * @param aAttribute is the X2_ATTRIBUTE which stores the full command */ void RemoveAttribute( X2_ATTRIBUTE& aAttribute ); ///< @copydoc EDA_ITEM::Visit() INSPECT_RESULT Visit( INSPECTOR inspector, void* testData, const std::vector& aScanTypes ) override; #if defined(DEBUG) void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); } #endif private: /** * Test for an end of line. * * If a end of line is found, read a new line. * * @param aBuff = buffer (size = GERBER_BUFZ) to fill with a new line * @param aText = pointer to the last useful char in aBuff * on return: points the beginning of the next line. * @param aBuffSize = the size in bytes of aBuff * @param aFile = the opened GERBER file to read * @return a pointer to the beginning of the next line or NULL if end of file */ char* GetNextLine( char *aBuff, unsigned int aBuffSize, char* aText, FILE* aFile ); bool GetEndOfBlock( char* aBuff, unsigned int aBuffSize, char*& aText, FILE* aGerberFile ); /** * Read a single RS274X command terminated with a % */ bool ReadRS274XCommand( char *aBuff, unsigned int aBuffSize, char*& aText ); /** * Execute a RS274X command */ bool ExecuteRS274XCommand( int aCommand, char* aBuff, unsigned int aBuffSize, char*& aText ); /** * Read two bytes of data and assembles them into an int with the first * byte in the sequence put into the most significant part of a 16 bit value * to build a RS274X command identifier. * * @param text A reference to a pointer to read bytes from and to advance as * they are read. * @return a RS274X command identifier. */ int ReadXCommandID( char*& text ); /** * Read in an aperture macro and saves it in m_aperture_macros. * * @param aBuff a character buffer at least GERBER_BUFZ long that can be * used to read successive lines from the gerber file. * @param text A reference to a character pointer which gives the initial * text to read from. * @param aBuffSize is the size of aBuff * @param gerber_file Which file to read from for continuation. * @return true if a macro was read in successfully, else false. */ bool ReadApertureMacro( char *aBuff, unsigned int aBuffSize, char*& text, FILE* gerber_file ); // functions to execute G commands or D basic commands: bool Execute_G_Command( char*& text, int G_command ); bool Execute_DCODE_Command( char*& text, int D_command ); public: bool m_InUse; ///< true if this image is currently in use (a file ///< is loaded in it) ///< false if it must be not drawn COLOR4D m_PositiveDrawColor; ///< The color used to draw positive items wxString m_FileName; ///< Full File Name for this layer wxString m_ImageName; ///< Image name, from IN * command bool m_IsX2_file; ///< True if a X2 gerber attribute was found in file X2_ATTRIBUTE_FILEFUNCTION* m_FileFunction; ///< file function parameters, found in a %TF ///< command or a G04 wxString m_MD5_value; ///< MD5 value found in a %TF.MD5 command wxString m_PartString; ///< string found in a %TF.Part command int m_GraphicLayer; ///< Graphic layer Number bool m_ImageNegative; ///< true = Negative image bool m_ImageJustifyXCenter; ///< Image Justify Center on X axis (default = false) bool m_ImageJustifyYCenter; ///< Image Justify Center on Y axis (default = false) VECTOR2I m_ImageJustifyOffset; ///< Image Justify Offset on XY axis (default = 0,0) bool m_GerbMetric; ///< false = Inches, true = metric bool m_Relative; ///< false = absolute Coord, true = relative Coord. bool m_NoTrailingZeros; ///< true: remove tailing zeros. VECTOR2I m_ImageOffset; ///< Coord Offset, from IO command wxSize m_FmtScale; ///< Fmt 2.3: m_FmtScale = 3, fmt 3.4: m_FmtScale = 4 wxSize m_FmtLen; ///< Nb chars per coord. ex fmt 2.3, m_FmtLen = 5 int m_ImageRotation; ///< Image rotation (0, 90, 180, 270 only) in degrees double m_LocalRotation; ///< Local rotation added to m_ImageRotation ///< @note This value is stored in 0.1 degrees VECTOR2I m_Offset; ///< Coord Offset, from OF command VECTOR2I m_Scale; ///< scale (X and Y) of layer. bool m_SwapAxis; ///< false if A = X and B = Y (default); true if ///< A = Y, B = X bool m_MirrorA; ///< true: mirror / axis A (X) bool m_MirrorB; ///< true: mirror / axis B (Y) int m_Iterpolation; ///< Linear, 90 arc, Circ. int m_Current_Tool; ///< Current Tool (Dcode) number selected int m_Last_Pen_Command; ///< Current or last pen state (0..9, set by Dn ///< option with n < 10 int m_CommandState; ///< state of gerber analysis command int m_LineNum; ///< Line number of the gerber file while reading. VECTOR2I m_CurrentPos; ///< current specified coord for plot VECTOR2I m_PreviousPos; ///< old current specified coord for plot VECTOR2I m_IJPos; ///< IJ coord (for arcs & circles ) ///< True if a IJ coord was read (for arcs & circles ). bool m_LastCoordIsIJPos; ///< A value ( = radius in circular routing in Excellon files ). int m_ArcRadius; ///< Identifier for arc data type (IJ (center) or A## (radius)). LAST_EXTRA_ARC_DATA_TYPE m_LastArcDataType; FILE* m_Current_File; // Current file to read int m_Selected_Tool; // For highlight: current selected Dcode ///< True if has DCodes in file or false if no DCodes found. Perhaps deprecated RS274D file. bool m_Has_DCode; // true = some DCodes in file are not defined (broken file or deprecated RS274D file). bool m_Has_MissingDCode; bool m_360Arc_enbl; // Enable 360 deg circular interpolation // Set to true when a circular interpolation command type is found. Mandatory before // drawing an arc. bool m_AsArcG74G75Cmd; // Enable polygon mode (read coord as a polygon descr) bool m_PolygonFillMode; // In polygon mode: 0 = first segm, 1 = next segm int m_PolygonFillModeState; ///< a collection of APERTURE_MACROS, sorted by name APERTURE_MACRO_SET m_aperture_macros; // the net attributes set by a %TO.CN, %TO.C and/or %TO.N add object attribute command. GBR_NETLIST_METADATA m_NetAttributeDict; // the aperture function set by a %TA.AperFunction, xxx (stores the xxx value). wxString m_AperFunction; std::map m_ComponentsList; // list of components std::map m_NetnamesList; // list of net names ///< Dcode (Aperture) List for this layer (max TOOLS_MAX_COUNT: see dcode.h) D_CODE* m_Aperture_List[TOOLS_MAX_COUNT]; ///< Whether an aperture macro tool is flashed on or off. bool m_Exposure; GERBER_LAYER m_GBRLayerParams; // hold params for the current gerber layer GERBER_DRAW_ITEMS m_drawings; // linked list of Gerber Items to draw ///< Parameters used only to draw (display) items on this layer. ///< Do not change actual coordinates/orientation VECTOR2I m_DisplayOffset; EDA_ANGLE m_DisplayRotation; // A large buffer to store one line static char m_LineBuffer[GERBER_BUFZ+1]; private: wxArrayString m_messagesList; // A list of messages created when reading a file /** * True if the image is negative or has some negative items. * * Used to optimize drawing because when there are no negative items screen refresh does * not need to build an intermediate bitmap specific to this image. * * - -1 negative items are. * - 0 no negative items found. * - 1 have negative items found. */ int m_hasNegativeItems; }; #endif // ifndef GERBER_FILE_IMAGE_H