diff --git a/pcbnew/cadstar2kicadpcb_plugin/cadstar_common.cpp b/pcbnew/cadstar2kicadpcb_plugin/cadstar_common.cpp index 347997688e..74a4d903fc 100644 --- a/pcbnew/cadstar2kicadpcb_plugin/cadstar_common.cpp +++ b/pcbnew/cadstar2kicadpcb_plugin/cadstar_common.cpp @@ -38,6 +38,15 @@ void CADSTAR_COMMON::EVALUE::Parse( XNODE* aNode ) } +void CADSTAR_COMMON::POINT::Parse( XNODE* aNode ) +{ + wxASSERT( aNode->GetName() == wxT( "PT" ) ); + + X = CADSTAR_COMMON::GetAttributeIDLong( aNode, 0 ); + Y = CADSTAR_COMMON::GetAttributeIDLong( aNode, 1 ); +} + + double CADSTAR_COMMON::EVALUE::GetDouble() { return Base * std::pow( 10.0, Exponent ); @@ -132,11 +141,8 @@ XNODE* CADSTAR_COMMON::LoadArchiveFile( const wxString& aFileName, FILE_TYPE aTy else if( iNode ) { str = wxString( lexer.CurText(), *conv ); - - if( !str.IsEmpty() ) - { - InsertAttributeAtEnd( iNode, str ); - } + //Insert even if string is empty + InsertAttributeAtEnd( iNode, str ); } else { @@ -217,3 +223,31 @@ void CADSTAR_COMMON::ParseChildEValue( XNODE* aNode, CADSTAR_COMMON::EVALUE& aVa THROW_UNKNOWN_NODE_IO_ERROR( aNode->GetChildren()->GetName(), aNode->GetName() ); } } + +std::vector CADSTAR_COMMON::ParseAllChildPoints( + XNODE* aNode, bool aTestAllChildNodes, int aExpectedNumPoints ) +{ + std::vector retVal; + + XNODE* cNode = aNode->GetChildren(); + + for( ; cNode; cNode = cNode->GetNext() ) + { + if( cNode->GetName() == wxT( "PT" ) ) + { + POINT pt; + //TODO try.. catch + throw again with more detailed error information + pt.Parse( cNode ); + retVal.push_back( pt ); + } + else if( aTestAllChildNodes ) + THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), aNode->GetName() ); + } + + if( aExpectedNumPoints >= 0 && retVal.size() != aExpectedNumPoints ) + THROW_IO_ERROR( wxString::Format( + _( "Unexpected number of points in '%s'. Found %d but expected %d." ), + aNode->GetName(), retVal.size(), aExpectedNumPoints ) ); + + return retVal; +} diff --git a/pcbnew/cadstar2kicadpcb_plugin/cadstar_common.h b/pcbnew/cadstar2kicadpcb_plugin/cadstar_common.h index 3ef98565f8..49c701513c 100644 --- a/pcbnew/cadstar2kicadpcb_plugin/cadstar_common.h +++ b/pcbnew/cadstar2kicadpcb_plugin/cadstar_common.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -72,6 +73,18 @@ struct EVALUE double GetDouble(); }; +/** + * @brief Represents a point in x,y coordinates +*/ +struct POINT +{ + long X; + long Y; + + void Parse( XNODE* aNode ); +}; + + extern void InsertAttributeAtEnd( XNODE* aNode, wxString aValue ); /** @@ -79,8 +92,8 @@ extern void InsertAttributeAtEnd( XNODE* aNode, wxString aValue ); * @param aFileName * @param aType * @return XNODE pointing to the top of the tree for further parsing. Each node has the first - element as the node's name and subsequent elements as node attributes ("attr0", - "attr1", "attr2", etc.). Caller is responsible for deleting to avoid memory leaks. + * element as the node's name and subsequent elements as node attributes ("attr0", + * "attr1", "attr2", etc.). Caller is responsible for deleting to avoid memory leaks. * @throws IO_ERROR */ extern XNODE* LoadArchiveFile( @@ -128,9 +141,23 @@ extern void CheckNoNextNodes( XNODE* aNode ); * @param aNode with a child node containing an EVALUE * @param aValueToParse * @throw IO_ERROR if unable to parse or node is not an EVALUE -*/ + */ extern void ParseChildEValue( XNODE* aNode, EVALUE& aValueToParse ); +/** + * @brief if no childs are present, it just returns an empty + * vector (without throwing an exception) + * @param aNode containing a series of POINT objects + * @param aTestAllChildNodes + * @param aExpectedNumPoints if -1, this is check is disabled + * @return std::vector containing all POINT objects + * @throw IO_ERROR if one of the following: + * - Unable to parse a POINT object + * - aTestAllChildNodes is true and one of the child nodes is not a valid POINT object + * - aExpectedNumPoints is non-negative and the number of POINT objects found is different + */ +extern std::vector ParseAllChildPoints( + XNODE* aNode, bool aTestAllChildNodes = true, int aExpectedNumPoints = -1 ); } // namespace CADSTAR_COMMON diff --git a/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_parser.cpp b/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_parser.cpp index 28dd23c714..23d940afdc 100644 --- a/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_parser.cpp +++ b/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_parser.cpp @@ -32,48 +32,32 @@ void CPA_FILE::Parse() XNODE* fileRootNode = CADSTAR_COMMON::LoadArchiveFile( Filename, CADSTAR_COMMON::FILE_TYPE::PCB_ARCHIVE ); - XNODE* tempNode = fileRootNode->GetChildren(); + XNODE* cNode = fileRootNode->GetChildren(); - for( ; tempNode && ( tempNode->GetName() != wxT( "HEADER" ) ); tempNode = tempNode->GetNext() ) - ; - - if( !tempNode ) + if( !cNode ) THROW_MISSING_NODE_IO_ERROR( wxT( "HEADER" ), wxT( "CADSTARPCB" ) ); - //TODO try.. catch + throw again with more detailed error information - Header.Parse( tempNode ); - - switch( Header.Resolution ) + for( ; cNode; cNode = cNode->GetNext() ) { - case CPA_RESOLUTION::HUNDREDTH_MICRON: - KiCadUnitMultiplier = 10; - break; - - default: - wxASSERT_MSG( true, wxT( "Unknown File Resolution" ) ); - break; - } - - for( ; tempNode && ( tempNode->GetName() != wxT( "ASSIGNMENTS" ) ); - tempNode = tempNode->GetNext() ) - ; - - if( !tempNode ) - THROW_MISSING_NODE_IO_ERROR( wxT( "ASSIGNMENTS" ), wxT( "CADSTARPCB" ) ); - - tempNode = tempNode->GetChildren(); - - if( !tempNode ) - THROW_MISSING_NODE_IO_ERROR( wxT( "LAYERDEFS" ), wxT( "ASSIGNMENTS" ) ); - - for( ; tempNode; tempNode = tempNode->GetNext() ) - { - if( tempNode->GetName() == wxT( "LAYERDEFS" ) ) + if( cNode->GetName() == wxT( "HEADER" ) ) + { //TODO try.. catch + throw again with more detailed error information - Assignments.Layerdefs.Parse( tempNode ); - else if( tempNode->GetName() == wxT( "CODEDEFS" ) ) - Assignments.Codedefs.Parse( tempNode ); - //TODO parse technology, grids,etc + Header.Parse( cNode ); + + switch( Header.Resolution ) + { + case CPA_RESOLUTION::HUNDREDTH_MICRON: + KiCadUnitMultiplier = 10; + break; + + default: + wxASSERT_MSG( true, wxT( "Unknown File Resolution" ) ); + break; + } + } + else if( cNode->GetName() == wxT( "ASSIGNMENTS" ) ) + Assignments.Parse( cNode ); + //TODO need to parse everything else! } @@ -85,8 +69,39 @@ void CPA_FILE::Parse() } //delete fileRootNode; +} - //TODO need to parse everything else! + +void CPA_ASSIGNMENTS::Parse( XNODE* aNode ) +{ + wxASSERT( aNode->GetName() == wxT( "ASSIGNMENTS" ) ); + + XNODE* cNode = aNode->GetChildren(); + + if( !cNode ) + THROW_MISSING_NODE_IO_ERROR( wxT( "TECHNOLOGY" ), wxT( "ASSIGNMENTS" ) ); + + for( ; cNode; cNode = cNode->GetNext() ) + { + if( cNode->GetName() == wxT( "LAYERDEFS" ) ) + //TODO try.. catch + throw again with more detailed error information + Layerdefs.Parse( cNode ); + else if( cNode->GetName() == wxT( "CODEDEFS" ) ) + //TODO try.. catch + throw again with more detailed error information + Codedefs.Parse( cNode ); + else if( cNode->GetName() == wxT( "TECHNOLOGY" ) ) + //TODO try.. catch + throw again with more detailed error information + Technology.Parse( cNode ); + else if( cNode->GetName() == wxT( "GRIDS" ) ) + //TODO try.. catch + throw again with more detailed error information + Grids.Parse( cNode ); + else if( cNode->GetName() == wxT( "NETCLASSEDITATTRIBSETTINGS" ) ) + NetclassEditAttributeSettings = true; + else if( cNode->GetName() == wxT( "SPCCLASSEDITATTRIBSETTINGS" ) ) + SpacingclassEditAttributeSettings = true; + else + THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), aNode->GetName() ); + } } @@ -1128,8 +1143,8 @@ void CPA_NETCLASS::Parse( XNODE* aNode ) if( cNodeName == wxT( "ATTR" ) ) { - //TODO try.. catch + throw again with more detailed error information CPA_ATTRIBUTE_VALUE attribute_val; + //TODO try.. catch + throw again with more detailed error information attribute_val.Parse( cNode ); Attributes.push_back( attribute_val ); } @@ -1158,3 +1173,162 @@ void CPA_SPCCLASSSPACE::Parse( XNODE* aNode ) LayerID = CADSTAR_COMMON::GetAttributeID( aNode, 2 ); Spacing = CADSTAR_COMMON::GetAttributeIDLong( aNode, 3 ); } + + +void CPA_TECHNOLOGY::Parse( XNODE* aNode ) +{ + wxASSERT( aNode->GetName() == wxT( "TECHNOLOGY" ) ); + + XNODE* cNode = aNode->GetChildren(); + + for( ; cNode; cNode = cNode->GetNext() ) + { + wxString cNodeName = cNode->GetName(); + + if( cNodeName == wxT( "UNITS" ) ) + { + wxString unit = CADSTAR_COMMON::GetAttributeID( cNode, 0 ); + + if( unit == wxT( "CENTIMETER" ) ) + Unit = CPA_UNITS::CENTIMETER; + else if( unit == wxT( "INCH" ) ) + Unit = CPA_UNITS::INCH; + else if( unit == wxT( "METER" ) ) + Unit = CPA_UNITS::METER; + else if( unit == wxT( "MICROMETRE" ) ) + Unit = CPA_UNITS::MICROMETRE; + else if( unit == wxT( "MM" ) ) + Unit = CPA_UNITS::MM; + else if( unit == wxT( "THOU" ) ) + Unit = CPA_UNITS::THOU; + else + THROW_UNKNOWN_PARAMETER_IO_ERROR( unit, wxT( "TECHNOLOGY -> UNITS" ) ); + } + else if( cNodeName == wxT( "UNITSPRECISION" ) ) + UnitDisplPrecision = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + else if( cNodeName == wxT( "INTERLINEGAP" ) ) + InterlineGap = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + else if( cNodeName == wxT( "BARLINEGAP" ) ) + BarlineGap = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + else if( cNodeName == wxT( "ALLOWBARTEXT" ) ) + AllowBarredText = true; + else if( cNodeName == wxT( "ANGULARPRECISION" ) ) + AngularPrecision = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + else if( cNodeName == wxT( "MINROUTEWIDTH" ) ) + MinRouteWidth = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + else if( cNodeName == wxT( "MINNECKED" ) ) + MinNeckedLength = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + else if( cNodeName == wxT( "MINUNNECKED" ) ) + MinUnneckedLength = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + else if( cNodeName == wxT( "MINMITER" ) ) + MinMitre = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + else if( cNodeName == wxT( "MAXMITER" ) ) + MaxMitre = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + else if( cNodeName == wxT( "MAXPHYSLAYER" ) ) + MaxPhysicalLayer = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + else if( cNodeName == wxT( "TRACKGRID" ) ) + TrackGrid = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + else if( cNodeName == wxT( "VIAGRID" ) ) + ViaGrid = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + else if( cNodeName == wxT( "DESIGNORIGIN" ) ) + { + std::vector pts = + CADSTAR_COMMON::ParseAllChildPoints( cNode, true, 1 ); + DesignOrigin = pts[0]; + } + else if( cNodeName == wxT( "DESIGNAREA" ) ) + { + std::vector pts = + CADSTAR_COMMON::ParseAllChildPoints( cNode, true, 2 ); + DesignArea = std::make_pair( pts[0], pts[1] ); + } + else if( cNodeName == wxT( "DESIGNREF" ) ) + { + std::vector pts = + CADSTAR_COMMON::ParseAllChildPoints( cNode, true, 1 ); + DesignRef = pts[0]; + } + else if( cNodeName == wxT( "DESIGNLIMIT" ) ) + { + std::vector pts = + CADSTAR_COMMON::ParseAllChildPoints( cNode, true, 1 ); + DesignLimit = pts[0]; + } + else if( cNodeName == wxT( "BACKOFFJCTS" ) ) + BackOffJunctions = true; + else if( cNodeName == wxT( "BCKOFFWIDCHANGE" ) ) + BackOffWidthChange = true; + else + THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, wxT( "TECHNOLOGY" ) ); + } +} + + +bool CPA_GRID::IsGrid( XNODE* aNode ) +{ + wxString aNodeName = aNode->GetName(); + + if( aNodeName == wxT( "FRACTIONALGRID" ) || aNodeName == wxT( "STEPGRID" ) ) + return true; + else + return false; +} + + +void CPA_GRID::Parse( XNODE* aNode ) +{ + wxASSERT( IsGrid( aNode ) ); + + wxString aNodeName = aNode->GetName(); + + if( aNodeName == wxT( "FRACTIONALGRID" ) ) + Type = CPA_GRID_TYPE::FRACTIONALGRID; + else if( aNodeName == wxT( "STEPGRID" ) ) + Type = CPA_GRID_TYPE::STEPGRID; + else + wxASSERT_MSG( true, wxT( "Unknown Grid Type" ) ); + + Name = CADSTAR_COMMON::GetAttributeID( aNode, 0 ); + Param1 = CADSTAR_COMMON::GetAttributeIDLong( aNode, 1 ); + Param2 = CADSTAR_COMMON::GetAttributeIDLong( aNode, 2 ); +} + + +void CPA_GRIDS::Parse( XNODE* aNode ) +{ + wxASSERT( aNode->GetName() == wxT( "GRIDS" ) ); + + XNODE* cNode = aNode->GetChildren(); + + for( ; cNode; cNode = cNode->GetNext() ) + { + wxString cNodeName = cNode->GetName(); + + if( cNodeName == wxT( "WORKINGGRID" ) ) + { + XNODE* workingGridNode = cNode->GetChildren(); + + if( !CPA_GRID::IsGrid( workingGridNode ) ) + THROW_UNKNOWN_NODE_IO_ERROR( + workingGridNode->GetName(), wxT( "GRIDS -> WORKINGGRID" ) ); + else + WorkingGrid.Parse( workingGridNode ); + } + else if( cNodeName == wxT( "SCREENGRID" ) ) + { + XNODE* screenGridNode = cNode->GetChildren(); + + if( !CPA_GRID::IsGrid( screenGridNode ) ) + THROW_UNKNOWN_NODE_IO_ERROR( + screenGridNode->GetName(), wxT( "GRIDS -> SCREENGRID" ) ); + else + ScreenGrid.Parse( screenGridNode ); + } + else if( CPA_GRID::IsGrid( cNode ) ) + { + CPA_GRID userGrid; + userGrid.Parse( cNode ); + UserGrids.push_back( userGrid ); + } + } +} diff --git a/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_parser.h b/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_parser.h index 7ac42a597c..51cd639845 100644 --- a/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_parser.h +++ b/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_parser.h @@ -30,7 +30,7 @@ #include #include -const long CPA_UNDEFINED = -1; // CADSTAR 2018.0 and 2019.0 arhive, - // 20=> CADSTAR 18.0 archive, 19=> CADSTAR 17.0 archive, etc.) + long SomeInt; ///< It is unclear what this parameter is used for + long Version; ///< Archive version number (e.g. 21 => CADSTAR 2018.0 and 2019.0 arhive, + ///< 20=> CADSTAR 18.0 archive, 19=> CADSTAR 17.0 archive, etc.) void Parse( XNODE* aNode ); }; @@ -106,10 +106,10 @@ struct CPA_MATERIAL { CPA_ID ID; wxString Name; - CPA_MATERIAL_LAYER_TYPE Type; // TextCodes; std::map RouteCodes; std::map CopperCodes; - std::vector SpacingCodes; // SpacingCodes; ///< Spacing Design Rules std::map PadCodes; std::map ViaCodes; - std::map LayerPairs; //< Default vias to use between pairs of layers + std::map LayerPairs; ///< Default vias to use between pairs of layers std::map AttributeNames; std::map NetClasses; std::map SpacingClassNames; std::vector SpacingClasses; - void Parse( XNODE* aNode ); //TODO Implement + void Parse( XNODE* aNode ); +}; + +//................................. +// ASSIGNMENTS -> TECHNOLOGY +//................................. + +enum class CPA_UNITS +{ + THOU, + INCH, + MICROMETRE, + MM, + CENTIMETER, + METER +}; + +struct CPA_TECHNOLOGY +{ + CPA_UNITS Unit; ///< Unit to display for linear dimensions + long UnitDisplPrecision; ///< Number of decimal points to display for linear dimensions + long InterlineGap; ///< For CADSTAR font only, distance between lines of text, + ///< expressed as a percentage of the text height (accepted + ///< values are 0-100) + long BarlineGap; ///< For CADSTAR font only, distance between top bar and + ///< character, expressed as a percentage of the text height + ///< (accepted values are 0-100) + bool AllowBarredText = false; ///< Specifies if barring is allowed in the design + long AngularPrecision; ///< Number of decimal points to display for angular dimensions + long MinRouteWidth; ///< Manufacturing Design Rule. Corresponds to "Thin Route Width" + long MinNeckedLength; ///< Manufacturing Design Rule. Corresponds to + ///< "Minimum Thinner Track Length" + long MinUnneckedLength; ///< Manufacturing Design Rule. Corresponds to + ///< "Minimum Thicker Track Length" + long MinMitre; ///< Manufacturing Design Rule. Corresponds to "Minimum Mitre" + long MaxMitre; ///< Manufacturing Design Rule. Corresponds to "Maximum Mitre" + long MaxPhysicalLayer; ///< Should equal number of copper layers. However, it seems this + ///< can be set to any arbitrarily high number as long as it is + ///< greater or equal to the number of copper layers. Also the + ///< last copper layer (bottom) must have this set as its value. + long TrackGrid; ///< Grid for Routes (equal X and Y steps) + long ViaGrid; ///< Grid for Vias (equal X and Y steps) + + CADSTAR_COMMON::POINT DesignOrigin; + std::pair DesignArea; + CADSTAR_COMMON::POINT DesignRef; ///< Appears to be 0,0 always + CADSTAR_COMMON::POINT DesignLimit; + + bool BackOffJunctions = false; + bool BackOffWidthChange = false; + + void Parse( XNODE* aNode ); +}; + +//................................. +// ASSIGNMENTS -> GRIDS +//................................. + +enum class CPA_GRID_TYPE +{ + FRACTIONALGRID, ///< Param1 = Unit, Param2 = Divisor. The grid is equal in X and Y dimensions + ///< with a step size equal to Param1/Param2 + STEPGRID ///< Param1 = X Step, Param2 = Y Step. A standard x,y grid. +}; + + +struct CPA_GRID +{ + CPA_GRID_TYPE Type; + wxString Name; + long Param1; ///< Either Unit or X step, depending on Type (see CPA_GRID_TYPE for + ///< more details) + long Param2; ///< Either Divisor or Y step, depending on Type (see CPA_GRID_TYPE for + ///< more details) + + static bool IsGrid( XNODE* aNode ); + void Parse( XNODE* aNode ); +}; + + +struct CPA_GRIDS +{ + CPA_GRID WorkingGrid; + CPA_GRID ScreenGrid; ///< From CADSTAR Help: "There is one Screen Grid, which is + ///< visible as dots on the screen. You cannot specify your + ///< own name for the Screen Grid. The visibility and colour + ///< of the dots representing the Screen Grid is set up by + ///< the Highlight category on the Colours dialog. + ///< + ///< The type of Screen grid displayed(Lined or Points) is + ///< set up on the Display dialog within Options(File menu)." + std::vector UserGrids; ///< List of predefined grids created by the user + + void Parse( XNODE* aNode ); }; struct CPA_ASSIGNMENTS { - CPA_LAYERDEFS Layerdefs; - CPA_CODEDEFS Codedefs; - //TODO Add technology, grids, etc. + CPA_LAYERDEFS Layerdefs; + CPA_CODEDEFS Codedefs; + CPA_TECHNOLOGY Technology; + CPA_GRIDS Grids; + bool NetclassEditAttributeSettings = false; //< Unclear what this does + bool SpacingclassEditAttributeSettings = false; //< Unclear what this does + + void Parse( XNODE* aNode ); }; @@ -556,7 +656,7 @@ public: CPA_ASSIGNMENTS Assignments; //TODO Add Library, Defaults, Parts, etc.. - int KiCadUnitMultiplier; //