IDF tools: code cleanup and debugging
This commit is contained in:
parent
60a86853ec
commit
7a110d0ce3
|
@ -36,6 +36,7 @@ include_directories(
|
|||
./exporters
|
||||
../lib_dxf
|
||||
./import_dxf
|
||||
../utils/idftools
|
||||
${INC_AFTER}
|
||||
)
|
||||
|
||||
|
@ -136,8 +137,6 @@ set( PCBNEW_EXPORTERS
|
|||
exporters/export_gencad.cpp
|
||||
exporters/export_idf.cpp
|
||||
exporters/export_vrml.cpp
|
||||
exporters/idf_common.cpp
|
||||
exporters/idf.cpp
|
||||
exporters/gen_drill_report_files.cpp
|
||||
exporters/gen_modules_placefile.cpp
|
||||
exporters/gendrill_Excellon_writer.cpp
|
||||
|
@ -385,6 +384,7 @@ if( KICAD_SCRIPTING_MODULES )
|
|||
common
|
||||
pcad2kicadpcb
|
||||
lib_dxf
|
||||
idf3
|
||||
${GITHUB_PLUGIN_LIBRARIES}
|
||||
polygon
|
||||
bitmaps
|
||||
|
@ -565,6 +565,7 @@ if( USE_KIWAY_DLLS )
|
|||
bitmaps
|
||||
gal
|
||||
lib_dxf
|
||||
idf3
|
||||
${GITHUB_PLUGIN_LIBRARIES}
|
||||
${wxWidgets_LIBRARIES}
|
||||
${OPENGL_LIBRARIES}
|
||||
|
@ -633,6 +634,7 @@ else() # milestone A) kills this off:
|
|||
bitmaps
|
||||
gal
|
||||
lib_dxf
|
||||
idf3
|
||||
${GITHUB_PLUGIN_LIBRARIES}
|
||||
${wxWidgets_LIBRARIES}
|
||||
${OPENGL_LIBRARIES}
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
#define OPTKEY_IDF_THOU wxT( "IDFExportThou" )
|
||||
|
||||
|
||||
bool Export_IDF3( BOARD *aPcb, const wxString & aFullFileName, double aUseThou );
|
||||
bool Export_IDF3( BOARD *aPcb, const wxString & aFullFileName, bool aUseThou );
|
||||
|
||||
|
||||
class DIALOG_EXPORT_IDF3: public DIALOG_EXPORT_IDF3_BASE
|
||||
|
|
|
@ -33,8 +33,9 @@
|
|||
#include <class_board.h>
|
||||
#include <class_module.h>
|
||||
#include <class_edge_mod.h>
|
||||
#include <idf.h>
|
||||
#include <idf_parser.h>
|
||||
#include <3d_struct.h>
|
||||
#include <build_version.h>
|
||||
|
||||
// assumed default graphical line thickness: 10000 IU == 0.1mm
|
||||
#define LINE_WIDTH (100000)
|
||||
|
@ -45,15 +46,15 @@
|
|||
* the data into a form which can be output as an IDFv3 compliant
|
||||
* BOARD_OUTLINE section.
|
||||
*/
|
||||
static void idf_export_outline( BOARD* aPcb, IDF_BOARD& aIDFBoard )
|
||||
static void idf_export_outline( BOARD* aPcb, IDF3_BOARD& aIDFBoard )
|
||||
{
|
||||
double scale = aIDFBoard.GetScale();
|
||||
double scale = aIDFBoard.GetUserScale();
|
||||
|
||||
DRAWSEGMENT* graphic; // KiCad graphical item
|
||||
IDF_POINT sp, ep; // start and end points from KiCad item
|
||||
|
||||
std::list< IDF_SEGMENT* > lines; // IDF intermediate form of KiCad graphical item
|
||||
IDF_OUTLINE outline; // graphical items forming an outline or cutout
|
||||
IDF_OUTLINE* outline = NULL; // graphical items forming an outline or cutout
|
||||
|
||||
// NOTE: IMPLEMENTATION
|
||||
// If/when component cutouts are allowed, we must implement them separately. Cutouts
|
||||
|
@ -61,7 +62,7 @@ static void idf_export_outline( BOARD* aPcb, IDF_BOARD& aIDFBoard )
|
|||
// The module cutouts should be handled via the idf_export_module() routine.
|
||||
|
||||
double offX, offY;
|
||||
aIDFBoard.GetOffset( offX, offY );
|
||||
aIDFBoard.GetUserOffset( offX, offY );
|
||||
|
||||
// Retrieve segments and arcs from the board
|
||||
for( BOARD_ITEM* item = aPcb->m_Drawings; item; item = item->Next() )
|
||||
|
@ -129,22 +130,31 @@ static void idf_export_outline( BOARD* aPcb, IDF_BOARD& aIDFBoard )
|
|||
// note: we do not use a try/catch block here since we intend
|
||||
// to simply ignore unclosed loops and continue processing
|
||||
// until we're out of segments to process
|
||||
IDF3::GetOutline( lines, outline );
|
||||
outline = new IDF_OUTLINE;
|
||||
IDF3::GetOutline( lines, *outline );
|
||||
|
||||
if( outline.empty() )
|
||||
if( outline->empty() )
|
||||
goto UseBoundingBox;
|
||||
|
||||
aIDFBoard.AddOutline( outline );
|
||||
aIDFBoard.AddBoardOutline( outline );
|
||||
outline = NULL;
|
||||
|
||||
// get all cutouts and write them out
|
||||
while( !lines.empty() )
|
||||
{
|
||||
IDF3::GetOutline( lines, outline );
|
||||
if( !outline )
|
||||
outline = new IDF_OUTLINE;
|
||||
|
||||
if( outline.empty() )
|
||||
IDF3::GetOutline( lines, *outline );
|
||||
|
||||
if( outline->empty() )
|
||||
{
|
||||
outline->Clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
aIDFBoard.AddOutline( outline );
|
||||
aIDFBoard.AddBoardOutline( outline );
|
||||
outline = NULL;
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -158,7 +168,10 @@ UseBoundingBox:
|
|||
lines.pop_front();
|
||||
}
|
||||
|
||||
outline.Clear();
|
||||
if( outline )
|
||||
outline->Clear();
|
||||
else
|
||||
outline = new IDF_OUTLINE;
|
||||
|
||||
// fetch a rectangular bounding box for the board;
|
||||
// there is always some uncertainty in the board dimensions
|
||||
|
@ -192,7 +205,7 @@ UseBoundingBox:
|
|||
p2.x = px[0];
|
||||
p2.y = py[0];
|
||||
|
||||
outline.push( new IDF_SEGMENT( p1, p2 ) );
|
||||
outline->push( new IDF_SEGMENT( p1, p2 ) );
|
||||
|
||||
for( int i = 1; i < 4; ++i )
|
||||
{
|
||||
|
@ -201,10 +214,10 @@ UseBoundingBox:
|
|||
p2.x = px[i];
|
||||
p2.y = py[i];
|
||||
|
||||
outline.push( new IDF_SEGMENT( p1, p2 ) );
|
||||
outline->push( new IDF_SEGMENT( p1, p2 ) );
|
||||
}
|
||||
|
||||
aIDFBoard.AddOutline( outline );
|
||||
aIDFBoard.AddBoardOutline( outline );
|
||||
}
|
||||
|
||||
|
||||
|
@ -216,7 +229,7 @@ UseBoundingBox:
|
|||
* the library ELECTRICAL section.
|
||||
*/
|
||||
static void idf_export_module( BOARD* aPcb, MODULE* aModule,
|
||||
IDF_BOARD& aIDFBoard )
|
||||
IDF3_BOARD& aIDFBoard )
|
||||
{
|
||||
// Reference Designator
|
||||
std::string crefdes = TO_UTF8( aModule->GetReference() );
|
||||
|
@ -243,14 +256,14 @@ static void idf_export_module( BOARD* aPcb, MODULE* aModule,
|
|||
|
||||
// Export pads
|
||||
double drill, x, y;
|
||||
double scale = aIDFBoard.GetScale();
|
||||
double scale = aIDFBoard.GetUserScale();
|
||||
IDF3::KEY_PLATING kplate;
|
||||
std::string pintype;
|
||||
std::string tstr;
|
||||
|
||||
double dx, dy;
|
||||
|
||||
aIDFBoard.GetOffset( dx, dy );
|
||||
aIDFBoard.GetUserOffset( dx, dy );
|
||||
|
||||
for( D_PAD* pad = aModule->Pads(); pad; pad = pad->Next() )
|
||||
{
|
||||
|
@ -313,7 +326,19 @@ static void idf_export_module( BOARD* aPcb, MODULE* aModule,
|
|||
}
|
||||
else
|
||||
{
|
||||
aIDFBoard.AddDrill( drill, x, y, kplate, crefdes, pintype, IDF3::ECAD );
|
||||
IDF_DRILL_DATA *dp = new IDF_DRILL_DATA( drill, x, y, kplate, crefdes,
|
||||
pintype, IDF3::ECAD );
|
||||
|
||||
if( !aIDFBoard.AddDrill( dp ) )
|
||||
{
|
||||
delete dp;
|
||||
|
||||
std::ostringstream ostr;
|
||||
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__;
|
||||
ostr << "(): could not add drill";
|
||||
|
||||
throw std::runtime_error( ostr.str() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -321,6 +346,8 @@ static void idf_export_module( BOARD* aPcb, MODULE* aModule,
|
|||
// add any valid models to the library item list
|
||||
std::string refdes;
|
||||
|
||||
IDF3_COMPONENT* comp = NULL;
|
||||
|
||||
for( S3D_MASTER* modfile = aModule->Models(); modfile != 0; modfile = modfile->Next() )
|
||||
{
|
||||
if( !modfile->Is3DType( S3D_MASTER::FILE3D_IDF ) )
|
||||
|
@ -330,14 +357,26 @@ static void idf_export_module( BOARD* aPcb, MODULE* aModule,
|
|||
{
|
||||
refdes = TO_UTF8( aModule->GetReference() );
|
||||
|
||||
// NOREFDES cannot be used or else the software gets confused
|
||||
// when writing out the placement data due to conflicting
|
||||
// placement and layer specifications; to work around this we
|
||||
// create a (hopefully) unique refdes for our exported part.
|
||||
if( refdes.empty() || !refdes.compare( "~" ) )
|
||||
refdes = aIDFBoard.GetRefDes();
|
||||
refdes = aIDFBoard.GetNewRefDes();
|
||||
}
|
||||
|
||||
IDF3_COMP_OUTLINE* outline;
|
||||
|
||||
outline = aIDFBoard.GetComponentOutline( modfile->GetShape3DName() );
|
||||
|
||||
if( !outline )
|
||||
throw( std::runtime_error( aIDFBoard.GetError() ) );
|
||||
|
||||
double rotz = aModule->GetOrientation()/10.0;
|
||||
double locx = modfile->m_MatPosition.x;
|
||||
double locy = modfile->m_MatPosition.y;
|
||||
double locz = modfile->m_MatPosition.z;
|
||||
double lrot = modfile->m_MatRotation.z;
|
||||
|
||||
bool top = ( aModule->GetLayer() == LAYER_N_BACK ) ? false : true;
|
||||
|
||||
|
@ -348,12 +387,12 @@ static void idf_export_module( BOARD* aPcb, MODULE* aModule,
|
|||
RotatePoint( &locx, &locy, aModule->GetOrientation() );
|
||||
locy = -locy;
|
||||
}
|
||||
|
||||
if( !top )
|
||||
{
|
||||
RotatePoint( &locx, &locy, aModule->GetOrientation() );
|
||||
locy = -locy;
|
||||
|
||||
rotz -= modfile->m_MatRotation.z;
|
||||
rotz = 180.0 - rotz;
|
||||
|
||||
if( rotz >= 360.0 )
|
||||
|
@ -363,10 +402,97 @@ static void idf_export_module( BOARD* aPcb, MODULE* aModule,
|
|||
while( rotz <= -360.0 ) rotz += 360.0;
|
||||
}
|
||||
|
||||
locx += aModule->GetPosition().x * scale + dx;
|
||||
locy += -aModule->GetPosition().y * scale + dy;
|
||||
if( comp == NULL )
|
||||
comp = aIDFBoard.FindComponent( refdes );
|
||||
|
||||
aIDFBoard.PlaceComponent( modfile->GetShape3DName(), refdes, locx, locy, locz, rotz, top );
|
||||
if( comp == NULL )
|
||||
{
|
||||
comp = new IDF3_COMPONENT( &aIDFBoard );
|
||||
|
||||
if( comp == NULL )
|
||||
throw( std::runtime_error( aIDFBoard.GetError() ) );
|
||||
|
||||
comp->SetRefDes( refdes );
|
||||
|
||||
if( top )
|
||||
comp->SetPosition( aModule->GetPosition().x * scale + dx,
|
||||
-aModule->GetPosition().y * scale + dy,
|
||||
rotz, IDF3::LYR_TOP );
|
||||
else
|
||||
comp->SetPosition( aModule->GetPosition().x * scale + dx,
|
||||
-aModule->GetPosition().y * scale + dy,
|
||||
rotz, IDF3::LYR_BOTTOM );
|
||||
|
||||
comp->SetPlacement( IDF3::PS_ECAD );
|
||||
|
||||
aIDFBoard.AddComponent( comp );
|
||||
}
|
||||
else
|
||||
{
|
||||
double refX, refY, refA;
|
||||
IDF3::IDF_LAYER side;
|
||||
|
||||
if( ! comp->GetPosition( refX, refY, refA, side ) )
|
||||
{
|
||||
// place the item
|
||||
if( top )
|
||||
comp->SetPosition( aModule->GetPosition().x * scale + dx,
|
||||
-aModule->GetPosition().y * scale + dy,
|
||||
rotz, IDF3::LYR_TOP );
|
||||
else
|
||||
comp->SetPosition( aModule->GetPosition().x * scale + dx,
|
||||
-aModule->GetPosition().y * scale + dy,
|
||||
rotz, IDF3::LYR_BOTTOM );
|
||||
}
|
||||
else
|
||||
{
|
||||
// check that the retrieved component matches this one
|
||||
refX = refX - ( aModule->GetPosition().x * scale + dx );
|
||||
refY = refY - ( -aModule->GetPosition().y * scale + dy );
|
||||
refA = refA - rotz;
|
||||
refA *= refA;
|
||||
refX *= refX;
|
||||
refY *= refY;
|
||||
refX += refY;
|
||||
|
||||
// conditions: same side, X,Y coordinates within 10 microns,
|
||||
// angle within 0.01 degree
|
||||
if( ( top && side == IDF3::LYR_BOTTOM ) || ( !top && side == IDF3::LYR_TOP )
|
||||
|| ( refA > 0.0001 ) || ( refX > 0.0001 ) )
|
||||
{
|
||||
comp->GetPosition( refX, refY, refA, side );
|
||||
|
||||
std::ostringstream ostr;
|
||||
ostr << "* " << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
|
||||
ostr << "* conflicting Reference Designator '" << refdes << "'\n";
|
||||
ostr << "* X loc: " << (aModule->GetPosition().x * scale + dx);
|
||||
ostr << " vs. " << refX << "\n";
|
||||
ostr << "* Y loc: " << (-aModule->GetPosition().y * scale + dy);
|
||||
ostr << " vs. " << refY << "\n";
|
||||
ostr << "* angle: " << rotz;
|
||||
ostr << " vs. " << refA << "\n";
|
||||
|
||||
if( top )
|
||||
ostr << "* TOP vs. ";
|
||||
else
|
||||
ostr << "* BOTTOM vs. ";
|
||||
|
||||
if( side == IDF3::LYR_TOP )
|
||||
ostr << "TOP";
|
||||
else
|
||||
ostr << "BOTTOM";
|
||||
|
||||
throw( std::runtime_error( ostr.str() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// create the local data ...
|
||||
IDF3_COMP_OUTLINE_DATA* data = new IDF3_COMP_OUTLINE_DATA( comp, outline );
|
||||
|
||||
data->SetOffsets( locx, locy, locz, lrot );
|
||||
comp->AddOutlineData( data );
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -378,21 +504,45 @@ static void idf_export_module( BOARD* aPcb, MODULE* aModule,
|
|||
* generates IDFv3 compliant board (*.emn) and library (*.emp)
|
||||
* files representing the user's PCB design.
|
||||
*/
|
||||
bool Export_IDF3( BOARD* aPcb, const wxString& aFullFileName, double aUseThou )
|
||||
bool Export_IDF3( BOARD* aPcb, const wxString& aFullFileName, bool aUseThou )
|
||||
{
|
||||
IDF_BOARD idfBoard;
|
||||
IDF3_BOARD idfBoard( IDF3::CAD_ELEC );
|
||||
|
||||
SetLocaleTo_C_standard();
|
||||
|
||||
bool ok = true;
|
||||
double scale = 1e-6; // we must scale internal units to mm for IDF
|
||||
IDF3::IDF_UNIT idfUnit;
|
||||
|
||||
if( aUseThou )
|
||||
{
|
||||
idfUnit = IDF3::UNIT_THOU;
|
||||
idfBoard.SetUserPrecision( 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
idfUnit = IDF3::UNIT_MM;
|
||||
idfBoard.SetUserPrecision( 5 );
|
||||
}
|
||||
|
||||
wxFileName brdName = aPcb->GetFileName();
|
||||
|
||||
idfBoard.SetUserScale( scale );
|
||||
idfBoard.SetBoardThickness( aPcb->GetDesignSettings().GetBoardThickness() * scale );
|
||||
idfBoard.SetBoardName( TO_UTF8( brdName.GetFullName() ) );
|
||||
idfBoard.SetBoardVersion( 0 );
|
||||
idfBoard.SetLibraryVersion( 0 );
|
||||
|
||||
std::ostringstream ostr;
|
||||
ostr << "Created by KiCad " << TO_UTF8( GetBuildVersion() );
|
||||
idfBoard.SetIDFSource( ostr.str() );
|
||||
|
||||
try
|
||||
{
|
||||
idfBoard.Setup( aPcb->GetFileName(), aFullFileName, aUseThou,
|
||||
aPcb->GetDesignSettings().GetBoardThickness() );
|
||||
|
||||
// set up the global offsets
|
||||
EDA_RECT bbox = aPcb->ComputeBoundingBox( true );
|
||||
idfBoard.SetOffset( -bbox.Centre().x * idfBoard.GetScale(),
|
||||
bbox.Centre().y * idfBoard.GetScale() );
|
||||
idfBoard.SetUserOffset( -bbox.Centre().x * scale,
|
||||
bbox.Centre().y * scale );
|
||||
|
||||
// Export the board outline
|
||||
idf_export_outline( aPcb, idfBoard );
|
||||
|
@ -401,15 +551,32 @@ bool Export_IDF3( BOARD* aPcb, const wxString& aFullFileName, double aUseThou )
|
|||
for( MODULE* module = aPcb->m_Modules; module != 0; module = module->Next() )
|
||||
idf_export_module( aPcb, module, idfBoard );
|
||||
|
||||
idfBoard.Finish();
|
||||
if( !idfBoard.WriteFile( aFullFileName, idfUnit, false ) )
|
||||
{
|
||||
wxString msg;
|
||||
msg << _( "IDF Export Failed:\n" ) << FROM_UTF8( idfBoard.GetError().c_str() );
|
||||
wxMessageBox( msg );
|
||||
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
catch( const IO_ERROR& ioe )
|
||||
{
|
||||
wxLogDebug( wxT( "An error occurred attemping export to IDFv3.\n\nError: %s" ),
|
||||
GetChars( ioe.errorText ) );
|
||||
wxString msg;
|
||||
msg << _( "IDF Export Failed:\n" ) << ioe.errorText;
|
||||
wxMessageBox( msg );
|
||||
|
||||
ok = false;
|
||||
}
|
||||
catch( std::exception& e )
|
||||
{
|
||||
wxString msg;
|
||||
msg << _( "IDF Export Failed:\n" ) << FROM_UTF8( e.what() );
|
||||
wxMessageBox( msg );
|
||||
ok = false;
|
||||
}
|
||||
|
||||
SetLocaleTo_Default();
|
||||
|
||||
return true;
|
||||
return ok;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,321 +0,0 @@
|
|||
/**
|
||||
* @file idf.h
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2013-2014 Cirilo Bernardo
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef IDF_H
|
||||
#define IDF_H
|
||||
|
||||
#include <wx/string.h>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <idf_common.h>
|
||||
|
||||
|
||||
/**
|
||||
* @Class IDF_COMP
|
||||
* is responsible for parsing individual component files and rewriting relevant
|
||||
* data to a library file.
|
||||
*/
|
||||
class IDF_COMP
|
||||
{
|
||||
private:
|
||||
/// filename (full path) of the IDF component footprint
|
||||
wxString componentFile;
|
||||
|
||||
/// reference designator; a valid designator or NOREFDES
|
||||
std::string refdes;
|
||||
|
||||
/// overall translation of the part (component location + 3D offset)
|
||||
double loc_x;
|
||||
double loc_y;
|
||||
double loc_z;
|
||||
|
||||
/// overall rotation of the part (3D Z rotation + component rotation)
|
||||
double rotation;
|
||||
|
||||
/// true if the component is on the top of the board
|
||||
bool top;
|
||||
|
||||
/// geometry of the package; for example, HORIZ, VERT, "HORIZ 0.2 inch"
|
||||
std::string geometry;
|
||||
|
||||
/// package name or part number; for example "TO92" or "BC107"
|
||||
std::string partno;
|
||||
|
||||
/// the owning IDF_LIB instance
|
||||
IDF_LIB* parent;
|
||||
|
||||
/**
|
||||
* Function substituteComponent
|
||||
* places a substitute component footprint into the library file
|
||||
* and creates an appropriate entry for the PLACEMENT section
|
||||
* @param aLibFile is the library file to write to
|
||||
* @return bool: true if data was successfully written
|
||||
*/
|
||||
bool substituteComponent( FILE* aLibFile );
|
||||
|
||||
// parse RECORD 2; return TRUE if all is OK, otherwise FALSE
|
||||
bool parseRec2( const std::string aLine, bool& isNewItem );
|
||||
|
||||
// parse RECORD 3; return TRUE if all is OK, otherwise FALSE
|
||||
bool parseRec3( const std::string aLine, int& aLoopIndex,
|
||||
double& aX, double& aY, bool& aClosed );
|
||||
|
||||
public:
|
||||
IDF_COMP( IDF_LIB* aParent );
|
||||
|
||||
/**
|
||||
* Function PlaceComponent
|
||||
* specifies the parameters of an IDF component outline placed on the board
|
||||
* @param aComponentFile is the IDF component file to include
|
||||
* @param aRefDes is the component reference designator; an empty string,
|
||||
* '~' or '0' all default to "NOREFDES".
|
||||
* @param aLocation is the overall translation of the part (board location + 3D offset)
|
||||
* @param aRotation is the overall rotation of the part (component rotation + 3D Z rotation)
|
||||
* @return bool: true if the specified component file exists
|
||||
*/
|
||||
bool PlaceComponent( const wxString aComponentFile, const std::string aRefDes,
|
||||
double aXLoc, double aYLoc, double aZLoc,
|
||||
double aRotation, bool isOnTop );
|
||||
|
||||
/**
|
||||
* Function WriteLib
|
||||
* parses the model file to extract information needed by the
|
||||
* PLACEMENT section and writes data (if necessary) to the
|
||||
* library file
|
||||
* @param aLibFile is the library file to write to
|
||||
* @return bool: true if data was successfully written
|
||||
*/
|
||||
bool WriteLib( FILE* aLibFile );
|
||||
|
||||
/**
|
||||
* Function WritePlacement
|
||||
* write the .PLACEMENT data of the component to the IDF board @param aLayoutFile
|
||||
* @return bool: true if data was successfully written
|
||||
*/
|
||||
bool WritePlacement( FILE* aLayoutFile );
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @Class IDF_LIB
|
||||
* stores information on IDF models ( also has an inbuilt NOMODEL model )
|
||||
* and is responsible for writing the ELECTRICAL sections of the library file
|
||||
* (*.emp) and the PLACEMENT section of the board file.
|
||||
*/
|
||||
class IDF_LIB
|
||||
{
|
||||
/// a list of component outline names and a flag to indicate their save state
|
||||
std::set< std::string > regOutlines;
|
||||
std::list< IDF_COMP* > components;
|
||||
bool libWritten;
|
||||
|
||||
/**
|
||||
* Function writeLib
|
||||
* writes all current library information to the output file
|
||||
*/
|
||||
bool writeLib( FILE* aLibFile );
|
||||
|
||||
/**
|
||||
* Function writeBrd
|
||||
* write placement information to the board file
|
||||
*/
|
||||
bool writeBrd( FILE* aLayoutFile );
|
||||
|
||||
public:
|
||||
virtual ~IDF_LIB();
|
||||
|
||||
/**
|
||||
* Function WriteFiles
|
||||
* writes the library entries to the *.emp file (aLibFile) and the
|
||||
* .PLACEMENT section to the *.emn file (aLayoutFile)
|
||||
* @param aLayoutFile IDF board file
|
||||
* @param aLibFile IDF library file
|
||||
* @return bool: true if all data was written successfully
|
||||
*/
|
||||
bool WriteFiles( FILE* aLayoutFile, FILE* aLibFile );
|
||||
|
||||
/**
|
||||
* Function RegisterOutline
|
||||
* adds the given string to a list of current outline entities.
|
||||
* @param aGeomPartString is a concatenation of the IDF component's
|
||||
* geometry name and part name; this is used as a unique identifier
|
||||
* to prevent redundant entries in the library output.
|
||||
* @return bool: true if the string was already registered,
|
||||
* false if it is a new registration.
|
||||
*/
|
||||
bool RegisterOutline( const std::string aGeomPartString );
|
||||
|
||||
bool PlaceComponent( const wxString aComponentFile, const std::string aRefDes,
|
||||
double aXLoc, double aYLoc, double aZLoc,
|
||||
double aRotation, bool isOnTop );
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @Class IDF_BOARD
|
||||
* contains objects necessary for the maintenance of the IDF board and library files.
|
||||
*/
|
||||
class IDF_BOARD
|
||||
{
|
||||
private:
|
||||
IDF_LIB IDFLib; ///< IDF library manager
|
||||
std::list<IDF_DRILL_DATA*> drills; ///< IDF drill data
|
||||
int outlineIndex; ///< next outline index to use
|
||||
bool useThou; ///< true if output is THOU
|
||||
double scale; ///< scale from KiCad IU to IDF output units
|
||||
double boardThickness; ///< total thickness of the PCB
|
||||
bool hasBrdOutlineHdr; ///< true when a board outline header has been written
|
||||
int refdesIndex; ///< index to generate REFDES for modules which have none
|
||||
|
||||
double offsetX; ///< offset to roughly center the board on the world origin
|
||||
double offsetY;
|
||||
|
||||
FILE* layoutFile; ///< IDF board file (*.emn)
|
||||
FILE* libFile; ///< IDF library file (*.emp)
|
||||
|
||||
/**
|
||||
* Function Write
|
||||
* outputs a .DRILLED_HOLES section compliant with the
|
||||
* IDFv3 specification.
|
||||
* @param aLayoutFile : open file (*.emn) for output
|
||||
*/
|
||||
bool WriteDrills( void );
|
||||
|
||||
public:
|
||||
IDF_BOARD();
|
||||
|
||||
~IDF_BOARD();
|
||||
|
||||
// Set up the output files and scale factor;
|
||||
// return TRUE if everything is OK
|
||||
bool Setup( wxString aBoardName, wxString aFullFileName, bool aUseThou, int aBoardThickness );
|
||||
|
||||
// Finish a board
|
||||
// Write out all current data and close files.
|
||||
// Return true for success
|
||||
bool Finish( void );
|
||||
|
||||
/**
|
||||
* Function GetScale
|
||||
* returns the output scaling factor
|
||||
*/
|
||||
double GetScale( void );
|
||||
|
||||
/**
|
||||
* Function SetOffset
|
||||
* sets the global coordinate offsets
|
||||
*/
|
||||
void SetOffset( double x, double y );
|
||||
|
||||
/**
|
||||
* Function GetOffset
|
||||
* returns the global coordinate offsets
|
||||
*/
|
||||
void GetOffset( double& x, double& y );
|
||||
|
||||
// Add an outline; the very first outline is the board perimeter;
|
||||
// all additional outlines are cutouts.
|
||||
bool AddOutline( IDF_OUTLINE& aOutline );
|
||||
|
||||
/**
|
||||
* Function AddDrill
|
||||
* creates a drill entry and adds it to the list of PCB holes
|
||||
* @param dia : drill diameter
|
||||
* @param x : X coordinate of the drill center
|
||||
* @param y : Y coordinate of the drill center
|
||||
* @param plating : flag, PTH or NPTH
|
||||
* @param refdes : component Reference Designator
|
||||
* @param holetype : purpose of hole
|
||||
* @param owner : one of MCAD, ECAD, UNOWNED
|
||||
*/
|
||||
bool AddDrill( double dia, double x, double y,
|
||||
IDF3::KEY_PLATING plating,
|
||||
const std::string refdes,
|
||||
const std::string holeType,
|
||||
IDF3::KEY_OWNER owner );
|
||||
|
||||
/**
|
||||
* Function AddSlot
|
||||
* creates a slot cutout within the IDF BOARD section; this is a deficient representation
|
||||
* of a KiCad 'oval' drill; IDF is unable to represent a plated slot and unable to
|
||||
* represent the Reference Designator association with a slot.
|
||||
*/
|
||||
bool AddSlot( double aWidth, double aLength, double aOrientation, double aX, double aY );
|
||||
|
||||
bool PlaceComponent( const wxString aComponentFile, const std::string aRefDes,
|
||||
double aXLoc, double aYLoc, double aZLoc,
|
||||
double aRotation, bool isOnTop );
|
||||
|
||||
std::string GetRefDes( void );
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @Class IDF_DRILL_DATA
|
||||
* contains information describing a drilled hole and is responsible for
|
||||
* writing this information to a file in compliance with the IDFv3 specification.
|
||||
*/
|
||||
class IDF_DRILL_DATA
|
||||
{
|
||||
private:
|
||||
double dia;
|
||||
double x;
|
||||
double y;
|
||||
IDF3::KEY_PLATING plating;
|
||||
IDF3::KEY_REFDES kref;
|
||||
IDF3::KEY_HOLETYPE khole;
|
||||
std::string refdes;
|
||||
std::string holetype;
|
||||
IDF3::KEY_OWNER owner;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor IDF_DRILL_DATA
|
||||
* creates a drill entry with information compliant with the
|
||||
* IDFv3 specifications.
|
||||
* @param aDrillDia : drill diameter
|
||||
* @param aPosX : X coordinate of the drill center
|
||||
* @param aPosY : Y coordinate of the drill center
|
||||
* @param aPlating : flag, PTH or NPTH
|
||||
* @param aRefDes : component Reference Designator
|
||||
* @param aHoleType : purpose of hole
|
||||
* @param aOwner : one of MCAD, ECAD, UNOWNED
|
||||
*/
|
||||
IDF_DRILL_DATA( double aDrillDia, double aPosX, double aPosY,
|
||||
IDF3::KEY_PLATING aPlating,
|
||||
const std::string aRefDes,
|
||||
const std::string aHoleType,
|
||||
IDF3::KEY_OWNER aOwner );
|
||||
|
||||
/**
|
||||
* Function Write
|
||||
* writes a single line representing the hole within a .DRILLED_HOLES section
|
||||
*/
|
||||
bool Write( FILE* aLayoutFile );
|
||||
};
|
||||
|
||||
#endif // IDF_H
|
|
@ -1,484 +0,0 @@
|
|||
/**
|
||||
* file: idf_common.cpp
|
||||
*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2013-2014 Cirilo Bernardo
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <cstdio>
|
||||
#include <cmath>
|
||||
#include <richio.h>
|
||||
#include <idf_common.h>
|
||||
#include <build_version.h>
|
||||
|
||||
#ifdef DEBUG_IDF
|
||||
void IDF3::PrintSeg( IDF_SEGMENT* aSegment )
|
||||
{
|
||||
if( aSegment->IsCircle() )
|
||||
{
|
||||
fprintf(stdout, "printSeg(): CIRCLE: C(%.3f, %.3f) P(%.3f, %.3f) rad. %.3f\n",
|
||||
aSegment->startPoint.x, aSegment->startPoint.y,
|
||||
aSegment->endPoint.x, aSegment->endPoint.y,
|
||||
aSegment->radius );
|
||||
return;
|
||||
}
|
||||
|
||||
if( aSegment->angle < -MIN_ANG || aSegment->angle > MIN_ANG )
|
||||
{
|
||||
fprintf(stdout, "printSeg(): ARC: p1(%.3f, %.3f) p2(%.3f, %.3f) ang. %.3f\n",
|
||||
aSegment->startPoint.x, aSegment->startPoint.y,
|
||||
aSegment->endPoint.x, aSegment->endPoint.y,
|
||||
aSegment->angle );
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(stdout, "printSeg(): LINE: p1(%.3f, %.3f) p2(%.3f, %.3f)\n",
|
||||
aSegment->startPoint.x, aSegment->startPoint.y,
|
||||
aSegment->endPoint.x, aSegment->endPoint.y );
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool IDF_POINT::Matches( const IDF_POINT& aPoint, double aRadius )
|
||||
{
|
||||
double dx = x - aPoint.x;
|
||||
double dy = y - aPoint.y;
|
||||
|
||||
double d2 = dx * dx + dy * dy;
|
||||
|
||||
if( d2 <= aRadius * aRadius )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
double IDF_POINT::CalcDistance( const IDF_POINT& aPoint ) const
|
||||
{
|
||||
double dx = aPoint.x - x;
|
||||
double dy = aPoint.y - y;
|
||||
double dist = sqrt( dx * dx + dy * dy );
|
||||
|
||||
return dist;
|
||||
}
|
||||
|
||||
|
||||
double IDF3::CalcAngleRad( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint )
|
||||
{
|
||||
return atan2( aEndPoint.y - aStartPoint.y, aEndPoint.x - aStartPoint.x );
|
||||
}
|
||||
|
||||
|
||||
double IDF3::CalcAngleDeg( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint )
|
||||
{
|
||||
double ang = CalcAngleRad( aStartPoint, aEndPoint );
|
||||
|
||||
// round to thousandths of a degree
|
||||
int iang = int (ang / M_PI * 1800000.0);
|
||||
|
||||
ang = iang / 10000.0;
|
||||
|
||||
return ang;
|
||||
}
|
||||
|
||||
|
||||
void IDF3::GetOutline( std::list<IDF_SEGMENT*>& aLines,
|
||||
IDF_OUTLINE& aOutline )
|
||||
{
|
||||
aOutline.Clear();
|
||||
|
||||
// NOTE: To tell if the point order is CCW or CW,
|
||||
// sum all: (endPoint.X[n] - startPoint.X[n])*(endPoint[n] + startPoint.Y[n])
|
||||
// If the result is >0, the direction is CW, otherwise
|
||||
// it is CCW. Note that the result cannot be 0 unless
|
||||
// we have a bounded area of 0.
|
||||
|
||||
// First we find the segment with the leftmost point
|
||||
std::list<IDF_SEGMENT*>::iterator bl = aLines.begin();
|
||||
std::list<IDF_SEGMENT*>::iterator el = aLines.end();
|
||||
std::list<IDF_SEGMENT*>::iterator idx = bl++; // iterator for the object with minX
|
||||
|
||||
double minx = (*idx)->GetMinX();
|
||||
double curx;
|
||||
|
||||
while( bl != el )
|
||||
{
|
||||
curx = (*bl)->GetMinX();
|
||||
|
||||
if( curx < minx )
|
||||
{
|
||||
minx = curx;
|
||||
idx = bl;
|
||||
}
|
||||
|
||||
++bl;
|
||||
}
|
||||
|
||||
aOutline.push( *idx );
|
||||
#ifdef DEBUG_IDF
|
||||
PrintSeg( *idx );
|
||||
#endif
|
||||
aLines.erase( idx );
|
||||
|
||||
// If the item is a circle then we're done
|
||||
if( aOutline.front()->IsCircle() )
|
||||
return;
|
||||
|
||||
// Assemble the loop
|
||||
bool complete = false; // set if loop is complete
|
||||
bool matched; // set if a segment's end point was matched
|
||||
|
||||
while( !complete )
|
||||
{
|
||||
matched = false;
|
||||
bl = aLines.begin();
|
||||
el = aLines.end();
|
||||
|
||||
while( bl != el && !matched )
|
||||
{
|
||||
if( (*bl)->MatchesStart( aOutline.back()->endPoint ) )
|
||||
{
|
||||
if( (*bl)->IsCircle() )
|
||||
{
|
||||
// a circle on the perimeter is pathological but we just ignore it
|
||||
++bl;
|
||||
}
|
||||
else
|
||||
{
|
||||
matched = true;
|
||||
#ifdef DEBUG_IDF
|
||||
PrintSeg( *bl );
|
||||
#endif
|
||||
aOutline.push( *bl );
|
||||
aLines.erase( bl );
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
++bl;
|
||||
}
|
||||
|
||||
if( !matched )
|
||||
{
|
||||
// attempt to match the end points
|
||||
bl = aLines.begin();
|
||||
el = aLines.end();
|
||||
|
||||
while( bl != el && !matched )
|
||||
{
|
||||
if( (*bl)->MatchesEnd( aOutline.back()->endPoint ) )
|
||||
{
|
||||
if( (*bl)->IsCircle() )
|
||||
{
|
||||
// a circle on the perimeter is pathological but we just ignore it
|
||||
++bl;
|
||||
}
|
||||
else
|
||||
{
|
||||
matched = true;
|
||||
(*bl)->SwapEnds();
|
||||
#ifdef DEBUG_IDF
|
||||
printSeg( *bl );
|
||||
#endif
|
||||
aOutline.push( *bl );
|
||||
aLines.erase( bl );
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
++bl;
|
||||
}
|
||||
}
|
||||
|
||||
if( !matched )
|
||||
{
|
||||
// still no match - attempt to close the loop
|
||||
if( (aOutline.size() > 1) || ( aOutline.front()->angle < -MIN_ANG )
|
||||
|| ( aOutline.front()->angle > MIN_ANG ) )
|
||||
{
|
||||
// close the loop
|
||||
IDF_SEGMENT* seg = new IDF_SEGMENT( aOutline.back()->endPoint,
|
||||
aOutline.front()->startPoint );
|
||||
|
||||
if( seg )
|
||||
{
|
||||
complete = true;
|
||||
#ifdef DEBUG_IDF
|
||||
printSeg( seg );
|
||||
#endif
|
||||
aOutline.push( seg );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// the outline is bad; drop the segments
|
||||
aOutline.Clear();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// check if the loop is complete
|
||||
if( aOutline.front()->MatchesStart( aOutline.back()->endPoint ) )
|
||||
{
|
||||
complete = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
IDF_SEGMENT::IDF_SEGMENT()
|
||||
{
|
||||
angle = 0.0;
|
||||
offsetAngle = 0.0;
|
||||
radius = 0.0;
|
||||
}
|
||||
|
||||
|
||||
IDF_SEGMENT::IDF_SEGMENT( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint )
|
||||
{
|
||||
angle = 0.0;
|
||||
offsetAngle = 0.0;
|
||||
radius = 0.0;
|
||||
startPoint = aStartPoint;
|
||||
endPoint = aEndPoint;
|
||||
}
|
||||
|
||||
|
||||
IDF_SEGMENT::IDF_SEGMENT( const IDF_POINT& aStartPoint,
|
||||
const IDF_POINT& aEndPoint,
|
||||
double aAngle,
|
||||
bool aFromKicad )
|
||||
{
|
||||
double diff = abs( aAngle ) - 360.0;
|
||||
|
||||
if( ( diff < MIN_ANG
|
||||
&& diff > -MIN_ANG ) || ( aAngle < MIN_ANG && aAngle > -MIN_ANG ) || (!aFromKicad) )
|
||||
{
|
||||
angle = 0.0;
|
||||
startPoint = aStartPoint;
|
||||
endPoint = aEndPoint;
|
||||
|
||||
if( diff < MIN_ANG && diff > -MIN_ANG )
|
||||
{
|
||||
angle = 360.0;
|
||||
center = aStartPoint;
|
||||
offsetAngle = 0.0;
|
||||
radius = aStartPoint.CalcDistance( aEndPoint );
|
||||
}
|
||||
else if( aAngle < MIN_ANG && aAngle > -MIN_ANG )
|
||||
{
|
||||
CalcCenterAndRadius();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// we need to convert from the KiCad arc convention
|
||||
angle = aAngle;
|
||||
|
||||
center = aStartPoint;
|
||||
|
||||
offsetAngle = IDF3::CalcAngleDeg( aStartPoint, aEndPoint );
|
||||
|
||||
radius = aStartPoint.CalcDistance( aEndPoint );
|
||||
|
||||
startPoint = aEndPoint;
|
||||
|
||||
double ang = offsetAngle + aAngle;
|
||||
ang = (ang / 180.0) * M_PI;
|
||||
|
||||
endPoint.x = ( radius * cos( ang ) ) + center.x;
|
||||
endPoint.y = ( radius * sin( ang ) ) + center.y;
|
||||
}
|
||||
|
||||
|
||||
bool IDF_SEGMENT::MatchesStart( const IDF_POINT& aPoint, double aRadius )
|
||||
{
|
||||
return startPoint.Matches( aPoint, aRadius );
|
||||
}
|
||||
|
||||
|
||||
bool IDF_SEGMENT::MatchesEnd( const IDF_POINT& aPoint, double aRadius )
|
||||
{
|
||||
return endPoint.Matches( aPoint, aRadius );
|
||||
}
|
||||
|
||||
|
||||
void IDF_SEGMENT::CalcCenterAndRadius( void )
|
||||
{
|
||||
// NOTE: this routine does not check if the points are the same
|
||||
// or too close to be sensible in a production setting.
|
||||
|
||||
double offAng = IDF3::CalcAngleRad( startPoint, endPoint );
|
||||
double d = startPoint.CalcDistance( endPoint ) / 2.0;
|
||||
double xm = ( startPoint.x + endPoint.x ) * 0.5;
|
||||
double ym = ( startPoint.y + endPoint.y ) * 0.5;
|
||||
|
||||
radius = d / sin( angle * M_PI / 180.0 );
|
||||
|
||||
if( radius < 0.0 )
|
||||
{
|
||||
radius = -radius;
|
||||
}
|
||||
|
||||
// calculate the height of the triangle with base d and hypotenuse r
|
||||
double dh2 = radius * radius - d * d;
|
||||
|
||||
if( dh2 < 0 )
|
||||
{
|
||||
// this should only ever happen due to rounding errors when r == d
|
||||
dh2 = 0;
|
||||
}
|
||||
|
||||
double h = sqrt( dh2 );
|
||||
|
||||
if( angle > 0.0 )
|
||||
offAng += M_PI2;
|
||||
else
|
||||
offAng -= M_PI2;
|
||||
|
||||
if( ( angle > M_PI ) || ( angle < -M_PI ) )
|
||||
offAng += M_PI;
|
||||
|
||||
center.x = h * cos( offAng ) + xm;
|
||||
center.y = h * sin( offAng ) + ym;
|
||||
|
||||
offsetAngle = IDF3::CalcAngleDeg( center, startPoint );
|
||||
}
|
||||
|
||||
|
||||
bool IDF_SEGMENT::IsCircle( void )
|
||||
{
|
||||
double diff = abs( angle ) - 360.0;
|
||||
|
||||
if( ( diff < MIN_ANG ) && ( diff > -MIN_ANG ) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
double IDF_SEGMENT::GetMinX( void )
|
||||
{
|
||||
if( angle == 0.0 )
|
||||
return std::min( startPoint.x, endPoint.x );
|
||||
|
||||
// Calculate the leftmost point of the circle or arc
|
||||
|
||||
if( IsCircle() )
|
||||
{
|
||||
// if only everything were this easy
|
||||
return center.x - radius;
|
||||
}
|
||||
|
||||
// cases:
|
||||
// 1. CCW arc: if offset + included angle >= 180 deg then
|
||||
// MinX = center.x - radius, otherwise MinX is the
|
||||
// same as for the case of a line.
|
||||
// 2. CW arc: if offset + included angle <= -180 deg then
|
||||
// MinX = center.x - radius, otherwise MinX is the
|
||||
// same as for the case of a line.
|
||||
|
||||
if( angle > 0 )
|
||||
{
|
||||
// CCW case
|
||||
if( ( offsetAngle + angle ) >= 180.0 )
|
||||
{
|
||||
return center.x - radius;
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::min( startPoint.x, endPoint.x );
|
||||
}
|
||||
}
|
||||
|
||||
// CW case
|
||||
if( ( offsetAngle + angle ) <= -180.0 )
|
||||
{
|
||||
return center.x - radius;
|
||||
}
|
||||
|
||||
return std::min( startPoint.x, endPoint.x );
|
||||
}
|
||||
|
||||
|
||||
void IDF_SEGMENT::SwapEnds( void )
|
||||
{
|
||||
if( IsCircle() )
|
||||
{
|
||||
// reverse the direction
|
||||
angle = -angle;
|
||||
return;
|
||||
}
|
||||
|
||||
IDF_POINT tmp = startPoint;
|
||||
startPoint = endPoint;
|
||||
endPoint = tmp;
|
||||
|
||||
if( ( angle < MIN_ANG ) && ( angle > -MIN_ANG ) )
|
||||
return; // nothing more to do
|
||||
|
||||
// change the direction of the arc
|
||||
angle = -angle;
|
||||
// calculate the new offset angle
|
||||
offsetAngle = IDF3::CalcAngleDeg( center, startPoint );
|
||||
}
|
||||
|
||||
|
||||
void IDF_OUTLINE::push( IDF_SEGMENT* item )
|
||||
{
|
||||
if( !outline.empty() )
|
||||
{
|
||||
if( item->IsCircle() )
|
||||
{
|
||||
// not allowed
|
||||
wxString msg = wxT( "INVALID GEOMETRY: a circle is being added to a non-empty outline" );
|
||||
THROW_IO_ERROR( msg );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( outline.back()->IsCircle() )
|
||||
{
|
||||
// we can't add lines to a circle
|
||||
wxString msg = wxT( "INVALID GEOMETRY: a line is being added to a circular outline" );
|
||||
THROW_IO_ERROR( msg );
|
||||
}
|
||||
else if( !item->MatchesStart( outline.back()->endPoint ) )
|
||||
{
|
||||
// startPoint[N] != endPoint[N -1]
|
||||
wxString msg = wxT( "INVALID GEOMETRY: disjoint segments" );
|
||||
THROW_IO_ERROR( msg );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outline.push_back( item );
|
||||
dir += ( outline.back()->endPoint.x - outline.back()->startPoint.x )
|
||||
* ( outline.back()->endPoint.y + outline.back()->startPoint.y );
|
||||
}
|
|
@ -1,290 +0,0 @@
|
|||
/**
|
||||
* @file idf_common.h
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2013-2014 Cirilo Bernardo
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef IDF_COMMON_H
|
||||
#define IDF_COMMON_H
|
||||
|
||||
#include <list>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.1415926535897932384626433832795028841
|
||||
#endif
|
||||
|
||||
#ifndef M_PI2
|
||||
#define M_PI2 ( M_PI / 2.0 )
|
||||
#endif
|
||||
|
||||
#ifndef M_PI4
|
||||
#define M_PI4 ( M_PI / 4.0 )
|
||||
#endif
|
||||
|
||||
// differences in angle smaller than MIN_ANG are considered equal
|
||||
#define MIN_ANG (0.01)
|
||||
|
||||
class IDF_POINT;
|
||||
class IDF_SEGMENT;
|
||||
class IDF_DRILL_DATA;
|
||||
class IDF_OUTLINE;
|
||||
class IDF_LIB;
|
||||
|
||||
namespace IDF3 {
|
||||
enum KEY_OWNER
|
||||
{
|
||||
UNOWNED = 0, // < either MCAD or ECAD may modify a feature
|
||||
MCAD, // < only MCAD may modify a feature
|
||||
ECAD // < only ECAD may modify a feature
|
||||
};
|
||||
|
||||
enum KEY_HOLETYPE
|
||||
{
|
||||
PIN = 0, // < drill hole is for a pin
|
||||
VIA, // < drill hole is for a via
|
||||
MTG, // < drill hole is for mounting
|
||||
TOOL, // < drill hole is for tooling
|
||||
OTHER // < user has specified a custom type
|
||||
};
|
||||
|
||||
enum KEY_PLATING
|
||||
{
|
||||
PTH = 0, // < Plate-Through Hole
|
||||
NPTH // < Non-Plate-Through Hole
|
||||
};
|
||||
|
||||
enum KEY_REFDES
|
||||
{
|
||||
BOARD = 0, // < feature is associated with the board
|
||||
NOREFDES, // < feature is associated with a component with no RefDes
|
||||
PANEL, // < feature is associated with an IDF panel
|
||||
REFDES // < reference designator as assigned by the CAD software
|
||||
};
|
||||
|
||||
// calculate the angle between the horizon and the segment aStartPoint to aEndPoint
|
||||
double CalcAngleRad( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint );
|
||||
double CalcAngleDeg( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint );
|
||||
|
||||
// take contiguous elements from 'lines' and stuff them into 'outline'
|
||||
void GetOutline( std::list<IDF_SEGMENT*>& aLines,
|
||||
IDF_OUTLINE& aOutline );
|
||||
|
||||
#ifdef DEBUG_IDF
|
||||
// prints out segment information for debug purposes
|
||||
void PrintSeg( IDF_SEGMENT* aSegment );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @Class IDF_POINT
|
||||
* represents a point
|
||||
*/
|
||||
class IDF_POINT
|
||||
{
|
||||
public:
|
||||
double x; // < X coordinate
|
||||
double y; // < Y coordinate
|
||||
|
||||
IDF_POINT()
|
||||
{
|
||||
x = 0.0;
|
||||
y = 0.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function Matches()
|
||||
* returns true if the given coordinate point is within the given radius
|
||||
* of the point.
|
||||
* @param aPoint : coordinates of the point being compared
|
||||
* @param aRadius : radius within which the points are considered the same
|
||||
*/
|
||||
bool Matches( const IDF_POINT& aPoint, double aRadius = 1e-5 );
|
||||
double CalcDistance( const IDF_POINT& aPoint ) const;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @Class IDF_SEGMENT
|
||||
* represents a geometry segment as used in IDFv3 outlines
|
||||
*/
|
||||
class IDF_SEGMENT
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* Function CalcCenterAndRadius()
|
||||
* Calculates the center, radius, and angle between center and start point given the
|
||||
* IDF compliant points and included angle.
|
||||
* @var startPoint, @var endPoint, and @var angle must be set prior as per IDFv3
|
||||
*/
|
||||
void CalcCenterAndRadius( void );
|
||||
|
||||
public:
|
||||
IDF_POINT startPoint; // starting point in IDF coordinates
|
||||
IDF_POINT endPoint; // end point in IDF coordinates
|
||||
IDF_POINT center; // center of an arc or circle; used primarily for calculating min X
|
||||
double angle; // included angle (degrees) according to IDFv3 specification
|
||||
double offsetAngle; // angle between center and start of arc; used to speed up some calcs.
|
||||
double radius; // radius of the arc or circle; used to speed up some calcs.
|
||||
|
||||
/**
|
||||
* Function IDF_SEGMENT()
|
||||
* initializes the internal variables
|
||||
*/
|
||||
IDF_SEGMENT();
|
||||
|
||||
/**
|
||||
* Function IDF_SEGMENT( start, end )
|
||||
* creates a straight segment
|
||||
*/
|
||||
IDF_SEGMENT( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint );
|
||||
|
||||
/**
|
||||
* Function IDF_SEGMENT( start, end )
|
||||
* creates a straight segment, arc, or circle depending on the angle
|
||||
* @param aStartPoint : start point (center if using KiCad convention, otherwise IDF convention)
|
||||
* @param aEndPoint : end point (start of arc if using KiCad convention, otherwise IDF convention)
|
||||
* @param aAngle : included angle; the KiCad convention is equivalent to the IDF convention
|
||||
* @param fromKicad : set true if we need to convert from KiCad to IDF convention
|
||||
*/
|
||||
IDF_SEGMENT( const IDF_POINT& aStartPoint,
|
||||
const IDF_POINT& aEndPoint,
|
||||
double aAngle,
|
||||
bool aFromKicad );
|
||||
|
||||
/**
|
||||
* Function MatchesStart()
|
||||
* returns true if the given coordinate is within a radius 'rad'
|
||||
* of the start point.
|
||||
* @param aPoint : coordinates of the point being compared
|
||||
* @param aRadius : radius within which the points are considered the same
|
||||
*/
|
||||
bool MatchesStart( const IDF_POINT& aPoint, double aRadius = 1e-3 );
|
||||
|
||||
/**
|
||||
* Function MatchesEnd()
|
||||
* returns true if the given coordinate is within a radius 'rad'
|
||||
* of the end point.
|
||||
* @param aPoint : coordinates of the point being compared
|
||||
* @param aRadius : radius within which the points are considered the same
|
||||
*/
|
||||
bool MatchesEnd( const IDF_POINT& aPoint, double aRadius = 1e-3 );
|
||||
|
||||
/**
|
||||
* Function IsCircle()
|
||||
* returns true if this segment is a circle
|
||||
*/
|
||||
bool IsCircle( void );
|
||||
|
||||
/**
|
||||
* Function GetMinX()
|
||||
* returns the minimum X coordinate of this segment
|
||||
*/
|
||||
double GetMinX( void );
|
||||
|
||||
/**
|
||||
* Function SwapEnds()
|
||||
* Swaps the start and end points and alters internal
|
||||
* variables as necessary for arcs
|
||||
*/
|
||||
void SwapEnds( void );
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @Class IDF_OUTLINE
|
||||
* contains segment and winding information for an IDF outline
|
||||
*/
|
||||
class IDF_OUTLINE
|
||||
{
|
||||
private:
|
||||
double dir;
|
||||
std::list<IDF_SEGMENT*> outline;
|
||||
|
||||
public:
|
||||
IDF_OUTLINE() { dir = 0.0; }
|
||||
~IDF_OUTLINE() { Clear(); }
|
||||
|
||||
// returns true if the current list of points represents a counterclockwise winding
|
||||
bool IsCCW( void )
|
||||
{
|
||||
if( dir > 0.0 )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// clears the internal list of outline segments
|
||||
void Clear( void )
|
||||
{
|
||||
dir = 0.0;
|
||||
|
||||
while( !outline.empty() )
|
||||
{
|
||||
delete outline.front();
|
||||
outline.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
// returns the size of the internal segment list
|
||||
size_t size( void )
|
||||
{
|
||||
return outline.size();
|
||||
}
|
||||
|
||||
// returns true if the internal segment list is empty
|
||||
bool empty( void )
|
||||
{
|
||||
return outline.empty();
|
||||
}
|
||||
|
||||
// return the front() of the internal segment list
|
||||
IDF_SEGMENT*& front( void )
|
||||
{
|
||||
return outline.front();
|
||||
}
|
||||
|
||||
// return the back() of the internal segment list
|
||||
IDF_SEGMENT*& back( void )
|
||||
{
|
||||
return outline.back();
|
||||
}
|
||||
|
||||
// return the begin() iterator of the internal segment list
|
||||
std::list<IDF_SEGMENT*>::iterator begin( void )
|
||||
{
|
||||
return outline.begin();
|
||||
}
|
||||
|
||||
// return the end() iterator of the internal segment list
|
||||
std::list<IDF_SEGMENT*>::iterator end( void )
|
||||
{
|
||||
return outline.end();
|
||||
}
|
||||
|
||||
// push a segment onto the internal list
|
||||
void push( IDF_SEGMENT* item );
|
||||
};
|
||||
|
||||
#endif // IDF_COMMON_H
|
|
@ -0,0 +1,45 @@
|
|||
.HEADER
|
||||
BOARD_FILE 3.0 "Created by some software" 2014/02/01.15:09:15 1
|
||||
"test_donut" MM
|
||||
.END_HEADER
|
||||
|
||||
# The board outline is a simple square with a small hole in it
|
||||
.BOARD_OUTLINE ECAD
|
||||
1.60000
|
||||
0 -100 100 0
|
||||
0 -100 -100 0
|
||||
0 100 -100 0
|
||||
0 100 100 0
|
||||
0 -100 100 0
|
||||
1 0 0 0
|
||||
1 5 0 360
|
||||
.END_BOARD_OUTLINE
|
||||
|
||||
# This OTHER OUTLINE is a square toroid
|
||||
.OTHER_OUTLINE UNOWNED
|
||||
MY_DONUT 30 TOP
|
||||
0 0 0 0
|
||||
0 75 0 360
|
||||
1 0 0 0
|
||||
1 30 0 360
|
||||
.END_OTHER_OUTLINE
|
||||
|
||||
# This OTHER OUTLINE is a square with a hole
|
||||
.OTHER_OUTLINE UNOWNED
|
||||
MY_NOT_DONUT 2 BOTTOM
|
||||
0 -50 50 0
|
||||
0 -50 -50 0
|
||||
0 50 -50 0
|
||||
0 50 50 0
|
||||
0 -50 50 0
|
||||
1 0 0 0
|
||||
1 10 0 360
|
||||
2 0 50 0
|
||||
2 0 75 360
|
||||
3 50 0 0
|
||||
3 75 0 360
|
||||
4 0 -50 0
|
||||
4 0 -75 360
|
||||
5 -50 0 0
|
||||
5 -75 0 360
|
||||
.END_OTHER_OUTLINE
|
|
@ -0,0 +1,5 @@
|
|||
.HEADER
|
||||
LIBRARY_FILE 3.0 "Created by some software" 2014/02/01.15:09:15 1
|
||||
.END_HEADER
|
||||
|
||||
# This file contains no component outlines
|
|
@ -693,6 +693,10 @@ void BOARD_OUTLINE::writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutli
|
|||
std::list<IDF_SEGMENT*>::iterator bo;
|
||||
std::list<IDF_SEGMENT*>::iterator eo;
|
||||
|
||||
if( !aOutline )
|
||||
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
|
||||
"\n* BUG: NULL outline pointer" ) );
|
||||
|
||||
if( aOutline->size() == 1 )
|
||||
{
|
||||
if( !aOutline->front()->IsCircle() )
|
||||
|
|
|
@ -36,6 +36,48 @@
|
|||
using namespace std;
|
||||
using namespace IDF3;
|
||||
|
||||
|
||||
static bool MatchCompOutline( IDF3_COMP_OUTLINE* aOutlineA, IDF3_COMP_OUTLINE* aOutlineB )
|
||||
{
|
||||
if( aOutlineA->GetComponentClass() != aOutlineB->GetComponentClass() )
|
||||
return false;
|
||||
|
||||
if( aOutlineA->OutlinesSize() != aOutlineB->OutlinesSize() )
|
||||
return false;
|
||||
|
||||
// are both outlines empty?
|
||||
if( aOutlineA->OutlinesSize() == 0 )
|
||||
return true;
|
||||
|
||||
IDF_OUTLINE* opA = aOutlineA->GetOutline( 0 );
|
||||
IDF_OUTLINE* opB = aOutlineB->GetOutline( 0 );
|
||||
|
||||
if( opA->size() != opB->size() )
|
||||
return false;
|
||||
|
||||
if( opA->size() == 0 )
|
||||
return true;
|
||||
|
||||
std::list<IDF_SEGMENT*>::iterator olAs = opA->begin();
|
||||
std::list<IDF_SEGMENT*>::iterator olAe = opA->end();
|
||||
std::list<IDF_SEGMENT*>::iterator olBs = opB->begin();
|
||||
|
||||
while( olAs != olAe )
|
||||
{
|
||||
if( !(*olAs)->MatchesStart( (*olBs)->startPoint ) )
|
||||
return false;
|
||||
|
||||
if( !(*olAs)->MatchesEnd( (*olBs)->endPoint ) )
|
||||
return false;
|
||||
|
||||
++olAs;
|
||||
++olBs;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CLASS: IDF3_COMP_OUTLINE_DATA
|
||||
* This represents the outline placement
|
||||
|
@ -285,7 +327,7 @@ bool IDF3_COMP_OUTLINE_DATA::readPlaceData( std::ifstream &aBoardFile,
|
|||
// component is given a unique RefDes. This class of defect
|
||||
// is one reason IDF does not work well in faithfully
|
||||
// conveying information between ECAD and MCAD.
|
||||
refdes = token;
|
||||
refdes = aBoard->GetNewRefDes();
|
||||
}
|
||||
else if( CompareToken( "BOARD", token ) )
|
||||
{
|
||||
|
@ -1297,6 +1339,7 @@ IDF3_BOARD::IDF3_BOARD( IDF3::CAD_TYPE aCadType )
|
|||
userYoff = 0.0;
|
||||
brdFileVersion = 0;
|
||||
libFileVersion = 0;
|
||||
iRefDes = 0;
|
||||
|
||||
// unlike other outlines which are created as necessary,
|
||||
// the board outline always exists and its parent must
|
||||
|
@ -1314,6 +1357,18 @@ IDF3_BOARD::~IDF3_BOARD()
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
const std::string& IDF3_BOARD::GetNewRefDes( void )
|
||||
{
|
||||
ostringstream ostr;
|
||||
ostr << "NOREFDESn" << iRefDes++;
|
||||
|
||||
sRefDes = ostr.str();
|
||||
|
||||
return sRefDes;
|
||||
}
|
||||
|
||||
|
||||
#ifndef DISABLE_IDF_OWNERSHIP
|
||||
bool IDF3_BOARD::checkComponentOwnership( int aSourceLine, const char* aSourceFunc,
|
||||
IDF3_COMPONENT* aComponent )
|
||||
|
@ -2421,8 +2476,13 @@ void IDF3_BOARD::readLibSection( std::ifstream& aLibFile, IDF3::FILE_STATE& aLib
|
|||
compOutlines.insert( pair<const std::string, IDF3_COMP_OUTLINE*>( pout->GetUID(), pout ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( MatchCompOutline( pout, cop ) )
|
||||
{
|
||||
delete pout;
|
||||
// everything is fine; the outlines are genuine duplicates
|
||||
return;
|
||||
}
|
||||
|
||||
ostringstream ostr;
|
||||
ostr << "invalid IDF library\n";
|
||||
|
@ -3131,7 +3191,7 @@ bool IDF3_BOARD::SetBoardVersion( int aVersion )
|
|||
{
|
||||
ostringstream ostr;
|
||||
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
|
||||
ostr << "* board version (" << aVersion << ") must be > 0";
|
||||
ostr << "* board version (" << aVersion << ") must be >= 0";
|
||||
errormsg = ostr.str();
|
||||
|
||||
return false;
|
||||
|
@ -3155,7 +3215,7 @@ bool IDF3_BOARD::SetLibraryVersion( int aVersion )
|
|||
{
|
||||
ostringstream ostr;
|
||||
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
|
||||
ostr << "* library version (" << aVersion << ") must be > 0";
|
||||
ostr << "* library version (" << aVersion << ") must be >= 0";
|
||||
errormsg = ostr.str();
|
||||
|
||||
return false;
|
||||
|
@ -3741,39 +3801,13 @@ IDF3_COMPONENT* IDF3_BOARD::FindComponent( std::string aRefDes )
|
|||
|
||||
// returns a pointer to a component outline object or NULL
|
||||
// if the object doesn't exist
|
||||
IDF3_COMP_OUTLINE* IDF3_BOARD::GetComponentOutline( const std::string aGeomName,
|
||||
const std::string aPartName,
|
||||
wxString aFullFileName )
|
||||
IDF3_COMP_OUTLINE* IDF3_BOARD::GetComponentOutline( wxString aFullFileName )
|
||||
{
|
||||
std::ostringstream ostr;
|
||||
ostr << aGeomName << "_" << aPartName;
|
||||
|
||||
IDF3_COMP_OUTLINE* cp = GetComponentOutline( ostr.str() );
|
||||
|
||||
if( cp != NULL )
|
||||
return cp;
|
||||
|
||||
std::string fname = TO_UTF8( aFullFileName );
|
||||
|
||||
cp = new IDF3_COMP_OUTLINE( this );
|
||||
|
||||
if( cp == NULL )
|
||||
{
|
||||
ostringstream ostr;
|
||||
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): \n";
|
||||
cerr << "* failed to create outline with UID '" << aGeomName << "_";
|
||||
cerr << aPartName << "'\n";
|
||||
cerr << "* filename: '" << fname << "'";
|
||||
errormsg = ostr.str();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wxFileName idflib( aFullFileName );
|
||||
|
||||
if( !idflib.IsOk() )
|
||||
{
|
||||
delete cp;
|
||||
ostringstream ostr;
|
||||
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): \n";
|
||||
cerr << "* invalid file name: '" << fname << "'";
|
||||
|
@ -3784,7 +3818,6 @@ IDF3_COMP_OUTLINE* IDF3_BOARD::GetComponentOutline( const std::string aGeomName,
|
|||
|
||||
if( !idflib.FileExists() )
|
||||
{
|
||||
delete cp;
|
||||
ostringstream ostr;
|
||||
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): \n";
|
||||
cerr << "* no such file: '" << fname << "'";
|
||||
|
@ -3795,7 +3828,6 @@ IDF3_COMP_OUTLINE* IDF3_BOARD::GetComponentOutline( const std::string aGeomName,
|
|||
|
||||
if( !idflib.IsFileReadable() )
|
||||
{
|
||||
delete cp;
|
||||
ostringstream ostr;
|
||||
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): \n";
|
||||
cerr << "* cannot read file: '" << fname << "'";
|
||||
|
@ -3804,6 +3836,24 @@ IDF3_COMP_OUTLINE* IDF3_BOARD::GetComponentOutline( const std::string aGeomName,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
std::map< std::string, std::string >::iterator itm = uidFileList.find( fname );
|
||||
|
||||
if( itm != uidFileList.end() )
|
||||
return GetComponentOutline( itm->second );
|
||||
|
||||
IDF3_COMP_OUTLINE* cp = new IDF3_COMP_OUTLINE( this );
|
||||
|
||||
if( cp == NULL )
|
||||
{
|
||||
ostringstream ostr;
|
||||
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): \n";
|
||||
cerr << "* failed to create outline\n";
|
||||
cerr << "* filename: '" << fname << "'";
|
||||
errormsg = ostr.str();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::ifstream model;
|
||||
model.exceptions ( std::ifstream::badbit );
|
||||
|
||||
|
@ -3867,7 +3917,92 @@ IDF3_COMP_OUTLINE* IDF3_BOARD::GetComponentOutline( const std::string aGeomName,
|
|||
|
||||
model.close();
|
||||
|
||||
// check the unique ID against the list from library components
|
||||
std::list< std::string >::iterator lsts = uidLibList.begin();
|
||||
std::list< std::string >::iterator lste = uidLibList.end();
|
||||
std::string uid = cp->GetUID();
|
||||
IDF3_COMP_OUTLINE* oldp = NULL;
|
||||
|
||||
while( lsts != lste )
|
||||
{
|
||||
if( ! lsts->compare( uid ) )
|
||||
{
|
||||
oldp = GetComponentOutline( uid );
|
||||
|
||||
if( MatchCompOutline( cp, oldp ) )
|
||||
{
|
||||
// everything is fine; the outlines are genuine duplicates; delete the copy
|
||||
delete cp;
|
||||
// make sure we can find the item via its filename
|
||||
uidFileList.insert( std::pair< std::string, std::string>( fname, uid ) );
|
||||
// return the pointer to the original
|
||||
return oldp;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete cp;
|
||||
ostringstream ostr;
|
||||
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
|
||||
ostr << "* duplicate UID for different Component Outlines: '" << uid << "'\n";
|
||||
ostr << "* original loaded from library, duplicate in current file\n";
|
||||
ostr << "* file: '" << fname << "'";
|
||||
|
||||
errormsg = ostr.str();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
++lsts;
|
||||
}
|
||||
|
||||
// if we got this far then any duplicates are from files previously read
|
||||
oldp = GetComponentOutline( uid );
|
||||
|
||||
if( oldp == NULL )
|
||||
{
|
||||
// everything is fine, there are no existing entries
|
||||
uidFileList.insert( std::pair< std::string, std::string>( fname, uid ) );
|
||||
compOutlines.insert( pair<const std::string, IDF3_COMP_OUTLINE*>( uid, cp ) );
|
||||
|
||||
return cp;
|
||||
}
|
||||
|
||||
if( MatchCompOutline( cp, oldp ) )
|
||||
{
|
||||
// everything is fine; the outlines are genuine duplicates; delete the copy
|
||||
delete cp;
|
||||
// make sure we can find the item via its other filename
|
||||
uidFileList.insert( std::pair< std::string, std::string>( fname, uid ) );
|
||||
// return the pointer to the original
|
||||
return oldp;
|
||||
}
|
||||
|
||||
delete cp;
|
||||
|
||||
// determine the file name of the first instance
|
||||
std::map< std::string, std::string >::iterator ufls = uidFileList.begin();
|
||||
std::map< std::string, std::string >::iterator ufle = uidFileList.end();
|
||||
std::string oldfname;
|
||||
|
||||
while( ufls != ufle )
|
||||
{
|
||||
if( ! ufls->second.compare( uid ) )
|
||||
{
|
||||
oldfname = ufls->first;
|
||||
break;
|
||||
}
|
||||
|
||||
++ufls;
|
||||
}
|
||||
|
||||
ostringstream ostr;
|
||||
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
|
||||
ostr << "* duplicate UID for different Component Outlines: '" << uid << "'\n";
|
||||
ostr << "* original file: '" << oldfname << "'\n";
|
||||
ostr << "* this file: '" << fname << "'";
|
||||
|
||||
errormsg = ostr.str();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -3940,8 +4075,12 @@ void IDF3_BOARD::Clear( void )
|
|||
libSource.clear();
|
||||
brdDate.clear();
|
||||
libDate.clear();
|
||||
uidFileList.clear();
|
||||
uidLibList.clear();
|
||||
brdFileVersion = 0;
|
||||
libFileVersion = 0;
|
||||
iRefDes = 0;
|
||||
sRefDes.clear();
|
||||
|
||||
// delete comment lists
|
||||
noteComments.clear();
|
||||
|
|
|
@ -463,6 +463,8 @@ public:
|
|||
class IDF3_BOARD
|
||||
{
|
||||
private:
|
||||
std::map< std::string, std::string > uidFileList; // map of files opened and UIDs
|
||||
std::list< std::string > uidLibList; // list of UIDs read from a library file
|
||||
std::string errormsg; // string for passing error messages to user
|
||||
std::list< IDF_NOTE* > notes; // IDF notes
|
||||
std::list< std::string > noteComments; // comment list for NOTES section
|
||||
|
@ -476,6 +478,8 @@ private:
|
|||
IDF3::CAD_TYPE cadType;
|
||||
IDF3::IDF_UNIT unit;
|
||||
IDF3::IDF_VERSION idfVer; // IDF version of Board or Library
|
||||
int iRefDes; // counter for automatically numbered NOREFDES items
|
||||
std::string sRefDes;
|
||||
|
||||
std::string idfSource; // SOURCE string to use when writing BOARD and LIBRARY headers
|
||||
std::string brdSource; // SOURCE string as retrieved from a BOARD file
|
||||
|
@ -569,6 +573,8 @@ public:
|
|||
// end user must use only mm in the API.
|
||||
IDF3::IDF_UNIT GetUnit( void );
|
||||
|
||||
const std::string& GetNewRefDes( void );
|
||||
|
||||
void SetBoardName( std::string aBoardName );
|
||||
const std::string& GetBoardName( void );
|
||||
|
||||
|
@ -692,9 +698,7 @@ public:
|
|||
|
||||
// returns a pointer to a component outline object or NULL
|
||||
// if the object doesn't exist
|
||||
IDF3_COMP_OUTLINE* GetComponentOutline( const std::string aGeomName,
|
||||
const std::string aPartName,
|
||||
wxString aFullFileName );
|
||||
IDF3_COMP_OUTLINE* GetComponentOutline( wxString aFullFileName );
|
||||
|
||||
// returns a pointer to the component outline object with the
|
||||
// unique ID aComponentID
|
||||
|
|
|
@ -23,17 +23,6 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* NOTES ON OUTPUT PRECISION:
|
||||
*
|
||||
* If we use %.6f then we have no need for special unit dependent formatting:
|
||||
*
|
||||
* inch: .0254 microns
|
||||
* mm: 0.001 microns
|
||||
* m: 1 micron
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <iomanip>
|
||||
|
|
Loading…
Reference in New Issue