Added kicad2step tool.

This commit is contained in:
Cirilo Bernardo 2016-09-02 20:08:40 +10:00 committed by Wayne Stambaugh
parent 809b0040ea
commit 231b08e58f
19 changed files with 4943 additions and 0 deletions

View File

@ -1,2 +1,5 @@
add_subdirectory( idftools ) add_subdirectory( idftools )
if( USE_OCE )
add_subdirectory( kicad2step )
endif( USE_OCE )

View File

@ -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 )

View File

@ -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

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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

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