committed by
Wayne Stambaugh
19 changed files with 4943 additions and 0 deletions
-
3utils/CMakeLists.txt
-
25utils/kicad2step/CMakeLists.txt
-
178utils/kicad2step/kicad2step.cpp
-
1167utils/kicad2step/pcb/3d_resolver.cpp
-
242utils/kicad2step/pcb/3d_resolver.h
-
244utils/kicad2step/pcb/base.cpp
-
89utils/kicad2step/pcb/base.h
-
136utils/kicad2step/pcb/kicadcurve.cpp
-
61utils/kicad2step/pcb/kicadcurve.h
-
92utils/kicad2step/pcb/kicadmodel.cpp
-
47utils/kicad2step/pcb/kicadmodel.h
-
338utils/kicad2step/pcb/kicadmodule.cpp
-
75utils/kicad2step/pcb/kicadmodule.h
-
177utils/kicad2step/pcb/kicadpad.cpp
-
66utils/kicad2step/pcb/kicadpad.h
-
385utils/kicad2step/pcb/kicadpcb.cpp
-
88utils/kicad2step/pcb/kicadpcb.h
-
1391utils/kicad2step/pcb/oce_utils.cpp
-
139utils/kicad2step/pcb/oce_utils.h
@ -1,2 +1,5 @@ |
|||
add_subdirectory( idftools ) |
|||
|
|||
if( USE_OCE ) |
|||
add_subdirectory( kicad2step ) |
|||
endif( USE_OCE ) |
|||
@ -0,0 +1,25 @@ |
|||
include_directories( |
|||
pcb |
|||
${CMAKE_CURRENT_SOURCE_DIR} |
|||
${OCE_INCLUDE_DIRS} |
|||
) |
|||
|
|||
add_executable( kicad2step |
|||
kicad2step.cpp |
|||
pcb/3d_resolver.cpp |
|||
pcb/base.cpp |
|||
pcb/kicadmodel.cpp |
|||
pcb/kicadmodule.cpp |
|||
pcb/kicadpad.cpp |
|||
pcb/kicadpcb.cpp |
|||
pcb/kicadcurve.cpp |
|||
pcb/oce_utils.cpp |
|||
sexpr/sexpr.cpp |
|||
sexpr/sexpr_parser.cpp |
|||
) |
|||
|
|||
target_link_libraries( kicad2step ${wxWidgets_LIBRARIES} ${LIBS_OCE} ) |
|||
|
|||
install( TARGETS kicad2step |
|||
DESTINATION bin |
|||
COMPONENT binary ) |
|||
@ -0,0 +1,178 @@ |
|||
/*
|
|||
* This program source code file is part of kicad2mcad |
|||
* |
|||
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com> |
|||
* |
|||
* 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 |
|||
*/ |
|||
|
|||
#include <wx/app.h>
|
|||
#include <wx/cmdline.h>
|
|||
#include <wx/log.h>
|
|||
#include <wx/string.h>
|
|||
#include <wx/filename.h>
|
|||
#include <sstream>
|
|||
#include <iostream>
|
|||
#include <Standard_Failure.hxx>
|
|||
|
|||
#include "kicadpcb.h"
|
|||
|
|||
class KICAD2MCAD : public wxAppConsole |
|||
{ |
|||
public: |
|||
virtual bool OnInit(); |
|||
virtual int OnRun(); |
|||
virtual void OnInitCmdLine(wxCmdLineParser& parser); |
|||
virtual bool OnCmdLineParsed(wxCmdLineParser& parser); |
|||
|
|||
private: |
|||
#ifdef SUPPORTS_IGES
|
|||
bool m_fmtIGES; |
|||
#endif
|
|||
bool m_overwrite; |
|||
wxString m_filename; |
|||
double m_xOrigin; |
|||
double m_yOrigin; |
|||
}; |
|||
|
|||
static const wxCmdLineEntryDesc cmdLineDesc[] = |
|||
{ |
|||
{ wxCMD_LINE_OPTION, "f", NULL, "input file name", |
|||
wxCMD_LINE_VAL_STRING, wxCMD_LINE_OPTION_MANDATORY }, |
|||
#ifdef SUPPORTS_IGES
|
|||
{ wxCMD_LINE_SWITCH, "i", NULL, "IGES output (default STEP)", |
|||
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL }, |
|||
#endif
|
|||
{ wxCMD_LINE_SWITCH, "w", NULL, "overwrite output file", |
|||
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL }, |
|||
{ wxCMD_LINE_OPTION, "x", NULL, "X origin of board", |
|||
wxCMD_LINE_VAL_DOUBLE, wxCMD_LINE_PARAM_OPTIONAL }, |
|||
{ wxCMD_LINE_OPTION, "y", NULL, "Y origin of board (pcbnew coordinate system)", |
|||
wxCMD_LINE_VAL_DOUBLE, wxCMD_LINE_PARAM_OPTIONAL }, |
|||
{ wxCMD_LINE_SWITCH, "h", NULL, "display this message", |
|||
wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP }, |
|||
{ wxCMD_LINE_NONE } |
|||
}; |
|||
|
|||
|
|||
wxIMPLEMENT_APP_CONSOLE( KICAD2MCAD ); |
|||
|
|||
|
|||
bool KICAD2MCAD::OnInit() |
|||
{ |
|||
#ifdef SUPPORTS_IGES
|
|||
m_fmtIGES = false; |
|||
#endif
|
|||
m_overwrite = false; |
|||
m_xOrigin = 0.0; |
|||
m_yOrigin = 0.0; |
|||
|
|||
if( !wxAppConsole::OnInit() ) |
|||
return false; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
void KICAD2MCAD::OnInitCmdLine( wxCmdLineParser& parser ) |
|||
{ |
|||
parser.SetDesc( cmdLineDesc ); |
|||
parser.SetSwitchChars( "-" ); |
|||
return; |
|||
} |
|||
|
|||
|
|||
bool KICAD2MCAD::OnCmdLineParsed( wxCmdLineParser& parser ) |
|||
{ |
|||
#ifdef SUPPORTS_IGES
|
|||
if( parser.Found( "i" ) ) |
|||
m_fmtIGES = true; |
|||
#endif
|
|||
|
|||
if( parser.Found( "w" ) ) |
|||
m_overwrite = true; |
|||
|
|||
parser.Found( "x", &m_xOrigin ); |
|||
parser.Found( "y", &m_yOrigin ); |
|||
|
|||
wxString fname; |
|||
parser.Found( "f", &fname ); |
|||
m_filename = fname; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
int KICAD2MCAD::OnRun() |
|||
{ |
|||
wxFileName fname( m_filename ); |
|||
|
|||
if( !fname.FileExists() ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; |
|||
ostr << " * no such file: '" << m_filename.ToUTF8() << "'\n"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
|
|||
return -1; |
|||
} |
|||
|
|||
#ifdef SUPPORTS_IGES
|
|||
if( m_fmtIGES ) |
|||
fname.SetExt( "igs" ); |
|||
else |
|||
#endif
|
|||
fname.SetExt( "stp" ); |
|||
|
|||
wxString outfile = fname.GetFullPath(); |
|||
|
|||
KICADPCB pcb; |
|||
pcb.SetOrigin( m_xOrigin, m_yOrigin ); |
|||
|
|||
if( pcb.ReadFile( m_filename ) ) |
|||
{ |
|||
bool res; |
|||
|
|||
try |
|||
{ |
|||
pcb.ComposePCB(); |
|||
|
|||
#ifdef SUPPORTS_IGES
|
|||
if( m_fmtIGES ) |
|||
res = pcb.WriteIGES( outfile, m_overwrite ); |
|||
else |
|||
#endif
|
|||
res = pcb.WriteSTEP( outfile, m_overwrite ); |
|||
|
|||
if( !res ) |
|||
return -1; |
|||
} |
|||
catch( Standard_Failure e ) |
|||
{ |
|||
e.Print( std::cerr ); |
|||
return -1; |
|||
} |
|||
catch( ... ) |
|||
{ |
|||
std::cerr << "** (no exception information)\n"; |
|||
return -1; |
|||
} |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
1167
utils/kicad2step/pcb/3d_resolver.cpp
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,242 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2015-2016 Cirilo Bernardo <cirilo.bernardo@gmail.com> |
|||
* |
|||
* 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 |
|||
*/ |
|||
|
|||
/** |
|||
* @file 3d_resolver.h |
|||
* provides an extensible class to resolve 3D model paths. |
|||
* Derived from 3d_filename_resolver.h,cpp and modified for |
|||
* use in stand-alone utilities. |
|||
*/ |
|||
|
|||
#ifndef RESOLVER_3D_H |
|||
#define RESOLVER_3D_H |
|||
|
|||
#include <list> |
|||
#include <map> |
|||
#include <vector> |
|||
#include <wx/string.h> |
|||
|
|||
namespace S3D |
|||
{ |
|||
|
|||
struct rsort_wxString |
|||
{ |
|||
bool operator() (const wxString& strA, const wxString& strB ) const |
|||
{ |
|||
// sort a wxString using the reverse character order; for 3d model |
|||
// filenames this will typically be a much faster operation than |
|||
// a normal alphabetic sort |
|||
wxString::const_reverse_iterator sA = strA.rbegin(); |
|||
wxString::const_reverse_iterator eA = strA.rend(); |
|||
|
|||
wxString::const_reverse_iterator sB = strB.rbegin(); |
|||
wxString::const_reverse_iterator eB = strB.rend(); |
|||
|
|||
if( strA.empty() ) |
|||
{ |
|||
if( strB.empty() ) |
|||
return false; |
|||
|
|||
// note: this rule implies that a null string is first in the sort order |
|||
return true; |
|||
} |
|||
|
|||
if( strB.empty() ) |
|||
return false; |
|||
|
|||
while( sA != eA && sB != eB ) |
|||
{ |
|||
if( (*sA) == (*sB) ) |
|||
{ |
|||
++sA; |
|||
++sB; |
|||
continue; |
|||
} |
|||
|
|||
if( (*sA) < (*sB) ) |
|||
return true; |
|||
else |
|||
return false; |
|||
} |
|||
|
|||
if( sB == eB ) |
|||
return false; |
|||
|
|||
return true; |
|||
} |
|||
}; |
|||
|
|||
}; // end NAMESPACE |
|||
|
|||
|
|||
class KICADPCB; |
|||
|
|||
struct S3D_ALIAS |
|||
{ |
|||
wxString m_alias; // alias to the base path |
|||
wxString m_pathvar; // base path as stored in the config file |
|||
wxString m_pathexp; // expanded base path |
|||
wxString m_description; // description of the aliased path |
|||
}; |
|||
|
|||
class S3D_RESOLVER |
|||
{ |
|||
private: |
|||
wxString m_ConfigDir; // 3D configuration directory |
|||
std::list< S3D_ALIAS > m_Paths; // list of base paths to search from |
|||
// mapping of (short) file names to resolved names |
|||
std::map< wxString, wxString, S3D::rsort_wxString > m_NameMap; |
|||
int m_errflags; |
|||
wxString m_curProjDir; |
|||
// environment variables |
|||
std::map< wxString, wxString > m_EnvVars; |
|||
|
|||
/** |
|||
* Function createPathList |
|||
* builds the path list using available information such as |
|||
* KISYS3DMOD and the 3d_path_list configuration file. Invalid |
|||
* paths are silently discarded and removed from the configuration |
|||
* file. |
|||
* |
|||
* @return true if at least one valid path was found |
|||
*/ |
|||
bool createPathList( void ); |
|||
|
|||
/** |
|||
* Function addPath |
|||
* checks that a path is valid and adds it to the search list |
|||
* |
|||
* @param aPath is the alias set to be checked and added |
|||
* @return true if aPath is valid |
|||
*/ |
|||
bool addPath( const S3D_ALIAS& aPath ); |
|||
|
|||
/** |
|||
* Function readPathList |
|||
* reads a list of path names from a configuration file |
|||
* |
|||
* @return true if a file was found and contained at least |
|||
* one valid path |
|||
*/ |
|||
bool readPathList( void ); |
|||
|
|||
/** |
|||
* Function writePathList |
|||
* writes the current path list to a configuration file |
|||
* |
|||
* @return true if the path list was not empty and was |
|||
* successfully written to the configuration file |
|||
*/ |
|||
bool writePathList( void ); |
|||
|
|||
/** |
|||
* Function checkEnvVarPath |
|||
* checks the ${ENV_VAR} component of a path and adds |
|||
* it to the resolver's path list if it is not yet in |
|||
* the list |
|||
*/ |
|||
void checkEnvVarPath( const wxString& aPath ); |
|||
|
|||
wxString expandVars( const wxString& aPath ); |
|||
|
|||
public: |
|||
S3D_RESOLVER(); |
|||
|
|||
/** |
|||
* Function Set3DConfigDir |
|||
* sets the user's configuration directory |
|||
* for 3D models. |
|||
* |
|||
* @param aConfigDir |
|||
* @return true if the call succeeds (directory exists) |
|||
*/ |
|||
bool Set3DConfigDir( const wxString& aConfigDir ); |
|||
|
|||
/** |
|||
* Function SetProjectDir |
|||
* sets the current KiCad project directory as the first |
|||
* entry in the model path list |
|||
* |
|||
* @param aProjDir is the current project directory |
|||
* @param flgChanged, if specified, is set to true if the directory actually changed |
|||
* @return true if the call succeeds |
|||
*/ |
|||
bool SetProjectDir( const wxString& aProjDir, bool* flgChanged = NULL ); |
|||
wxString GetProjectDir( void ); |
|||
|
|||
/** |
|||
* Function UpdatePathList |
|||
* clears the current path list and substitutes the given path |
|||
* list, updating the path configuration file on success. |
|||
*/ |
|||
bool UpdatePathList( std::vector< S3D_ALIAS >& aPathList ); |
|||
|
|||
/** |
|||
* Function ResolvePath |
|||
* determines the full path of the given file name. In the future |
|||
* remote files may be supported, in which case it is best to |
|||
* require a full URI in which case ResolvePath should check that |
|||
* the URI conforms to RFC-2396 and related documents and copies |
|||
* aFileName into aResolvedName if the URI is valid. |
|||
*/ |
|||
wxString ResolvePath( const wxString& aFileName ); |
|||
|
|||
/** |
|||
* Function ShortenPath |
|||
* produces a relative path based on the existing |
|||
* search directories or returns the same path if |
|||
* the path is not a superset of an existing search path. |
|||
* |
|||
* @param aFullPathName is an absolute path to shorten |
|||
* @return the shortened path or aFullPathName |
|||
*/ |
|||
wxString ShortenPath( const wxString& aFullPathName ); |
|||
|
|||
/** |
|||
* Function GetPaths |
|||
* returns a pointer to the internal path list; the items in:load |
|||
* |
|||
* the list can be used to set up the list of search paths |
|||
* available to a 3D file browser. |
|||
* |
|||
* @return pointer to the internal path list |
|||
*/ |
|||
const std::list< S3D_ALIAS >* GetPaths( void ); |
|||
|
|||
/** |
|||
* Function SplitAlias |
|||
* returns true if the given name contains an alias and |
|||
* populates the string anAlias with the alias and aRelPath |
|||
* with the relative path. |
|||
*/ |
|||
bool SplitAlias( const wxString& aFileName, wxString& anAlias, wxString& aRelPath ); |
|||
|
|||
/** |
|||
* Function ValidateName |
|||
* returns true if the given path is a valid aliased relative path. |
|||
* If the path contains an alias then hasAlias is set true. |
|||
*/ |
|||
bool ValidateFileName( const wxString& aFileName, bool& hasAlias ); |
|||
}; |
|||
|
|||
#endif // RESOLVER_3D_H |
|||
@ -0,0 +1,244 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com> |
|||
* |
|||
* 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 |
|||
*/ |
|||
|
|||
#include <wx/log.h>
|
|||
#include <iostream>
|
|||
#include <sstream>
|
|||
#include <cmath>
|
|||
#include "sexpr/sexpr.h"
|
|||
#include "base.h"
|
|||
|
|||
static const char bad_position[] = "* corrupt module in PCB file; invalid position"; |
|||
|
|||
|
|||
bool Get2DPositionAndRotation( SEXPR::SEXPR* data, DOUBLET& aPosition, double& aRotation ) |
|||
{ |
|||
// form: (at X Y {rot})
|
|||
int nchild = data->GetNumberOfChildren(); |
|||
|
|||
if( nchild < 3 ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << bad_position; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
if( data->GetChild( 0 )->GetSymbol() != "at" ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << "* SEXPR item is not a position string"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
SEXPR::SEXPR* child = data->GetChild( 1 ); |
|||
double x; |
|||
|
|||
if( child->IsDouble() ) |
|||
x = child->GetDouble(); |
|||
else if( child->IsInteger() ) |
|||
x = (double) child->GetInteger(); |
|||
else |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << bad_position; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
child = data->GetChild( 2 ); |
|||
double y; |
|||
|
|||
if( child->IsDouble() ) |
|||
y = child->GetDouble(); |
|||
else if( child->IsInteger() ) |
|||
y = (double) child->GetInteger(); |
|||
else |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << bad_position; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
aPosition.x = x; |
|||
aPosition.y = y; |
|||
|
|||
if( nchild == 3 ) |
|||
return true; |
|||
|
|||
child = data->GetChild( 3 ); |
|||
double angle = 0.0; |
|||
|
|||
if( child->IsDouble() ) |
|||
angle = child->GetDouble(); |
|||
else if( child->IsInteger() ) |
|||
angle = (double) child->GetInteger(); |
|||
else |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << bad_position; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
while( angle >= 360.0 ) |
|||
angle -= 360.0; |
|||
|
|||
while( angle <= -360.0 ) |
|||
angle += 360.0; |
|||
|
|||
aRotation = (angle / 180.0) * M_PI; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
bool Get2DCoordinate( SEXPR::SEXPR* data, DOUBLET& aCoordinate ) |
|||
{ |
|||
// form: (at X Y {rot})
|
|||
int nchild = data->GetNumberOfChildren(); |
|||
|
|||
if( nchild < 3 ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << bad_position; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
SEXPR::SEXPR* child = data->GetChild( 1 ); |
|||
double x; |
|||
|
|||
if( child->IsDouble() ) |
|||
x = child->GetDouble(); |
|||
else if( child->IsInteger() ) |
|||
x = (double) child->GetInteger(); |
|||
else |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << bad_position; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
child = data->GetChild( 2 ); |
|||
double y; |
|||
|
|||
if( child->IsDouble() ) |
|||
y = child->GetDouble(); |
|||
else if( child->IsInteger() ) |
|||
y = (double) child->GetInteger(); |
|||
else |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << bad_position; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
aCoordinate.x = x; |
|||
aCoordinate.y = y; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
bool Get3DCoordinate( SEXPR::SEXPR* data, TRIPLET& aCoordinate ) |
|||
{ |
|||
// form: (at X Y Z)
|
|||
int nchild = data->GetNumberOfChildren(); |
|||
|
|||
if( nchild < 4 ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << bad_position; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
SEXPR::SEXPR* child; |
|||
double val[3]; |
|||
|
|||
for( int i = 1; i < 4; ++i ) |
|||
{ |
|||
child = data->GetChild( i ); |
|||
|
|||
if( child->IsDouble() ) |
|||
val[i -1] = child->GetDouble(); |
|||
else if( child->IsInteger() ) |
|||
val[i -1] = (double) child->GetInteger(); |
|||
else |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << bad_position; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
aCoordinate.x = val[0]; |
|||
aCoordinate.y = val[1]; |
|||
aCoordinate.z = val[2]; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
bool GetXYZRotation( SEXPR::SEXPR* data, TRIPLET& aRotation ) |
|||
{ |
|||
const char bad_rotation[] = "* invalid 3D rotation"; |
|||
|
|||
if( !Get3DCoordinate( data, aRotation ) ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << bad_rotation; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
if( aRotation.x > 360.0 || aRotation.x < -360.0 ) |
|||
{ |
|||
int nr = (int) aRotation.x / 360; |
|||
aRotation.x -= ( 360.0 * nr ); |
|||
} |
|||
|
|||
if( aRotation.y > 360.0 || aRotation.y < -360.0 ) |
|||
{ |
|||
int nr = (int) aRotation.y / 360; |
|||
aRotation.y -= ( 360.0 * nr ); |
|||
} |
|||
|
|||
if( aRotation.z > 360.0 || aRotation.z < -360.0 ) |
|||
{ |
|||
int nr = (int) aRotation.z / 360; |
|||
aRotation.z -= ( 360.0 * nr ); |
|||
} |
|||
|
|||
aRotation.x *= M_PI / 180.0; |
|||
aRotation.y *= M_PI / 180.0; |
|||
aRotation.z *= M_PI / 180.0; |
|||
|
|||
return true; |
|||
} |
|||
@ -0,0 +1,89 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com> |
|||
* |
|||
* 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 |
|||
*/ |
|||
|
|||
/** |
|||
* @file base.h |
|||
* provides declarations of items which are basic to all |
|||
* kicad2mcad code. |
|||
*/ |
|||
|
|||
#ifndef KICADBASE_H |
|||
#define KICADBASE_H |
|||
|
|||
namespace SEXPR |
|||
{ |
|||
class SEXPR; |
|||
} |
|||
|
|||
enum CURVE_TYPE |
|||
{ |
|||
CURVE_NONE = 0, // invalid curve |
|||
CURVE_LINE, |
|||
CURVE_ARC, |
|||
CURVE_CIRCLE |
|||
}; |
|||
|
|||
/* |
|||
* Layers of importance to MCAD export: |
|||
* LAYER_TOP: specifies that a module is on the top of the PCB |
|||
* LAYER_BOTTOM: specifies that a module is on the bottom of the PCB |
|||
* LAYER_EDGE: specifies that a Curve is associated with the PCB edge |
|||
*/ |
|||
enum LAYERS |
|||
{ |
|||
LAYER_NONE = 0, // no layer specified (bad object) |
|||
LAYER_TOP, // top side |
|||
LAYER_BOTTOM, // bottom side |
|||
LAYER_EDGE // edge data |
|||
}; |
|||
|
|||
struct DOUBLET |
|||
{ |
|||
double x; |
|||
double y; |
|||
|
|||
DOUBLET() : x( 0.0 ), y( 0.0 ) { return; } |
|||
DOUBLET( double aX, double aY ) : x( aX ), y( aY ) { return; } |
|||
}; |
|||
|
|||
struct TRIPLET |
|||
{ |
|||
double x; |
|||
double y; |
|||
|
|||
union |
|||
{ |
|||
double z; |
|||
double angle; |
|||
}; |
|||
|
|||
TRIPLET() : x( 0.0 ), y( 0.0 ), z( 0.0 ) { return; } |
|||
TRIPLET( double aX, double aY, double aZ ) : x( aX ), y( aY ), z( aZ ) { return; } |
|||
}; |
|||
|
|||
bool Get2DPositionAndRotation( SEXPR::SEXPR* data, DOUBLET& aPosition, double& aRotation ); |
|||
bool Get2DCoordinate( SEXPR::SEXPR* data, DOUBLET& aCoordinate ); |
|||
bool Get3DCoordinate( SEXPR::SEXPR* data, TRIPLET& aCoordinate ); |
|||
bool GetXYZRotation( SEXPR::SEXPR* data, TRIPLET& aRotation ); |
|||
|
|||
#endif // KICADBASE_H |
|||
@ -0,0 +1,136 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com> |
|||
* |
|||
* 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 |
|||
*/ |
|||
|
|||
#include <wx/log.h>
|
|||
#include <iostream>
|
|||
#include <sstream>
|
|||
#include <math.h>
|
|||
#include "sexpr/sexpr.h"
|
|||
#include "kicadcurve.h"
|
|||
|
|||
|
|||
KICADCURVE::KICADCURVE() |
|||
{ |
|||
m_form = CURVE_NONE; |
|||
m_angle = 0.0; |
|||
m_radius = 0.0; |
|||
m_layer = LAYER_NONE; |
|||
m_startangle = 0.0; |
|||
m_endangle = 0.0; |
|||
|
|||
return; |
|||
} |
|||
|
|||
|
|||
KICADCURVE::~KICADCURVE() |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
|
|||
bool KICADCURVE::Read( SEXPR::SEXPR* aEntry, CURVE_TYPE aCurveType ) |
|||
{ |
|||
if( CURVE_LINE != aCurveType && CURVE_ARC != aCurveType && CURVE_CIRCLE != aCurveType ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << "* Unsupported curve type: " << aCurveType; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
m_form = aCurveType; |
|||
|
|||
int nchild = aEntry->GetNumberOfChildren(); |
|||
|
|||
if( ( CURVE_CIRCLE == aCurveType && nchild < 5 ) |
|||
|| ( CURVE_ARC == aCurveType && nchild < 6 ) |
|||
|| ( CURVE_LINE == aCurveType && nchild < 5 ) ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << "* bad curve data; not enough parameters"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
SEXPR::SEXPR* child; |
|||
std::string text; |
|||
|
|||
for( int i = 1; i < nchild; ++i ) |
|||
{ |
|||
child = aEntry->GetChild( i ); |
|||
|
|||
if( !child->IsList() ) |
|||
continue; |
|||
|
|||
text = child->GetChild( 0 )->GetSymbol(); |
|||
|
|||
if( text == "start" || text == "center" ) |
|||
{ |
|||
if( !Get2DCoordinate( child, m_start ) ) |
|||
return false; |
|||
} |
|||
else if( text == "end" ) |
|||
{ |
|||
if( !Get2DCoordinate( child, m_end ) ) |
|||
return false; |
|||
} |
|||
else if( text == "angle" ) |
|||
{ |
|||
if( child->GetNumberOfChildren() < 2 |
|||
|| ( !child->GetChild( 1 )->IsDouble() |
|||
&& !child->GetChild( 1 )->IsInteger() ) ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << "* bad angle data"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
if( child->GetChild( 1 )->IsDouble() ) |
|||
m_angle = child->GetChild( 1 )->GetDouble(); |
|||
else |
|||
m_angle = child->GetChild( 1 )->GetInteger(); |
|||
|
|||
m_angle = m_angle / 180.0 * M_PI; |
|||
} |
|||
else if( text == "layer" ) |
|||
{ |
|||
if( child->GetNumberOfChildren() < 2 |
|||
|| !child->GetChild( 1 )->IsSymbol() ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << "* bad layer data"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
text = child->GetChild( 1 )->GetSymbol(); |
|||
|
|||
// NOTE: for the moment we only process Edge.Cuts
|
|||
if( text == "Edge.Cuts" ) |
|||
m_layer = LAYER_EDGE; |
|||
} |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com> |
|||
* |
|||
* 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 |
|||
*/ |
|||
|
|||
/** |
|||
* @file kicadcurve.h |
|||
* declares the Curve (glyph) object. |
|||
*/ |
|||
|
|||
#ifndef KICADCURVE_H |
|||
#define KICADCURVE_H |
|||
|
|||
#include <string> |
|||
#include <vector> |
|||
#include "base.h" |
|||
|
|||
|
|||
class KICADCURVE |
|||
{ |
|||
public: |
|||
KICADCURVE(); |
|||
virtual ~KICADCURVE(); |
|||
|
|||
bool Read( SEXPR::SEXPR* aEntry, CURVE_TYPE aCurveType ); |
|||
|
|||
LAYERS GetLayer() |
|||
{ |
|||
return m_layer; |
|||
} |
|||
|
|||
CURVE_TYPE m_form; // form of curve: line, arc, circle |
|||
LAYERS m_layer; // layer of the glyph |
|||
DOUBLET m_start; // start point of line or center for arc and circle |
|||
DOUBLET m_end; // end point of line, first point on arc or circle |
|||
DOUBLET m_ep; // actual endpoint, to be computed in the case of arcs |
|||
double m_radius;// radius; to be computed in the case of arcs and circles |
|||
double m_angle; // subtended angle of arc |
|||
double m_startangle; |
|||
double m_endangle; |
|||
}; |
|||
|
|||
#endif // KICADCURVE_H |
|||
@ -0,0 +1,92 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com> |
|||
* |
|||
* 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 |
|||
*/ |
|||
|
|||
#include <wx/log.h>
|
|||
#include <iostream>
|
|||
#include <sstream>
|
|||
#include "sexpr/sexpr.h"
|
|||
#include "kicadmodel.h"
|
|||
|
|||
|
|||
KICADMODEL::KICADMODEL() : m_scale( 1.0, 1.0, 1.0 ) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
|
|||
KICADMODEL::~KICADMODEL() |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
|
|||
bool KICADMODEL::Read( SEXPR::SEXPR* aEntry ) |
|||
{ |
|||
// form: ( pad N thru_hole shape (at x y {r}) (size x y) (drill {oval} x {y}) (layers X X X) )
|
|||
int nchild = aEntry->GetNumberOfChildren(); |
|||
|
|||
if( nchild < 2 ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << "* invalid model entry"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
SEXPR::SEXPR* child = aEntry->GetChild( 1 ); |
|||
|
|||
if( child->IsSymbol() ) |
|||
m_modelname = child->GetSymbol(); |
|||
else if( child->IsString() ) |
|||
m_modelname = child->GetString(); |
|||
else |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << "* invalid model entry; invalid path"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
for( int i = 2; i < nchild; ++i ) |
|||
{ |
|||
child = aEntry->GetChild( i ); |
|||
|
|||
if( !child->IsList() ) |
|||
continue; |
|||
|
|||
std::string name = child->GetChild( 0 )->GetSymbol(); |
|||
bool ret = true; |
|||
|
|||
if( name == "at" ) |
|||
ret = Get3DCoordinate( child->GetChild( 1 ), m_offset ); |
|||
else if( name == "scale" ) |
|||
ret = Get3DCoordinate( child->GetChild( 1 ), m_scale ); |
|||
else if( name == "rotate" ) |
|||
ret = GetXYZRotation( child->GetChild( 1 ), m_rotation ); |
|||
|
|||
if( !ret ) |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com> |
|||
* |
|||
* 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 |
|||
*/ |
|||
|
|||
/** |
|||
* @file kicadmodel.h |
|||
* declares the 3D model object. |
|||
*/ |
|||
|
|||
#ifndef KICADMODEL_H |
|||
#define KICADMODEL_H |
|||
|
|||
#include "base.h" |
|||
|
|||
struct KICADMODEL |
|||
{ |
|||
KICADMODEL(); |
|||
virtual ~KICADMODEL(); |
|||
|
|||
bool Read( SEXPR::SEXPR* aEntry ); |
|||
|
|||
std::string m_modelname; |
|||
TRIPLET m_scale; |
|||
TRIPLET m_offset; |
|||
TRIPLET m_rotation; |
|||
}; |
|||
|
|||
#endif // KICADMODEL_H |
|||
@ -0,0 +1,338 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com> |
|||
* |
|||
* 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 |
|||
*/ |
|||
|
|||
#include <wx/log.h>
|
|||
#include <iostream>
|
|||
#include <limits>
|
|||
#include <sstream>
|
|||
|
|||
#include "3d_resolver.h"
|
|||
#include "sexpr/sexpr.h"
|
|||
#include "kicadmodel.h"
|
|||
#include "kicadmodule.h"
|
|||
#include "kicadpad.h"
|
|||
#include "kicadcurve.h"
|
|||
#include "oce_utils.h"
|
|||
|
|||
|
|||
KICADMODULE::KICADMODULE() |
|||
{ |
|||
m_side = LAYER_NONE; |
|||
m_rotation = 0.0; |
|||
|
|||
return; |
|||
} |
|||
|
|||
|
|||
KICADMODULE::~KICADMODULE() |
|||
{ |
|||
for( auto i : m_pads ) |
|||
delete i; |
|||
|
|||
for( auto i : m_curves ) |
|||
delete i; |
|||
|
|||
for( auto i : m_models ) |
|||
delete i; |
|||
|
|||
return; |
|||
} |
|||
|
|||
|
|||
bool KICADMODULE::Read( SEXPR::SEXPR* aEntry ) |
|||
{ |
|||
if( NULL == aEntry ) |
|||
return false; |
|||
|
|||
if( aEntry->IsList() ) |
|||
{ |
|||
size_t nc = aEntry->GetNumberOfChildren(); |
|||
SEXPR::SEXPR* child = aEntry->GetChild( 0 ); |
|||
std::string name = child->GetSymbol(); |
|||
|
|||
if( name != "module" ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << "* BUG: module parser invoked for type '" << name << "'\n"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
bool result = true; |
|||
|
|||
for( size_t i = 1; i < nc && result; ++i ) |
|||
{ |
|||
child = aEntry->GetChild( i ); |
|||
|
|||
// skip the module name and the optional 'locked' attribute;
|
|||
// due to the vagaries of the kicad version of sexpr, the
|
|||
// name may be a Symbol or a String
|
|||
if( i <= 2 && ( child->IsSymbol() || child->IsString() ) ) |
|||
continue; |
|||
|
|||
if( !child->IsList() ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << "* corrupt module in PCB file\n"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
std::string symname( child->GetChild( 0 )->GetSymbol() ); |
|||
|
|||
if( symname == "layer" ) |
|||
result = result && parseLayer( child ); |
|||
else if( symname == "at" ) |
|||
result = result && parsePosition( child ); |
|||
else if( symname == "fp_text" ) |
|||
result = result && parseText( child ); |
|||
else if( symname == "fp_arc" ) |
|||
result = result && parseCurve( child, CURVE_ARC ); |
|||
else if( symname == "fp_line" ) |
|||
result = result && parseCurve( child, CURVE_LINE ); |
|||
else if( symname == "fp_circle" ) |
|||
result = result && parseCurve( child, CURVE_CIRCLE ); |
|||
else if( symname == "pad" ) |
|||
result = result && parsePad( child ); |
|||
else if( symname == "model" ) |
|||
result = result && parseModel( child ); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
std::ostringstream ostr; |
|||
ostr << "* data is not a valid PCB module\n"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
|
|||
return false; |
|||
} |
|||
|
|||
|
|||
bool KICADMODULE::parseModel( SEXPR::SEXPR* data ) |
|||
{ |
|||
KICADMODEL* mp = new KICADMODEL(); |
|||
|
|||
if( !mp->Read( data ) ) |
|||
{ |
|||
delete mp; |
|||
return false; |
|||
} |
|||
|
|||
m_models.push_back( mp ); |
|||
return true; |
|||
} |
|||
|
|||
|
|||
bool KICADMODULE::parseCurve( SEXPR::SEXPR* data, CURVE_TYPE aCurveType ) |
|||
{ |
|||
KICADCURVE* mp = new KICADCURVE(); |
|||
|
|||
if( !mp->Read( data, aCurveType ) ) |
|||
{ |
|||
delete mp; |
|||
return false; |
|||
} |
|||
|
|||
// NOTE: for now we are only interested in glyphs on the outline layer
|
|||
if( LAYER_EDGE != mp->GetLayer() ) |
|||
{ |
|||
delete mp; |
|||
return true; |
|||
} |
|||
|
|||
m_curves.push_back( mp ); |
|||
return true; |
|||
} |
|||
|
|||
|
|||
bool KICADMODULE::parseLayer( SEXPR::SEXPR* data ) |
|||
{ |
|||
SEXPR::SEXPR* val = data->GetChild( 1 ); |
|||
std::string layer; |
|||
|
|||
if( val->IsSymbol() ) |
|||
layer = val->GetSymbol(); |
|||
else if( val->IsString() ) |
|||
layer = val->GetString(); |
|||
else |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << "* corrupt module in PCB file; layer cannot be parsed\n"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
if( layer == "F.Cu" ) |
|||
m_side = LAYER_TOP; |
|||
else if( layer == "B.Cu" ) |
|||
m_side = LAYER_BOTTOM; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
bool KICADMODULE::parsePosition( SEXPR::SEXPR* data ) |
|||
{ |
|||
return Get2DPositionAndRotation( data, m_position, m_rotation ); |
|||
} |
|||
|
|||
|
|||
bool KICADMODULE::parseText( SEXPR::SEXPR* data ) |
|||
{ |
|||
// we're only interested in the Reference Designator
|
|||
if( data->GetNumberOfChildren() < 3 ) |
|||
return true; |
|||
|
|||
SEXPR::SEXPR* child = data->GetChild( 1 ); |
|||
std::string text; |
|||
|
|||
if( child->IsSymbol() ) |
|||
text = child->GetSymbol(); |
|||
else if( child->IsString() ) |
|||
text = child->GetString(); |
|||
|
|||
if( text != "reference" ) |
|||
return true; |
|||
|
|||
child = data->GetChild( 2 ); |
|||
|
|||
if( child->IsSymbol() ) |
|||
text = child->GetSymbol(); |
|||
else if( child->IsString() ) |
|||
text = child->GetString(); |
|||
|
|||
m_refdes = text; |
|||
return true; |
|||
} |
|||
|
|||
|
|||
bool KICADMODULE::parsePad( SEXPR::SEXPR* data ) |
|||
{ |
|||
KICADPAD* mp = new KICADPAD(); |
|||
|
|||
if( !mp->Read( data ) ) |
|||
{ |
|||
delete mp; |
|||
return false; |
|||
} |
|||
|
|||
// NOTE: for now we only accept thru-hole pads
|
|||
// for the MCAD description
|
|||
if( !mp->IsThruHole() ) |
|||
{ |
|||
delete mp; |
|||
return true; |
|||
} |
|||
|
|||
m_pads.push_back( mp ); |
|||
return true; |
|||
} |
|||
|
|||
|
|||
bool KICADMODULE::ComposePCB( class PCBMODEL* aPCB, S3D_RESOLVER* resolver, DOUBLET aOrigin ) |
|||
{ |
|||
// translate pads and curves to final position and append to PCB.
|
|||
double dlim = (double)std::numeric_limits< float >::epsilon(); |
|||
|
|||
double vsin = sin( m_rotation ); |
|||
double vcos = cos( m_rotation ); |
|||
bool hasdata = false; |
|||
|
|||
double posX = m_position.x - aOrigin.x; |
|||
double posY = m_position.y - aOrigin.y; |
|||
|
|||
for( auto i : m_curves ) |
|||
{ |
|||
if( i->m_layer != LAYER_EDGE || CURVE_NONE == i->m_form ) |
|||
continue; |
|||
|
|||
KICADCURVE lcurve = *i; |
|||
|
|||
if( LAYER_TOP == m_side ) |
|||
{ |
|||
lcurve.m_start.y = -lcurve.m_start.y; |
|||
lcurve.m_end.y = -lcurve.m_end.y; |
|||
lcurve.m_angle = -lcurve.m_angle; |
|||
} |
|||
|
|||
if( m_rotation < -dlim || m_rotation > dlim ) |
|||
{ |
|||
double x = lcurve.m_start.x * vcos - lcurve.m_start.y * vsin; |
|||
double y = lcurve.m_start.x * vsin + lcurve.m_start.y * vcos; |
|||
lcurve.m_start.x = x; |
|||
lcurve.m_start.y = y; |
|||
x = lcurve.m_end.x * vcos - lcurve.m_end.y * vsin; |
|||
y = lcurve.m_end.x * vsin + lcurve.m_end.y * vcos; |
|||
lcurve.m_end.x = x; |
|||
lcurve.m_end.y = y; |
|||
} |
|||
|
|||
lcurve.m_start.x += posX; |
|||
lcurve.m_start.y -= posY; |
|||
lcurve.m_end.x += posX; |
|||
lcurve.m_end.y -= posY; |
|||
|
|||
if( aPCB->AddOutlineSegment( &lcurve ) ) |
|||
hasdata = true; |
|||
|
|||
} |
|||
|
|||
for( auto i : m_pads ) |
|||
{ |
|||
if( !i->IsThruHole() ) |
|||
continue; |
|||
|
|||
KICADPAD lpad = *i; |
|||
lpad.m_position.y = -lpad.m_position.y; |
|||
|
|||
if( m_rotation < -dlim || m_rotation > dlim ) |
|||
{ |
|||
double x = lpad.m_position.x * vcos - lpad.m_position.y * vsin; |
|||
double y = lpad.m_position.x * vsin + lpad.m_position.y * vcos; |
|||
lpad.m_position.x = x; |
|||
lpad.m_position.y = y; |
|||
} |
|||
|
|||
lpad.m_position.x += posX; |
|||
lpad.m_position.y -= posY; |
|||
|
|||
if( aPCB->AddPadHole( &lpad ) ) |
|||
hasdata = true; |
|||
|
|||
} |
|||
|
|||
DOUBLET newpos( posX, posY ); |
|||
|
|||
for( auto i : m_models ) |
|||
{ |
|||
std::string fname( resolver->ResolvePath( i->m_modelname.c_str() ).ToUTF8() ); |
|||
|
|||
if( aPCB->AddComponent( fname, m_refdes, LAYER_BOTTOM == m_side ? true : false, |
|||
newpos, m_rotation, i->m_offset, i->m_rotation ) ) |
|||
hasdata = true; |
|||
|
|||
} |
|||
|
|||
return hasdata; |
|||
} |
|||
@ -0,0 +1,75 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com> |
|||
* |
|||
* 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 |
|||
*/ |
|||
|
|||
/** |
|||
* @file kicadmodule.h |
|||
* declares the PCB Component object. |
|||
*/ |
|||
|
|||
#ifndef KICADMODULE_H |
|||
#define KICADMODULE_H |
|||
|
|||
#include <string> |
|||
#include <vector> |
|||
#include "base.h" |
|||
|
|||
namespace SEXPR |
|||
{ |
|||
class SEXPR; |
|||
} |
|||
|
|||
class KICADPAD; |
|||
class KICADCURVE; |
|||
class KICADMODEL; |
|||
class PCBMODEL; |
|||
class S3D_RESOLVER; |
|||
|
|||
class KICADMODULE |
|||
{ |
|||
private: |
|||
bool parseModel( SEXPR::SEXPR* data ); |
|||
bool parseCurve( SEXPR::SEXPR* data, CURVE_TYPE aCurveType ); |
|||
bool parseLayer( SEXPR::SEXPR* data ); |
|||
bool parsePosition( SEXPR::SEXPR* data ); |
|||
bool parseText( SEXPR::SEXPR* data ); |
|||
bool parsePad( SEXPR::SEXPR* data ); |
|||
|
|||
LAYERS m_side; |
|||
std::string m_refdes; |
|||
DOUBLET m_position; |
|||
double m_rotation; // rotation (radians) |
|||
|
|||
std::vector< KICADPAD* > m_pads; |
|||
std::vector< KICADCURVE* > m_curves; |
|||
std::vector< KICADMODEL* > m_models; |
|||
|
|||
public: |
|||
KICADMODULE(); |
|||
virtual ~KICADMODULE(); |
|||
|
|||
bool Read( SEXPR::SEXPR* aEntry ); |
|||
|
|||
bool ComposePCB( class PCBMODEL* aPCB, S3D_RESOLVER* resolver, DOUBLET aOrigin ); |
|||
}; |
|||
|
|||
#endif // KICADMODULE_H |
|||
@ -0,0 +1,177 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com> |
|||
* |
|||
* 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 |
|||
*/ |
|||
|
|||
#include <wx/log.h>
|
|||
#include <iostream>
|
|||
#include <sstream>
|
|||
#include "sexpr/sexpr.h"
|
|||
#include "kicadpad.h"
|
|||
|
|||
|
|||
static const char bad_pad[] = "* corrupt module in PCB file; bad pad"; |
|||
|
|||
|
|||
KICADPAD::KICADPAD() |
|||
{ |
|||
m_rotation = 0.0; |
|||
m_thruhole = false; |
|||
m_drill.oval = false; |
|||
return; |
|||
} |
|||
|
|||
|
|||
KICADPAD::~KICADPAD() |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
|
|||
bool KICADPAD::Read( SEXPR::SEXPR* aEntry ) |
|||
{ |
|||
// form: ( pad N thru_hole shape (at x y {r}) (size x y) (drill {oval} x {y}) (layers X X X) )
|
|||
int nchild = aEntry->GetNumberOfChildren(); |
|||
|
|||
if( nchild < 2 ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << bad_pad; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
SEXPR::SEXPR* child; |
|||
|
|||
for( int i = 1; i < nchild; ++i ) |
|||
{ |
|||
child = aEntry->GetChild( i ); |
|||
|
|||
if( child->IsSymbol() && |
|||
( child->GetSymbol() == "thru_hole" || child->GetSymbol() == "np_thru_hole" ) ) |
|||
{ |
|||
m_thruhole = true; |
|||
continue; |
|||
} |
|||
|
|||
if( child->IsList() ) |
|||
{ |
|||
std::string name = child->GetChild( 0 )->GetSymbol(); |
|||
bool ret = true; |
|||
|
|||
if( name == "drill" ) |
|||
ret = parseDrill( child ); |
|||
else if( name == "at" ) |
|||
ret = Get2DPositionAndRotation( child, m_position, m_rotation ); |
|||
|
|||
if( !ret ) |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
bool KICADPAD::parseDrill( SEXPR::SEXPR* aDrill ) |
|||
{ |
|||
// form: (drill {oval} X {Y})
|
|||
const char bad_drill[] = "* corrupt module in PCB file; bad drill"; |
|||
int nchild = aDrill->GetNumberOfChildren(); |
|||
|
|||
if( nchild < 2 ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << bad_drill; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
SEXPR::SEXPR* child = aDrill->GetChild( 1 ); |
|||
int idx = 1; |
|||
m_drill.oval = false; |
|||
|
|||
if( child->IsSymbol() ) |
|||
{ |
|||
if( child->GetSymbol() == "oval" && nchild >= 4 ) |
|||
{ |
|||
m_drill.oval = true; |
|||
child = aDrill->GetChild( ++idx ); |
|||
} |
|||
else |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << bad_drill << " (unexpected symbol: "; |
|||
ostr << child->GetSymbol() << "), nchild = " << nchild; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
double x; |
|||
|
|||
if( child->IsDouble() ) |
|||
x = child->GetDouble(); |
|||
else if( child->IsInteger() ) |
|||
x = (double) child->GetInteger(); |
|||
else |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << bad_drill << " (did not find X size)"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
m_drill.size.x = x; |
|||
m_drill.size.y = x; |
|||
|
|||
if( ++idx == nchild || !m_drill.oval ) |
|||
return true; |
|||
|
|||
for( int i = idx; i < nchild; ++i ) |
|||
{ |
|||
child = aDrill->GetChild( i ); |
|||
|
|||
// NOTE: the Offset of the copper pad is stored
|
|||
// in the drill string but since the copper is not
|
|||
// needed in the MCAD model the Offset is simply ignored.
|
|||
if( !child->IsList() ) |
|||
{ |
|||
double y; |
|||
|
|||
if( child->IsDouble() ) |
|||
y = child->GetDouble(); |
|||
else if( child->IsInteger() ) |
|||
y = (double) child->GetInteger(); |
|||
else |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << bad_drill << " (did not find Y size)"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
m_drill.size.y = y; |
|||
} |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
@ -0,0 +1,66 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com> |
|||
* |
|||
* 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 |
|||
*/ |
|||
|
|||
/** |
|||
* @file kicadpad.h |
|||
* declares the PAD description object. |
|||
*/ |
|||
|
|||
#ifndef KICADPAD_H |
|||
#define KICADPAD_H |
|||
|
|||
#include <string> |
|||
#include <vector> |
|||
#include "base.h" |
|||
|
|||
|
|||
struct KICADDRILL |
|||
{ |
|||
DOUBLET size; |
|||
bool oval; |
|||
}; |
|||
|
|||
|
|||
class KICADPAD |
|||
{ |
|||
private: |
|||
bool m_thruhole; |
|||
bool parseDrill( SEXPR::SEXPR* aDrill ); |
|||
|
|||
public: |
|||
KICADPAD(); |
|||
virtual ~KICADPAD(); |
|||
|
|||
bool Read( SEXPR::SEXPR* aEntry ); |
|||
|
|||
bool IsThruHole() |
|||
{ |
|||
return m_thruhole; |
|||
} |
|||
|
|||
DOUBLET m_position; |
|||
double m_rotation; // rotation (radians) |
|||
KICADDRILL m_drill; |
|||
}; |
|||
|
|||
#endif // KICADPAD_H |
|||
@ -0,0 +1,385 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com> |
|||
* |
|||
* 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 |
|||
*/ |
|||
|
|||
#include <wx/utils.h>
|
|||
#include <wx/filename.h>
|
|||
#include <wx/log.h>
|
|||
#include <wx/stdpaths.h>
|
|||
#include <iostream>
|
|||
#include <sstream>
|
|||
#include <string>
|
|||
|
|||
#include "kicadpcb.h"
|
|||
#include "sexpr/sexpr.h"
|
|||
#include "sexpr/sexpr_parser.h"
|
|||
#include "kicadmodule.h"
|
|||
#include "kicadcurve.h"
|
|||
#include "oce_utils.h"
|
|||
|
|||
|
|||
/*
|
|||
* GetKicadConfigPath() is taken from KiCad's common.cpp source: |
|||
* Copyright (C) 2014-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr |
|||
* Copyright (C) 2008-2015 Wayne Stambaugh <stambaughw@verizon.net> |
|||
* Copyright (C) 1992-2015 KiCad Developers |
|||
*/ |
|||
static wxString GetKicadConfigPath() |
|||
{ |
|||
wxFileName cfgpath; |
|||
|
|||
// From the wxWidgets wxStandardPaths::GetUserConfigDir() help:
|
|||
// Unix: ~ (the home directory)
|
|||
// Windows: "C:\Documents and Settings\username\Application Data"
|
|||
// Mac: ~/Library/Preferences
|
|||
cfgpath.AssignDir( wxStandardPaths::Get().GetUserConfigDir() ); |
|||
|
|||
#if !defined( __WINDOWS__ ) && !defined( __WXMAC__ )
|
|||
wxString envstr; |
|||
|
|||
if( !wxGetEnv( wxT( "XDG_CONFIG_HOME" ), &envstr ) || envstr.IsEmpty() ) |
|||
{ |
|||
// XDG_CONFIG_HOME is not set, so use the fallback
|
|||
cfgpath.AppendDir( wxT( ".config" ) ); |
|||
} |
|||
else |
|||
{ |
|||
// Override the assignment above with XDG_CONFIG_HOME
|
|||
cfgpath.AssignDir( envstr ); |
|||
} |
|||
#endif
|
|||
|
|||
cfgpath.AppendDir( wxT( "kicad" ) ); |
|||
|
|||
if( !cfgpath.DirExists() ) |
|||
{ |
|||
cfgpath.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ); |
|||
} |
|||
|
|||
return cfgpath.GetPath(); |
|||
} |
|||
|
|||
|
|||
KICADPCB::KICADPCB() |
|||
{ |
|||
wxFileName cfgdir( GetKicadConfigPath(), "" ); |
|||
cfgdir.AppendDir( "3d" ); |
|||
m_resolver.Set3DConfigDir( cfgdir.GetPath() ); |
|||
m_thickness = 1.6; |
|||
m_pcb = NULL; |
|||
|
|||
return; |
|||
} |
|||
|
|||
|
|||
KICADPCB::~KICADPCB() |
|||
{ |
|||
for( auto i : m_modules ) |
|||
delete i; |
|||
|
|||
for( auto i : m_curves ) |
|||
delete i; |
|||
|
|||
if( m_pcb ) |
|||
delete m_pcb; |
|||
|
|||
return; |
|||
} |
|||
|
|||
|
|||
bool KICADPCB::ReadFile( const wxString& aFileName ) |
|||
{ |
|||
wxFileName fname( aFileName ); |
|||
|
|||
if( fname.GetExt() != "kicad_pcb" ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; |
|||
ostr << " * expecting extension 'kicad_pcb', got '"; |
|||
ostr << fname.GetExt().ToUTF8() << "'\n"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
|
|||
return false; |
|||
} |
|||
|
|||
if( !fname.FileExists() ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; |
|||
ostr << " * no such file: '" << aFileName.ToUTF8() << "'\n"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
|
|||
return false; |
|||
} |
|||
|
|||
fname.Normalize(); |
|||
m_filename = fname.GetFullPath().ToUTF8(); |
|||
m_resolver.SetProjectDir( fname.GetPath() ); |
|||
|
|||
try |
|||
{ |
|||
SEXPR::PARSER parser; |
|||
std::string infile( fname.GetFullPath().ToUTF8() ); |
|||
SEXPR::SEXPR* data = parser.ParseFromFile( infile ); |
|||
|
|||
if( NULL == data ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << "* no data in file: '" << aFileName.ToUTF8() << "'\n"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
|
|||
return false; |
|||
} |
|||
|
|||
if( !parsePCB( data ) ) |
|||
return false; |
|||
|
|||
} |
|||
catch( std::exception& e ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << "* error reading file: '" << aFileName.ToUTF8() << "'\n"; |
|||
ostr << " * " << e.what() << "\n"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
|
|||
return false; |
|||
} |
|||
catch( ... ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << "* unexpected exception while reading file: '" << aFileName.ToUTF8() << "'\n"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
|
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
bool KICADPCB::WriteSTEP( const wxString& aFileName, bool aOverwrite ) |
|||
{ |
|||
if( m_pcb ) |
|||
{ |
|||
std::string filename( aFileName.ToUTF8() ); |
|||
return m_pcb->WriteSTEP( filename, aOverwrite ); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
|
|||
#ifdef SUPPORTS_IGES
|
|||
bool KICADPCB::WriteIGES( const wxString& aFileName, bool aOverwrite ) |
|||
{ |
|||
if( m_pcb ) |
|||
{ |
|||
std::string filename( aFileName.ToUTF8() ); |
|||
return m_pcb->WriteIGES( filename, aOverwrite ); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
#endif
|
|||
|
|||
|
|||
bool KICADPCB::parsePCB( SEXPR::SEXPR* data ) |
|||
{ |
|||
if( NULL == data ) |
|||
return false; |
|||
|
|||
if( data->IsList() ) |
|||
{ |
|||
size_t nc = data->GetNumberOfChildren(); |
|||
SEXPR::SEXPR* child = data->GetChild( 0 ); |
|||
std::string name = child->GetSymbol(); |
|||
|
|||
if( name != "kicad_pcb" ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << "* data is not a valid PCB file: '" << m_filename << "'\n"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
bool result = true; |
|||
|
|||
for( size_t i = 1; i < nc && result; ++i ) |
|||
{ |
|||
child = data->GetChild( i ); |
|||
|
|||
if( !child->IsList() ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << "* corrupt PCB file: '" << m_filename << "'\n"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
std::string symname( child->GetChild( 0 )->GetSymbol() ); |
|||
|
|||
if( symname == "general" ) |
|||
result = result && parseGeneral( child ); |
|||
else if( symname == "module" ) |
|||
result = result && parseModule( child ); |
|||
else if( symname == "gr_arc" ) |
|||
result = result && parseCurve( child, CURVE_ARC ); |
|||
else if( symname == "gr_line" ) |
|||
result = result && parseCurve( child, CURVE_LINE ); |
|||
else if( symname == "gr_circle" ) |
|||
result = result && parseCurve( child, CURVE_CIRCLE ); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
std::ostringstream ostr; |
|||
ostr << "* data is not a valid PCB file: '" << m_filename << "'\n"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
|
|||
return false; |
|||
} |
|||
|
|||
|
|||
bool KICADPCB::parseGeneral( SEXPR::SEXPR* data ) |
|||
{ |
|||
size_t nc = data->GetNumberOfChildren(); |
|||
SEXPR::SEXPR* child = NULL; |
|||
|
|||
for( size_t i = 1; i < nc; ++i ) |
|||
{ |
|||
child = data->GetChild( i ); |
|||
|
|||
if( !child->IsList() ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << "* corrupt PCB file: '" << m_filename << "'\n"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
// at the moment only the thickness is of interest in
|
|||
// the general section
|
|||
if( child->GetChild( 0 )->GetSymbol() != "thickness" ) |
|||
continue; |
|||
|
|||
m_thickness = child->GetChild( 1 )->GetDouble(); |
|||
return true; |
|||
} |
|||
|
|||
std::ostringstream ostr; |
|||
ostr << "* corrupt PCB file: '" << m_filename << "'\n"; |
|||
ostr << "* no PCB thickness specified in general section\n"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
|
|||
return false; |
|||
} |
|||
|
|||
|
|||
bool KICADPCB::parseModule( SEXPR::SEXPR* data ) |
|||
{ |
|||
KICADMODULE* mp = new KICADMODULE(); |
|||
|
|||
if( !mp->Read( data ) ) |
|||
{ |
|||
delete mp; |
|||
return false; |
|||
} |
|||
|
|||
m_modules.push_back( mp ); |
|||
return true; |
|||
} |
|||
|
|||
|
|||
bool KICADPCB::parseCurve( SEXPR::SEXPR* data, CURVE_TYPE aCurveType ) |
|||
{ |
|||
KICADCURVE* mp = new KICADCURVE(); |
|||
|
|||
if( !mp->Read( data, aCurveType ) ) |
|||
{ |
|||
delete mp; |
|||
return false; |
|||
} |
|||
|
|||
// reject any curves not on the Edge.Cuts layer
|
|||
if( mp->GetLayer() != LAYER_EDGE ) |
|||
{ |
|||
delete mp; |
|||
return true; |
|||
} |
|||
|
|||
m_curves.push_back( mp ); |
|||
return true; |
|||
} |
|||
|
|||
|
|||
bool KICADPCB::ComposePCB() |
|||
{ |
|||
if( m_pcb ) |
|||
return true; |
|||
|
|||
if( m_modules.empty() && m_curves.empty() ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << "** " << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "\n"; |
|||
ostr << "* no PCB data to render\n"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
return false; |
|||
} |
|||
|
|||
m_pcb = new PCBMODEL(); |
|||
m_pcb->SetPCBThickness( m_thickness ); |
|||
|
|||
for( auto i : m_curves ) |
|||
{ |
|||
if( CURVE_NONE == i->m_form || LAYER_EDGE != i->m_layer ) |
|||
continue; |
|||
|
|||
// adjust the coordinate system
|
|||
KICADCURVE lcurve = *i; |
|||
lcurve.m_start.y = -( lcurve.m_start.y - m_origin.y ); |
|||
lcurve.m_end.y = -( lcurve.m_end.y - m_origin.y ); |
|||
lcurve.m_start.x -= m_origin.x; |
|||
lcurve.m_end.x -= m_origin.x; |
|||
|
|||
if( CURVE_ARC == lcurve.m_form ) |
|||
lcurve.m_angle = -lcurve.m_angle; |
|||
|
|||
m_pcb->AddOutlineSegment( &lcurve ); |
|||
} |
|||
|
|||
for( auto i : m_modules ) |
|||
i->ComposePCB( m_pcb, &m_resolver, m_origin ); |
|||
|
|||
if( !m_pcb->CreatePCB() ) |
|||
{ |
|||
std::ostringstream ostr; |
|||
ostr << "** " << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "\n"; |
|||
ostr << "* could not create PCB solid model\n"; |
|||
wxLogMessage( "%s\n", ostr.str().c_str() ); |
|||
delete m_pcb; |
|||
m_pcb = NULL; |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
@ -0,0 +1,88 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com> |
|||
* |
|||
* 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 |
|||
*/ |
|||
|
|||
/** |
|||
* @file kicadpcb.h |
|||
* declares the main PCB object |
|||
*/ |
|||
|
|||
#ifndef KICADPCB_H |
|||
#define KICADPCB_H |
|||
|
|||
#include <wx/string.h> |
|||
#include <string> |
|||
#include <vector> |
|||
#include "3d_resolver.h" |
|||
#include "base.h" |
|||
|
|||
#ifdef SUPPORTS_IGES |
|||
#undef SUPPORTS_IGES |
|||
#endif |
|||
|
|||
namespace SEXPR |
|||
{ |
|||
class SEXPR; |
|||
} |
|||
|
|||
class KICADMODULE; |
|||
class KICADCURVE; |
|||
class PCBMODEL; |
|||
|
|||
class KICADPCB |
|||
{ |
|||
private: |
|||
S3D_RESOLVER m_resolver; |
|||
std::string m_filename; |
|||
PCBMODEL* m_pcb; |
|||
DOUBLET m_origin; |
|||
|
|||
// PCB parameters/entities |
|||
double m_thickness; |
|||
std::vector< KICADMODULE* > m_modules; |
|||
std::vector< KICADCURVE* > m_curves; |
|||
|
|||
bool parsePCB( SEXPR::SEXPR* data ); |
|||
bool parseGeneral( SEXPR::SEXPR* data ); |
|||
bool parseModule( SEXPR::SEXPR* data ); |
|||
bool parseCurve( SEXPR::SEXPR* data, CURVE_TYPE aCurveType ); |
|||
|
|||
public: |
|||
KICADPCB(); |
|||
virtual ~KICADPCB(); |
|||
|
|||
void SetOrigin( double aXOrigin, double aYOrigin ) |
|||
{ |
|||
m_origin.x = aXOrigin; |
|||
m_origin.y = aYOrigin; |
|||
} |
|||
|
|||
bool ReadFile( const wxString& aFileName ); |
|||
bool ComposePCB(); |
|||
bool WriteSTEP( const wxString& aFileName, bool aOverwrite ); |
|||
#ifdef SUPPORTS_IGES |
|||
bool WriteIGES( const wxString& aFileName, bool aOverwrite ); |
|||
#endif |
|||
}; |
|||
|
|||
|
|||
#endif // KICADPCB_H |
|||
1391
utils/kicad2step/pcb/oce_utils.cpp
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,139 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com> |
|||
* |
|||
* 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 OCE_VIS_OCE_UTILS_H |
|||
#define OCE_VIS_OCE_UTILS_H |
|||
|
|||
#include <list> |
|||
#include <map> |
|||
#include <string> |
|||
#include <utility> |
|||
#include <vector> |
|||
#include "base.h" |
|||
#include "kicadpcb.h" |
|||
#include "kicadcurve.h" |
|||
|
|||
#include <BRepBuilderAPI_MakeWire.hxx> |
|||
#include <TDocStd_Document.hxx> |
|||
#include <XCAFApp_Application.hxx> |
|||
#include <XCAFDoc_ShapeTool.hxx> |
|||
#include <TopoDS_Shape.hxx> |
|||
#include <TopoDS_Edge.hxx> |
|||
|
|||
|
|||
typedef std::pair< std::string, TDF_Label > MODEL_DATUM; |
|||
typedef std::map< std::string, TDF_Label > MODEL_MAP; |
|||
|
|||
class KICADPAD; |
|||
|
|||
class OUTLINE |
|||
{ |
|||
private: |
|||
bool m_closed; // set true if the loop is closed |
|||
|
|||
bool addEdge( BRepBuilderAPI_MakeWire* aWire, KICADCURVE& aCurve, DOUBLET& aLastPoint ); |
|||
bool testClosed( KICADCURVE& aFrontCurve, KICADCURVE& aBackCurve ); |
|||
|
|||
public: |
|||
std::list< KICADCURVE > m_curves; // list of contiguous segments |
|||
OUTLINE(); |
|||
virtual ~OUTLINE(); |
|||
|
|||
void Clear(); |
|||
|
|||
// attempt to add a curve to the outline; on success returns true |
|||
bool AddSegment( const KICADCURVE& aCurve ); |
|||
|
|||
bool IsClosed() |
|||
{ |
|||
return m_closed; |
|||
} |
|||
|
|||
bool MakeShape( TopoDS_Shape& aShape, double aThickness ); |
|||
}; |
|||
|
|||
|
|||
class PCBMODEL |
|||
{ |
|||
Handle( XCAFApp_Application ) m_app; |
|||
Handle( TDocStd_Document ) m_doc; |
|||
Handle( XCAFDoc_ShapeTool ) m_assy; |
|||
TDF_Label m_assy_label; |
|||
bool m_hasPCB; // set true if CreatePCB() has been invoked |
|||
TDF_Label m_pcb_label; // label for the PCB model |
|||
MODEL_MAP m_models; // map of file names to model labels |
|||
int m_components; // number of successfully loaded components; |
|||
double m_precision; // model (length unit) numeric precision |
|||
double m_angleprec; // angle numeric precision |
|||
double m_thickness; // PCB thickness, mm |
|||
double m_minx; // minimum X value in curves (leftmost curve feature) |
|||
std::list< KICADCURVE >::iterator m_mincurve; // iterator to the leftmost curve |
|||
|
|||
std::list< KICADCURVE > m_curves; |
|||
std::vector< TopoDS_Shape > m_cutouts; |
|||
|
|||
bool getModelLabel( const std::string aFileName, TDF_Label& aLabel ); |
|||
|
|||
bool getModelLocation( bool aBottom, DOUBLET aPosition, double aRotation, |
|||
TRIPLET aOffset, TRIPLET aOrientation, TopLoc_Location& aLocation ); |
|||
|
|||
bool readIGES( Handle( TDocStd_Document )& m_doc, const char* fname ); |
|||
bool readSTEP( Handle( TDocStd_Document )& m_doc, const char* fname ); |
|||
|
|||
TDF_Label transferModel( Handle( TDocStd_Document )& source, |
|||
Handle( TDocStd_Document )& dest ); |
|||
|
|||
public: |
|||
PCBMODEL(); |
|||
virtual ~PCBMODEL(); |
|||
|
|||
// add an outline segment (must be in final position) |
|||
bool AddOutlineSegment( KICADCURVE* aCurve ); |
|||
|
|||
// add a pad hole or slot (must be in final position) |
|||
bool AddPadHole( KICADPAD* aPad ); |
|||
|
|||
// add a component at the given position and orientation |
|||
bool AddComponent( const std::string& aFileName, const std::string aRefDes, |
|||
bool aBottom, DOUBLET aPosition, double aRotation, |
|||
TRIPLET aOffset, TRIPLET aOrientation ); |
|||
|
|||
// set the thickness of the PCB (mm); the top of the PCB shall be at Z = aThickness |
|||
// aThickness < 0.0 == use default thickness |
|||
// aThickness <= THICKNESS_MIN == use THICKNESS_MIN |
|||
// aThickness > THICKNESS_MIN == use aThickness |
|||
void SetPCBThickness( double aThickness ); |
|||
|
|||
// create the PCB model using the current outlines and drill holes |
|||
bool CreatePCB(); |
|||
|
|||
#ifdef SUPPORTS_IGES |
|||
// write the assembly model in IGES format |
|||
bool WriteIGES( const std::string& aFileName, bool aOverwrite ); |
|||
#endif |
|||
|
|||
// write the assembly model in STEP format |
|||
bool WriteSTEP( const std::string& aFileName, bool aOverwrite ); |
|||
}; |
|||
|
|||
#endif //OCE_VIS_OCE_UTILS_H |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue