Added kicad2step tool.
This commit is contained in:
parent
809b0040ea
commit
231b08e58f
|
@ -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;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
Loading…
Reference in New Issue