Commit 7a110d0c authored by unknown's avatar unknown Committed by jean-pierre charras

IDF tools: code cleanup and debugging

parent 60a86853
......@@ -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
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/**
* @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
.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
.HEADER
LIBRARY_FILE 3.0 "Created by some software" 2014/02/01.15:09:15 1
.END_HEADER
# This file contains no component outlines
\ No newline at end of file
......@@ -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 )
......@@ -2422,7 +2477,12 @@ void IDF3_BOARD::readLibSection( std::ifstream& aLibFile, IDF3::FILE_STATE& aLib
}
else
{
delete pout;
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,64 +3801,54 @@ 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 );
wxFileName idflib( aFullFileName );
cp = new IDF3_COMP_OUTLINE( this );
if( cp == NULL )
if( !idflib.IsOk() )
{
ostringstream ostr;
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): \n";
cerr << "* failed to create outline with UID '" << aGeomName << "_";
cerr << aPartName << "'\n";
cerr << "* filename: '" << fname << "'";
cerr << "* invalid file name: '" << fname << "'";
errormsg = ostr.str();
return NULL;
}
wxFileName idflib( aFullFileName );
if( !idflib.IsOk() )
if( !idflib.FileExists() )
{
delete cp;
ostringstream ostr;
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): \n";
cerr << "* invalid file name: '" << fname << "'";
cerr << "* no such file: '" << fname << "'";
errormsg = ostr.str();
return NULL;
}
if( !idflib.FileExists() )
if( !idflib.IsFileReadable() )
{
delete cp;
ostringstream ostr;
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): \n";
cerr << "* no such file: '" << fname << "'";
cerr << "* cannot read file: '" << fname << "'";
errormsg = ostr.str();
return NULL;
}
if( !idflib.IsFileReadable() )
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 )
{
delete cp;
ostringstream ostr;
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): \n";
cerr << "* cannot read file: '" << fname << "'";
cerr << "* failed to create outline\n";
cerr << "* filename: '" << fname << "'";
errormsg = ostr.str();
return NULL;
......@@ -3867,7 +3917,92 @@ IDF3_COMP_OUTLINE* IDF3_BOARD::GetComponentOutline( const std::string aGeomName,
model.close();
return cp;
// 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>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment