/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2014 Cirilo Bernardo * * 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 */ /* * NOTE: * * Rules to ensure friendly use within a DLL: * * 1. all functions which throw exceptions must not be publicly available; * they must become FRIEND functions instead. * * 2. All objects with PRIVATE functions which throw exceptions when * invoked by a PUBLIC function must indicate success or failure * and make the exception information available via a GetError() * routine. * * General notes: * * 1. Due to the complexity of objects and the risk of accumulated * position errors, CAD packages should only delete or add complete * components. If a component being added already exists, it is * replaced by the new component IF and only if the CAD type is * permitted to make such changes. * * 2. Internally all units shall be in mm and by default we shall * write files with mm units. The internal flags mm/thou shall only * be used to translate data being read from or written to files. * This avoids the painful management of a mixture of mm and thou. * The API shall require all dimensions in mm; for people using any * other unit, it is their responsibility to perform the conversion * to mm. Conversion back to thou may incur small rounding errors. */ #ifndef IDF_PARSER_H #define IDF_PARSER_H #include class IDF3_COMPONENT; class IDF3_COMP_OUTLINE_DATA { friend class IDF3_BOARD; friend class IDF3_COMPONENT; private: double xoff; // X offset from KiCad or X placement from IDF file double yoff; // Y offset from KiCad or Y placement from IDF file double zoff; // height offset (specified in IDFv3 spec, corresponds to KiCad Z offset) double aoff; // angular offset from KiCad or Rotation Angle from IDF file std::string errormsg; IDF3_COMP_OUTLINE* outline; // component outline to use IDF3_COMPONENT* parent; // associated component #ifndef DISABLE_IDF_OWNERSHIP bool checkOwnership( int aSourceLine, const char* aSourceFunc ); #endif /** * Function readPlaceData * reads placement data from an open IDFv3 file * * @param aBoardFile is the open IDFv3 file * @param aBoardState is the internal status flag of the IDF parser * @param aIdfVersion is the version of the file currently being parsed * @param aBoard is the IDF3_BOARD object which will store the data * * @return bool: true if placement data was successfully read. false if * no placement data was read; this may happen if the end of the placement * data was encountered or an error occurred. if an error occurred then * an exception is thrown. */ bool readPlaceData( std::ifstream &aBoardFile, IDF3::FILE_STATE& aBoardState, IDF3_BOARD *aBoard, IDF3::IDF_VERSION aIdfVersion, bool aNoSubstituteOutlines ); /** * Function writePlaceData * writes RECORD 2 and RECORD 3 of a PLACEMENT section as per IDFv3 specification * * @param aBoardFile is the open IDFv3 file * @param aXpos is the X location of the parent component * @param aYpos is the Y location of the parent component * @param aAngle is the rotation of the parent component * @param aRefDes is the reference designator of the parent component * @param aPlacement is the IDF Placement Status of the parent component * @param aSide is the IDF Layer Designator (TOP or BOTTOM) * * @return bool: true if data was successfully written, otherwise false */ void writePlaceData( std::ofstream& aBoardFile, double aXpos, double aYpos, double aAngle, const std::string aRefDes, IDF3::IDF_PLACEMENT aPlacement, IDF3::IDF_LAYER aSide ); public: /** * Constructor * creates an object with default settings and no parent or associated outline */ IDF3_COMP_OUTLINE_DATA(); /** * Constructor * creates an object with default settings and the specified parent and associated outline * * @param aParent is the owning IDF3_COMPONENT object * @param aOutline is the outline for this placed component */ IDF3_COMP_OUTLINE_DATA( IDF3_COMPONENT* aParent, IDF3_COMP_OUTLINE* aOutline ); /** * Constructor * creates an object the specified parent and associated outline and the specified * data. * * @param aParent is the owning IDF3_COMPONENT object * @param aOutline is the outline for this placed component * @param aXoff is the X offset of this outline in relation to its parent * @param aYoff is the Y offset of this outline in relation to its parent * @param aZoff is the board offset of this outline as per IDFv3 specification * @param aAoff is the rotational offset of this outline in relation to its parent */ IDF3_COMP_OUTLINE_DATA( IDF3_COMPONENT* aParent, IDF3_COMP_OUTLINE* aOutline, double aXoff, double aYoff, double aZoff, double aAngleOff ); ~IDF3_COMP_OUTLINE_DATA(); /** * Function SetOffsets * sets the position and orientation of this outline item in relation to its parent * * @param aXoff is the X offset of this outline in relation to its parent * @param aYoff is the Y offset of this outline in relation to its parent * @param aZoff is the board offset of this outline as per IDFv3 specification * @param aAoff is the rotational offset of this outline in relation to its parent * * @return bool: true if the operation succeeded, false if an ownership * violation occurred */ bool SetOffsets( double aXoff, double aYoff, double aZoff, double aAngleOff ); /** * Function GetOffsets * retrieves the position and orientation of this outline item in relation to its parent * * @param aXoff is the X offset of this outline in relation to its parent * @param aYoff is the Y offset of this outline in relation to its parent * @param aZoff is the board offset of this outline as per IDFv3 specification * @param aAoff is the rotational offset of this outline in relation to its parent */ void GetOffsets( double& aXoff, double& aYoff, double& aZoff, double& aAngleOff ); /** * Function SetParent * sets the parent object * * @param aParent is the owning IDF3_COMPONENT object */ void SetParent( IDF3_COMPONENT* aParent ); /** * Function SetOutline * sets the outline whose position is managed by this object * * @param aOutline is the outline for this component * * @return bool: true if the operation succeeded, false if an ownership * violation occurred */ bool SetOutline( IDF3_COMP_OUTLINE* aOutline ); /** * Function GetOutline * retrieves the outline whose position is managed by this object * * @return IDF3_COMP_OUTLINE*: the outline for this component */ IDF3_COMP_OUTLINE* GetOutline( void ) { return outline; } const std::string& GetError( void ) { return errormsg; } }; class IDF3_COMPONENT { friend class IDF3_BOARD; private: std::list< IDF3_COMP_OUTLINE_DATA* > components; std::list< IDF_DRILL_DATA* > drills; double xpos; double ypos; double angle; IDF3::IDF_PLACEMENT placement; IDF3::IDF_LAYER layer; // [TOP/BOTTOM ONLY as per IDF spec] bool hasPosition; ///< True after SetPosition is called once std::string refdes; ///< Reference Description (MUST BE UNIQUE) IDF3_BOARD* parent; std::string errormsg; /** * Function WriteDrillData * writes the internal drill data to an IDFv3 .DRILLED_HOLES section * * @param aBoardFile is an IDFv3 file opened for writing * * @return bool: true if the operation succeeded, otherwise false */ bool writeDrillData( std::ofstream& aBoardFile ); /** * Function WritePlaceData * writes the component placement data to an IDFv3 .PLACEMENT section * * @param aBoardFile is an IDFv3 file opened for writing * * @return bool: true if the operation succeeded, otherwise false */ bool writePlaceData( std::ofstream& aBoardFile ); #ifndef DISABLE_IDF_OWNERSHIP bool checkOwnership( int aSourceLine, const char* aSourceFunc ); #endif public: /** * Constructor * sets the parent object and initializes other internal parameters to default values * * @param aParent is the owning IDF3_BOARD object */ IDF3_COMPONENT( IDF3_BOARD* aParent ); ~IDF3_COMPONENT(); /** * Function SetParent * sets the parent object * * @param aParent is the owning IDF3_BOARD object */ void SetParent( IDF3_BOARD* aParent ); /** * Function GetCadType * returns the type of CAD (IDF3::CAD_ELEC, IDF3::CAD_MECH) which instantiated this object * * @return IDF3::CAD_TYPE */ IDF3::CAD_TYPE GetCadType( void ); /** * Function GetCadType * returns the IDF UNIT type of the parent object or IDF3::UNIT_INVALID if * the parent was not set * * @return IDF3::IDF_UNIT */ IDF3::IDF_UNIT GetUnit( void ); /** * Function SetRefDes * sets the Reference Designator (RefDes) of this component; the RefDes is shared * by all outlines associated with this component. * * @return bool: true if the RefDes was accepted, otherwise false. Prohibited * values include empty strings and the word PANEL. */ bool SetRefDes( const std::string& aRefDes ); /** * Function GetRefDes * Retrieves the Reference Designator (RefDes) of this component * * @return string: the Reference Designator */ const std::string& GetRefDes( void ); /** * Function AddDrill * adds a drill entry to the component and returns its pointer * * @param aDia diameter of the drill (mm) * @param aXpos X position of the drill (mm) * @param aYpos Y position of the drill (mm) * @param aPlating plating type (PTH, NPTH) * @param aHoleType hole class (PIN, VIA, MTG, TOOL, etc) * @param aOwner owning CAD system (ECAD, MCAD, UNOWNED) * * @return pointer: a pointer to the newly created drill entry or NULL */ IDF_DRILL_DATA* AddDrill( double aDia, double aXpos, double aYpos, IDF3::KEY_PLATING aPlating, const std::string aHoleType, IDF3::KEY_OWNER aOwner ); /** * Function AddDrill * adds the given drill entry to the component and returns the pointer * to indicate success. A return value of NULL indicates that the item * was not added and it is the user's responsibility to delete the * object if necessary. * * @param aDrilledHole pointer to a drill entry * * @return pointer: aDrilledHole if the function succeeds, otherwise NULL */ IDF_DRILL_DATA* AddDrill( IDF_DRILL_DATA* aDrilledHole ); /** * Function DelDrill( double aDia, double aXpos, double aYpos ) * deletes a drill entry based on its size and location. This operation is * subject to IDF ownership rules. * * @param aDia diameter (mm) of the drilled hole to be deleted * @param aXpos X position (mm) of the hole to be deleted * @param aYpos X position (mm) of the hole to be deleted * * @return bool: true if a drill was found and deleted, otherwise false. * If an ownership violation occurs an exception is thrown. */ bool DelDrill( double aDia, double aXpos, double aYpos ); /** * Function DelDrill( IDF_DRILL_DATA* aDrill ) * deletes a drill entry based on pointer. This operation is * subject to IDF ownership rules. * * @param aDrill the pointer associated with the drill entry to be deleted * * @return bool: true if a drill was found and deleted, otherwise false. * If an ownership violation occurs an exception is thrown. */ bool DelDrill( IDF_DRILL_DATA* aDrill ); /** * Function GetDrills * returns a pointer to the internal list of drills. To avoid IDF * violations, the user should not alter these entries. */ const std::list< IDF_DRILL_DATA* >*const GetDrills( void ); /** * Function AddOutlineData * adds the given component outline data to this component * * @param aComponentOutline is a pointer to the outline data to be added * * @return true if the operation succeedes, otherwise false */ bool AddOutlineData( IDF3_COMP_OUTLINE_DATA* aComponentOutline ); /** * Function DeleteOutlineData( IDF3_COMP_OUTLINE_DATA* aComponentOutline ) * removes outline data based on the pointer provided. * * @param aComponentOutline is a pointer to be deleted from the internal list * * @return bool: true if the data was found and deleted, otherwise false */ bool DeleteOutlineData( IDF3_COMP_OUTLINE_DATA* aComponentOutline ); /** * Function DeleteOutlineData( size_t aIndex ) * removes outline data based on the provided index. * * @param aIndex is an index to the internal outline list * * @return bool: true if the data was deleted, false if the * index was out of bounds. */ bool DeleteOutlineData( size_t aIndex ); /** * Function GetOutlineSize * returns the number of outlines in the internal list */ size_t GetOutlinesSize( void ); /** * Function GetOutlinesData * returns a pointer to the internal list of outline data */ const std::list< IDF3_COMP_OUTLINE_DATA* >*const GetOutlinesData( void ); /** * Function GetPosition * retrieves the internal position parameters and returns true if the * position was previously set, otherwise false. */ bool GetPosition( double& aXpos, double& aYpos, double& aAngle, IDF3::IDF_LAYER& aLayer ); // NOTE: it may be possible to extend this so that internal drills and outlines // are moved when the component is moved. However there is always a danger of // position creep due to the relative position updates. /** * Function SetPosition * sets the internal position parameters and returns true if the * position was set, false if the position was previously set. This object * does not allow modification of the position once it is set since this may * adversely affect the relationship with its internal objects. * * @param aXpos is the X position (mm) of the component * @param aYpos is the Y position (mm) of the component * @param aAngle is the rotation of the component (degrees) * @param aLayer is the layer on which the component is places (TOP, BOTTOM) * * @return bool: true if the position was set, otherwise false */ bool SetPosition( double aXpos, double aYpos, double aAngle, IDF3::IDF_LAYER aLayer ); /** * Function GetPlacement * returns the IDF placement value of this component (UNPLACED, PLACED, ECAD, MCAD) */ IDF3::IDF_PLACEMENT GetPlacement( void ); /** * Function SetPlacement * sets the placement value of the component subject to ownership rules. * An exception is thrown if aPlacementValue is invalid or an ownership * violation occurs. * * @return bool: true if the operation succeeded, otherwise false and the * error message is set. */ bool SetPlacement( IDF3::IDF_PLACEMENT aPlacementValue ); const std::string& GetError( void ) { return errormsg; } }; class IDF3_BOARD { private: std::map< std::string, std::string > uidFileList; // map of files opened and UIDs std::list< std::string > uidLibList; // list of UIDs read from a library file std::string errormsg; // string for passing error messages to user std::list< IDF_NOTE* > notes; // IDF notes std::list< std::string > noteComments; // comment list for NOTES section std::list< std::string > drillComments; // comment list for DRILL section std::list< std::string > placeComments; // comment list for PLACEMENT section std::list board_drills; std::map< std::string, IDF3_COMPONENT*> components; // drill and placement data for components std::map< std::string, IDF3_COMP_OUTLINE*> compOutlines; // component outlines (data for library file) std::string boardName; IDF3::FILE_STATE state; IDF3::CAD_TYPE cadType; IDF3::IDF_UNIT unit; IDF3::IDF_VERSION idfVer; // IDF version of Board or Library int iRefDes; // counter for automatically numbered NOREFDES items std::string sRefDes; std::string idfSource; // SOURCE string to use when writing BOARD and LIBRARY headers std::string brdSource; // SOURCE string as retrieved from a BOARD file std::string libSource; // SOURCE string as retrieved from a LIBRARY file std::string brdDate; // DATE string from BOARD file std::string libDate; // DATE string from LIBRARY file int brdFileVersion; // File Version from BOARD file int libFileVersion; // File Version from LIBRARY file int userPrec; // user may store any integer here double userScale; // user may store a scale for translating to arbitrary units double userXoff; // user may specify an arbitrary X/Y offset double userYoff; // main board outline and cutouts BOARD_OUTLINE olnBoard; // OTHER outlines std::map olnOther; // ROUTE outlines std::list olnRoute; // PLACEMENT outlines std::list olnPlace; // ROUTE KEEPOUT outlines std::list olnRouteKeepout; // VIA KEEPOUT outlines std::list olnViaKeepout; // PLACE KEEPOUT outlines std::list olnPlaceKeepout; // PLACEMENT GROUP outlines std::multimap olnGroup; // Set the unit; this can only be done internally upon // reading a file or saving bool setUnit( IDF3::IDF_UNIT aUnit, bool convert = false ); IDF_DRILL_DATA* addCompDrill( double aDia, double aXpos, double aYpos, IDF3::KEY_PLATING aPlating, const std::string aHoleType, IDF3::KEY_OWNER aOwner, const std::string& aRefDes ); IDF_DRILL_DATA* addCompDrill( IDF_DRILL_DATA* aDrilledHole ); bool delCompDrill( double aDia, double aXpos, double aYpos, std::string aRefDes ); // read the DRILLED HOLES section void readBrdDrills( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState ); // read the NOTES section void readBrdNotes( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState ); // read the component placement section void readBrdPlacement( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState, bool aNoSubstituteOutlines ); // read the board HEADER void readBrdHeader( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState ); // read individual board sections; pay attention to IDFv3 section specifications // exception thrown on unrecoverable errors. state flag set to FILE_PLACEMENT // upon reading the PLACEMENT file; according to IDFv3 this is the final section void readBrdSection( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState, bool aNoSubstituteOutlines ); // read the board file data void readBoardFile( const std::string& aFileName, bool aNoSubstituteOutlines ); // write the board file data void writeBoardFile( const std::string& aFileName ); // read the library sections (outlines) void readLibSection( std::ifstream& aLibFile, IDF3::FILE_STATE& aLibState, IDF3_BOARD* aBoard ); // read the library HEADER void readLibHeader( std::ifstream& aLibFile, IDF3::FILE_STATE& aLibState ); // read the library file data void readLibFile( const std::string& aFileName ); // write the library file data bool writeLibFile( const std::string& aFileName ); #ifndef DISABLE_IDF_OWNERSHIP bool checkComponentOwnership( int aSourceLine, const char* aSourceFunc, IDF3_COMPONENT* aComponent ); #endif public: IDF3_BOARD( IDF3::CAD_TYPE aCadType ); virtual ~IDF3_BOARD(); IDF3::CAD_TYPE GetCadType( void ); // retrieve the nominal unit used in reading/writing // data. This is primarily for use by owned objects // and is only of informational use for the end user. // Internally all data is represented in mm and the // end user must use only mm in the API. IDF3::IDF_UNIT GetUnit( void ); const std::string& GetNewRefDes( void ); void SetBoardName( std::string aBoardName ); const std::string& GetBoardName( void ); bool SetBoardThickness( double aBoardThickness ); double GetBoardThickness( void ); bool ReadFile( const wxString& aFullFileName, bool aNoSubstituteOutlines = false ); bool WriteFile( const wxString& aFullFileName, bool aUnitMM = true, bool aForceUnitFlag = false ); const std::string& GetIDFSource( void ); void SetIDFSource( const std::string& aIDFSource); const std::string& GetBoardSource( void ); const std::string& GetLibrarySource( void ); const std::string& GetBoardDate( void ); const std::string& GetLibraryDate( void ); int GetBoardVersion( void ); bool SetBoardVersion( int aVersion ); int GetLibraryVersion( void ); bool SetLibraryVersion( int aVersion ); double GetUserScale( void ); bool SetUserScale( double aScaleFactor ); int GetUserPrecision( void ); bool SetUserPrecision( int aPrecision ); void GetUserOffset( double& aXoff, double& aYoff ); void SetUserOffset( double aXoff, double aYoff ); bool AddBoardOutline( IDF_OUTLINE* aOutline ); bool DelBoardOutline( IDF_OUTLINE* aOutline ); bool DelBoardOutline( size_t aIndex ); size_t GetBoardOutlinesSize( void ); BOARD_OUTLINE* GetBoardOutline( void ); const std::list< IDF_OUTLINE* >*const GetBoardOutlines( void ); // Operations for OTHER OUTLINES const std::map*const GetOtherOutlines( void ); /// XXX - TO BE IMPLEMENTED // // SetBoardOutlineOwner() // // AddDrillComment // AddPlacementComment // GetDrillComments() // GetPlacementComments() // ClearDrillComments() // ClearPlacementComments() // AddNoteComment // GetNoteComments // AddNote // // [IMPLEMENTED] const std::map*const GetOtherOutlines( void ) // size_t GetOtherOutlinesSize() // OTHER_OUTLINE* AddOtherOutline( OTHER_OUTLINE* aOtherOutline ) // bool DelOtherOutline( int aIndex ) // bool DelOtherOutline( OTHER_OUTLINE* aOtherOutline ) // // const std::list*const GetRouteOutlines() // size_t GetRouteOutlinesSize() // ROUTE_OUTLINE* AddRouteOutline( ROUTE_OUTLINE* aRouteOutline ) // bool DelRouteOutline( int aIndex ) // bool DelRouteOutline( ROUTE_OUTLINE* aRouteOutline ) // // const std::list*const GetPlacementOutlines() // size_t GetPlacementOutlinesSize() // PLACE_OUTLINE* AddPlacementOutline( PLACE_OUTLINE* aPlaceOutline ) // bool DelPlacementOutline( int aIndex ) // bool DelPlacementOutline( PLACE_OUTLINE* aPlaceOutline ) // // const std::list*const GetRouteKeepOutOutlines() // size_t GetRouteKeepOutOutlinesSize() // ROUTE_KO_OUTLINE* AddRouteKeepoutOutline( ROUTE_KO_OUTLINE* aRouteKeepOut ) // bool DelRouteKeepOutOutline( int aIndex ) // bool DelRouteKeepOutOutline( ROUTE_KO_OUTLINE* aRouteKeepOut ) // // const std::list*const GetViaKeepOutOutlines() // size_t GetViaKeepOutOutlinesSize() // VIA_KO_OUTLINE* AddViaKeepoutOutline( VIA_KO_OUTLINE* aViaKeepOut ) // bool DelViaKeepOutOutline( int aIndex ) // bool DelViaKeepOutOutline( VIA_KO_OUTLINE* aViaKeepOut ) // // const std::list*const GetPlacementKeepOutOutlines() // size_t GetPlacementKeepOutOutlinesSize() // PLACE_KO_OUTLINE* AddPlacementKeepoutOutline( PLACE_KO_OUTLINE* aPlaceKeepOut ) // bool DelPlacementKeepOutOutline( int aIndex ) // bool DelPlacementKeepOutOutline( PLACE_KO_OUTLINE* aPlaceKeepOut ) // // const std::multimap*const GetGroupOutlines() // size_t GetGroupOutlinesSize() // GROUP_OUTLINE* AddGroupOutline( GROUP_OUTLINE* aGroupOutline ) // bool DelGroupOutline( int aIndex ) // bool DelGroupOutline( GROUP_OUTLINE* aGroupOutline ) std::list& GetBoardDrills( void ) { return board_drills; } IDF_DRILL_DATA* AddBoardDrill( double aDia, double aXpos, double aYpos, IDF3::KEY_PLATING aPlating, const std::string aHoleType, IDF3::KEY_OWNER aOwner ); IDF_DRILL_DATA* AddDrill( IDF_DRILL_DATA* aDrilledHole ); bool DelBoardDrill( double aDia, double aXpos, double aYpos ); // a slot is a deficient representation of a kicad slotted hole; // it is usually associated with a component but IDFv3 does not // provide for such an association. bool AddSlot( double aWidth, double aLength, double aOrientation, double aX, double aY ); bool AddComponent( IDF3_COMPONENT* aComponent ); bool DelComponent( IDF3_COMPONENT* aComponent ); bool DelComponent( size_t aIndex ); size_t GetComponentsSize( void ); std::map< std::string, IDF3_COMPONENT* >*const GetComponents( void ); IDF3_COMPONENT* FindComponent( std::string aRefDes ); // returns a pointer to a component outline object or NULL // if the object doesn't exist IDF3_COMP_OUTLINE* GetComponentOutline( wxString aFullFileName ); // returns a pointer to the component outline object with the // unique ID aComponentID IDF3_COMP_OUTLINE* GetComponentOutline( std::string aComponentID ); // returns a pointer to the outline "NOGEOM NOPART" which is substituted // whenever a true outline cannot be found or is defective IDF3_COMP_OUTLINE* GetInvalidOutline( const std::string& aGeomName, const std::string& aPartName ); // clears all data void Clear( void ); // return error string const std::string& GetError( void ) { return errormsg; } }; #endif // IDF_PARSER_H