IDF code housekeeping.

This commit is contained in:
Wayne Stambaugh 2021-07-27 17:24:40 -04:00
parent c0f12cf8b0
commit 05a5a2416a
11 changed files with 1264 additions and 1379 deletions

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014 Cirilo Bernardo
* Copyright (C) 2018-2020 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2018-2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -36,6 +36,7 @@
#define MIN_BULGE 0.002
#define MAX_BULGE 2000.0
DXF2IDF::~DXF2IDF()
{
while( !lines.empty() )
@ -71,7 +72,6 @@ void DXF2IDF::addLine( const DL_LineData& aData )
p2.y = aData.y2 * m_scale;
insertLine( p1, p2 );
return;
}
@ -89,8 +89,6 @@ void DXF2IDF::addCircle( const DL_CircleData& aData )
if( seg )
lines.push_back( seg );
return;
}
@ -116,8 +114,6 @@ void DXF2IDF::addArc( const DL_ArcData& aData )
if( seg )
lines.push_back( seg );
return;
}
@ -156,24 +152,22 @@ bool DXF2IDF::WriteOutline( FILE* aFile, bool isInch )
return false;
}
// NOTE: a circle always has an angle of 360, never -360,
// otherwise SolidWorks chokes on the file.
if( isInch )
{
fprintf( aFile, "%c %d %d 0\n", loopDir,
(int) (1000 * outline.front()->startPoint.x),
(int) (1000 * outline.front()->startPoint.y) );
fprintf( aFile, "%c %d %d 360\n", loopDir,
(int) (1000 * outline.front()->endPoint.x),
(int) (1000 * outline.front()->endPoint.y) );
}
else
{
fprintf( aFile, "%c %.3f %.3f 0\n", loopDir,
outline.front()->startPoint.x, outline.front()->startPoint.y );
fprintf( aFile, "%c %.3f %.3f 360\n", loopDir,
outline.front()->endPoint.x, outline.front()->endPoint.y );
}
// NOTE: a circle always has an angle of 360, never -360,
// otherwise SolidWorks chokes on the file.
if( isInch )
{
fprintf( aFile, "%c %d %d 0\n", loopDir, (int) ( 1000 * outline.front()->startPoint.x ),
(int) ( 1000 * outline.front()->startPoint.y ) );
fprintf( aFile, "%c %d %d 360\n", loopDir, (int) ( 1000 * outline.front()->endPoint.x ),
(int) ( 1000 * outline.front()->endPoint.y ) );
}
else
{
fprintf( aFile, "%c %.3f %.3f 0\n", loopDir, outline.front()->startPoint.x,
outline.front()->startPoint.y );
fprintf( aFile, "%c %.3f %.3f 360\n", loopDir, outline.front()->endPoint.x,
outline.front()->endPoint.y );
}
return true;
}
@ -185,43 +179,37 @@ bool DXF2IDF::WriteOutline( FILE* aFile, bool isInch )
eo = outline.end();
// for the first item we write out both points
if( (*bo)->angle < MIN_ANG && (*bo)->angle > -MIN_ANG )
if( ( *bo )->angle < MIN_ANG && ( *bo )->angle > -MIN_ANG )
{
if( isInch )
{
fprintf( aFile, "%c %d %d 0\n", loopDir,
(int) (1000 * (*bo)->startPoint.x),
(int) (1000 * (*bo)->startPoint.y) );
fprintf( aFile, "%c %d %d 0\n", loopDir,
(int) (1000 * (*bo)->endPoint.x),
(int) (1000 * (*bo)->endPoint.y) );
fprintf( aFile, "%c %d %d 0\n", loopDir, (int) ( 1000 * ( *bo )->startPoint.x ),
(int) ( 1000 * ( *bo )->startPoint.y ) );
fprintf( aFile, "%c %d %d 0\n", loopDir, (int) ( 1000 * ( *bo )->endPoint.x ),
(int) ( 1000 * ( *bo )->endPoint.y ) );
}
else
{
fprintf( aFile, "%c %.3f %.3f 0\n", loopDir,
(*bo)->startPoint.x, (*bo)->startPoint.y );
fprintf( aFile, "%c %.3f %.3f 0\n", loopDir,
(*bo)->endPoint.x, (*bo)->endPoint.y );
fprintf( aFile, "%c %.3f %.3f 0\n", loopDir, ( *bo )->startPoint.x,
( *bo )->startPoint.y );
fprintf( aFile, "%c %.3f %.3f 0\n", loopDir, ( *bo )->endPoint.x, ( *bo )->endPoint.y );
}
}
else
{
if( isInch )
{
fprintf( aFile, "%c %d %d 0\n", loopDir,
(int) (1000 * (*bo)->startPoint.x),
(int) (1000 * (*bo)->startPoint.y) );
fprintf( aFile, "%c %d %d %.2f\n", loopDir,
(int) (1000 * (*bo)->endPoint.x),
(int) (1000 * (*bo)->endPoint.y),
(*bo)->angle );
fprintf( aFile, "%c %d %d 0\n", loopDir, (int) ( 1000 * ( *bo )->startPoint.x ),
(int) ( 1000 * ( *bo )->startPoint.y ) );
fprintf( aFile, "%c %d %d %.2f\n", loopDir, (int) ( 1000 * ( *bo )->endPoint.x ),
(int) ( 1000 * ( *bo )->endPoint.y ), ( *bo )->angle );
}
else
{
fprintf( aFile, "%c %.3f %.3f 0\n", loopDir,
(*bo)->startPoint.x, (*bo)->startPoint.y );
fprintf( aFile, "%c %.3f %.3f %.2f\n", loopDir,
(*bo)->endPoint.x, (*bo)->endPoint.y, (*bo)->angle );
fprintf( aFile, "%c %.3f %.3f 0\n", loopDir, ( *bo )->startPoint.x,
( *bo )->startPoint.y );
fprintf( aFile, "%c %.3f %.3f %.2f\n", loopDir, ( *bo )->endPoint.x,
( *bo )->endPoint.y, ( *bo )->angle );
}
}
@ -232,31 +220,28 @@ bool DXF2IDF::WriteOutline( FILE* aFile, bool isInch )
{
if( isInch )
{
if( (*bo)->angle < MIN_ANG && (*bo)->angle > -MIN_ANG )
if( ( *bo )->angle < MIN_ANG && ( *bo )->angle > -MIN_ANG )
{
fprintf( aFile, "%c %d %d 0\n", loopDir,
(int) (1000 * (*bo)->endPoint.x),
(int) (1000 * (*bo)->endPoint.y) );
fprintf( aFile, "%c %d %d 0\n", loopDir, (int) ( 1000 * ( *bo )->endPoint.x ),
(int) ( 1000 * ( *bo )->endPoint.y ) );
}
else
{
fprintf( aFile, "%c %d %d %.2f\n", loopDir,
(int) (1000 * (*bo)->endPoint.x),
(int) (1000 * (*bo)->endPoint.y),
(*bo)->angle );
fprintf( aFile, "%c %d %d %.2f\n", loopDir, (int) ( 1000 * ( *bo )->endPoint.x ),
(int) ( 1000 * ( *bo )->endPoint.y ), ( *bo )->angle );
}
}
else
{
if( (*bo)->angle < MIN_ANG && (*bo)->angle > -MIN_ANG )
if( ( *bo )->angle < MIN_ANG && ( *bo )->angle > -MIN_ANG )
{
fprintf( aFile, "%c %.5f %.5f 0\n", loopDir,
(*bo)->endPoint.x, (*bo)->endPoint.y );
fprintf( aFile, "%c %.5f %.5f 0\n", loopDir, ( *bo )->endPoint.x,
( *bo )->endPoint.y );
}
else
{
fprintf( aFile, "%c %.5f %.5f %.2f\n", loopDir,
(*bo)->endPoint.x, (*bo)->endPoint.y, (*bo)->angle );
fprintf( aFile, "%c %.5f %.5f %.2f\n", loopDir, ( *bo )->endPoint.x,
( *bo )->endPoint.y, ( *bo )->angle );
}
}
@ -336,8 +321,6 @@ void DXF2IDF::setVariableInt( const std::string& key, int value, int code )
m_scale = 1.0;
break;
}
return;
}
}
@ -400,20 +383,16 @@ void DXF2IDF::endEntity()
}
void DXF2IDF::insertLine( const IDF_POINT& aSegStart, const IDF_POINT& aSegEnd )
{
IDF_SEGMENT* seg = new IDF_SEGMENT( aSegStart, aSegEnd );
if( seg )
lines.push_back( seg );
return;
}
void DXF2IDF::insertArc( const IDF_POINT& aSegStart, const IDF_POINT& aSegEnd,
double aBulge )
void DXF2IDF::insertArc( const IDF_POINT& aSegStart, const IDF_POINT& aSegEnd, double aBulge )
{
if( aBulge < -MAX_BULGE )
aBulge = -MAX_BULGE;
@ -426,6 +405,4 @@ void DXF2IDF::insertArc( const IDF_POINT& aSegStart, const IDF_POINT& aSegEnd,
if( seg )
lines.push_back( seg );
return;
}

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014 Cirilo Bernardo
* Copyright (C) 2018 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2018-2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -32,22 +32,6 @@
class DXF2IDF : public DL_CreationAdapter
{
private:
std::list< IDF_SEGMENT* > lines; // Unsorted list of graphical segments
double m_scale; // scaling factor to mm
int m_entityType; // the DXF type of entity
int m_entityParseStatus; // Inside a entity: status od parsing:
// 0 = no entity
// 1 = first item of entity
// 2 = entity in progress
int m_entity_flags; // state of flags read from last entity
IDF_POINT m_lastCoordinate; // the last vertex coordinate read (unit = mm)
IDF_POINT m_polylineStart; // The first point of the polyline entity, when reading a polyline (unit = mm)
double m_bulgeVertex; // the last vertex bulge value read
void insertLine( const IDF_POINT& aSegStart, const IDF_POINT& aSegEnd );
void insertArc( const IDF_POINT& aSegStart, const IDF_POINT& aSegEnd, double aBulge );
public:
DXF2IDF() : m_scale( 1.0 ), m_entityType( 0 ), m_entityParseStatus( 0 ),
m_entity_flags( 0 ), m_bulgeVertex( 0.0 ) {};
@ -62,14 +46,17 @@ private:
virtual void addArc( const DL_ArcData& aData ) override;
virtual void addCircle( const DL_CircleData& aData ) override;
virtual void addPolyline( const DL_PolylineData& aData ) override;
/** Called for every polyline vertex */
/**
* Called for every polyline vertex.
*/
virtual void addVertex( const DL_VertexData& aData ) override;
/**
* Called for every string variable in the DXF file (e.g. "$ACADVER").
*/
virtual void setVariableString( const std::string& key, const std::string& value,
int code ) override {};
int code ) override {};
/**
* Called for every int variable in the DXF file (e.g. "$ACADMAINTVER").
@ -82,6 +69,24 @@ private:
virtual void setVariableDouble( const std::string& key, double value, int code ) override {}
virtual void endEntity() override;
private:
std::list< IDF_SEGMENT* > lines; // Unsorted list of graphical segments
double m_scale; // scaling factor to mm
int m_entityType; // the DXF type of entity
int m_entityParseStatus; // Inside a entity: status of parsing:
// 0 = no entity
// 1 = first item of entity
// 2 = entity in progress
int m_entity_flags; // state of flags read from last entity
IDF_POINT m_lastCoordinate; // the last vertex coordinate read (unit = mm)
// The first point of the polyline entity, when reading a polyline (unit = mm).
IDF_POINT m_polylineStart;
double m_bulgeVertex; // the last vertex bulge value read
void insertLine( const IDF_POINT& aSegStart, const IDF_POINT& aSegEnd );
void insertArc( const IDF_POINT& aSegStart, const IDF_POINT& aSegEnd, double aBulge );
};
#endif // DXF2IDF_H

View File

@ -1,7 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014 Cirilo Bernardo
* Copyright (C) 2014 Cirilo Bernardo
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -61,6 +62,7 @@ int main( int argc, char **argv )
}
line.clear();
while( line.empty() || line.find( ".dxf" ) == string::npos )
{
cout << "* DXF filename: ";
@ -68,9 +70,11 @@ int main( int argc, char **argv )
line.clear();
std::getline( cin, line );
}
dname = line;
line.clear();
while( line.compare( "mm" ) && line.compare( "in" )
&& line.compare( "MM" ) && line.compare( "IN" ) )
{
@ -83,6 +87,7 @@ int main( int argc, char **argv )
inch = true;
line.clear();
while( line.empty() )
{
cout << "* Geometry name: ";
@ -95,9 +100,11 @@ int main( int argc, char **argv )
line.clear();
}
}
gname = line;
line.clear();
while( line.empty() )
{
cout << "* Part name: ";
@ -110,9 +117,11 @@ int main( int argc, char **argv )
line.clear();
}
}
pname = line;
ok = false;
while( !ok )
{
cout << "* Height: ";
@ -124,6 +133,7 @@ int main( int argc, char **argv )
tstr.str( line );
tstr >> height;
if( !tstr.fail() && height > 0.001 )
ok = true;
}
@ -131,6 +141,7 @@ int main( int argc, char **argv )
cout << "* COMMENTS: any non-blank line is a comment;\n";
cout << " a blank line signifies the end of comments.\n";
ok = false;
while( !ok )
{
line.clear();
@ -150,6 +161,7 @@ int main( int argc, char **argv )
}
line.clear();
while( line.empty() || line.find( ".idf" ) == string::npos )
{
cout << "* File name (*.idf): ";
@ -176,15 +188,14 @@ int main( int argc, char **argv )
fprintf( fp, ".ELECTRICAL\n" );
if( inch )
fprintf( fp, "\"%s\" \"%s\" THOU %d\n", gname.c_str(),
pname.c_str(), (int) (height * 1000.0) );
fprintf( fp, "\"%s\" \"%s\" THOU %d\n", gname.c_str(), pname.c_str(),
(int) ( height * 1000.0 ) );
else
fprintf( fp, "\"%s\" \"%s\" MM %.3f\n", gname.c_str(),
pname.c_str(), height );
fprintf( fp, "\"%s\" \"%s\" MM %.3f\n", gname.c_str(), pname.c_str(), height );
dxf.WriteOutline( fp, inch );
fprintf( fp, ".END_ELECTRICAL\n" );
return 0;
}
}

View File

@ -1,9 +1,10 @@
/**
/*
* file: idf_common.cpp
*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013-2017 Cirilo Bernardo
* Copyright (C) 2013-2017 Cirilo Bernardo
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -62,8 +63,6 @@ IDF_ERROR::IDF_ERROR( const char* aSourceFile, const char* aSourceMethod, int aS
ostr << aMessage;
message = ostr.str();
return;
}
@ -122,7 +121,8 @@ bool IDF_NOTE::readNote( std::istream& aBoardFile, IDF3::FILE_STATE& aBoardState
aBoardState = IDF3::FILE_INVALID;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"invalid IDFv3 file\n"
"* Violation of specification: X position in NOTES section must not be in quotes" ) );
"* Violation of specification: X position in NOTES section must not be "
"in quotes" ) );
}
if( CompareToken( ".END_NOTES", token ) )
@ -132,12 +132,14 @@ bool IDF_NOTE::readNote( std::istream& aBoardFile, IDF3::FILE_STATE& aBoardState
istr.str( token );
istr >> xpos;
if( istr.fail() )
{
aBoardState = IDF3::FILE_INVALID;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"invalid IDFv3 file\n"
"* Violation of specification: X position in NOTES section is not numeric" ) );
"* Violation of specification: X position in NOTES section is not "
"numeric" ) );
}
if( !GetIDFString( iline, token, quoted, idx ) )
@ -145,7 +147,8 @@ bool IDF_NOTE::readNote( std::istream& aBoardFile, IDF3::FILE_STATE& aBoardState
aBoardState = IDF3::FILE_INVALID;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"invalid IDFv3 file\n"
"* Violation of specification: Y position in NOTES section is missing" ) );
"* Violation of specification: Y position in NOTES section is "
"missing" ) );
}
if( quoted )
@ -153,19 +156,22 @@ bool IDF_NOTE::readNote( std::istream& aBoardFile, IDF3::FILE_STATE& aBoardState
aBoardState = IDF3::FILE_INVALID;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"invalid IDFv3 file\n"
"* Violation of specification: Y position in NOTES section must not be in quotes" ) );
"* Violation of specification: Y position in NOTES section must not be "
"in quotes" ) );
}
istr.clear();
istr.str( token );
istr >> ypos;
if( istr.fail() )
{
aBoardState = IDF3::FILE_INVALID;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"invalid IDFv3 file\n"
"* Violation of specification: Y position in NOTES section is not numeric" ) );
"* Violation of specification: Y position in NOTES section is not "
"numeric" ) );
}
if( !GetIDFString( iline, token, quoted, idx ) )
@ -173,7 +179,8 @@ bool IDF_NOTE::readNote( std::istream& aBoardFile, IDF3::FILE_STATE& aBoardState
aBoardState = IDF3::FILE_INVALID;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"invalid IDFv3 file\n"
"* Violation of specification: text height in NOTES section is missing" ) );
"* Violation of specification: text height in NOTES section is "
"missing" ) );
}
if( quoted )
@ -181,19 +188,22 @@ bool IDF_NOTE::readNote( std::istream& aBoardFile, IDF3::FILE_STATE& aBoardState
aBoardState = IDF3::FILE_INVALID;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"invalid IDFv3 file\n"
"* Violation of specification: text height in NOTES section must not be in quotes" ) );
"* Violation of specification: text height in NOTES section must not "
"be in quotes" ) );
}
istr.clear();
istr.str( token );
istr >> height;
if( istr.fail() )
{
aBoardState = IDF3::FILE_INVALID;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"invalid IDFv3 file\n"
"* Violation of specification: text height in NOTES section is not numeric" ) );
"* Violation of specification: text height in NOTES section is not "
"numeric" ) );
}
if( !GetIDFString( iline, token, quoted, idx ) )
@ -201,7 +211,8 @@ bool IDF_NOTE::readNote( std::istream& aBoardFile, IDF3::FILE_STATE& aBoardState
aBoardState = IDF3::FILE_INVALID;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"invalid IDFv3 file\n"
"* Violation of specification: text length in NOTES section is missing" ) );
"* Violation of specification: text length in NOTES section is "
"missing" ) );
}
if( quoted )
@ -209,19 +220,22 @@ bool IDF_NOTE::readNote( std::istream& aBoardFile, IDF3::FILE_STATE& aBoardState
aBoardState = IDF3::FILE_INVALID;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"invalid IDFv3 file\n"
"* Violation of specification: text length in NOTES section must not be in quotes" ) );
"* Violation of specification: text length in NOTES section must not "
"be in quotes" ) );
}
istr.clear();
istr.str( token );
istr >> length;
if( istr.fail() )
{
aBoardState = IDF3::FILE_INVALID;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"invalid IDFv3 file\n"
"* Violation of specification: text length in NOTES section is not numeric" ) );
"* Violation of specification: text length in NOTES section is not "
"numeric" ) );
}
if( !GetIDFString( iline, token, quoted, idx ) )
@ -229,7 +243,8 @@ bool IDF_NOTE::readNote( std::istream& aBoardFile, IDF3::FILE_STATE& aBoardState
aBoardState = IDF3::FILE_INVALID;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"invalid IDFv3 file\n"
"* Violation of specification: text value in NOTES section is missing" ) );
"* Violation of specification: text value in NOTES section is "
"missing" ) );
}
text = token;
@ -250,16 +265,14 @@ bool IDF_NOTE::writeNote( std::ostream& aBoardFile, IDF3::IDF_UNIT aBoardUnit )
{
if( aBoardUnit == UNIT_THOU )
{
aBoardFile << setiosflags(ios::fixed) << setprecision(1)
<< (xpos / IDF_THOU_TO_MM) << " "
<< (ypos / IDF_THOU_TO_MM) << " "
<< (height / IDF_THOU_TO_MM) << " "
<< (length / IDF_THOU_TO_MM) << " ";
aBoardFile << setiosflags( ios::fixed ) << setprecision( 1 ) << ( xpos / IDF_THOU_TO_MM )
<< " " << ( ypos / IDF_THOU_TO_MM ) << " " << ( height / IDF_THOU_TO_MM ) << " "
<< ( length / IDF_THOU_TO_MM ) << " ";
}
else
{
aBoardFile << setiosflags(ios::fixed) << setprecision(5)
<< xpos << " " << ypos << " " << height << " " << length << " ";
aBoardFile << setiosflags( ios::fixed ) << setprecision( 5 ) << xpos << " " << ypos << " "
<< height << " " << length << " ";
}
aBoardFile << "\"" << text << "\"\n";
@ -273,29 +286,34 @@ void IDF_NOTE::SetText( const std::string& aText )
text = aText;
}
void IDF_NOTE::SetPosition( double aXpos, double aYpos )
{
xpos = aXpos;
ypos = aYpos;
}
void IDF_NOTE::SetSize( double aHeight, double aLength )
{
height = aHeight;
length = aLength;
}
const std::string& IDF_NOTE::GetText()
{
return text;
}
void IDF_NOTE::GetPosition( double& aXpos, double& aYpos )
{
aXpos = xpos;
aYpos = ypos;
}
void IDF_NOTE::GetSize( double& aHeight, double& aLength )
{
aHeight = height;
@ -303,9 +321,6 @@ void IDF_NOTE::GetSize( double& aHeight, double& aLength )
}
/*
* IDF_DRILL_DATA
*/
IDF_DRILL_DATA::IDF_DRILL_DATA() :
dia( 0.0 ),
x( 0.0 ),
@ -319,10 +334,8 @@ IDF_DRILL_DATA::IDF_DRILL_DATA() :
IDF_DRILL_DATA::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 )
IDF3::KEY_PLATING aPlating, const std::string& aRefDes,
const std::string& aHoleType, IDF3::KEY_OWNER aOwner )
{
if( aDrillDia < 0.3 )
dia = 0.3;
@ -374,7 +387,8 @@ IDF_DRILL_DATA::IDF_DRILL_DATA( double aDrillDia, double aPosX, double aPosY,
}
owner = aOwner;
} // IDF_DRILL_DATA::IDF_DRILL_DATA( ... )
}
bool IDF_DRILL_DATA::Matches( double aDrillDia, double aPosX, double aPosY ) const
{
@ -392,6 +406,7 @@ bool IDF_DRILL_DATA::Matches( double aDrillDia, double aPosX, double aPosY ) con
return false;
}
bool IDF_DRILL_DATA::read( std::istream& aBoardFile, IDF3::IDF_UNIT aBoardUnit,
IDF3::FILE_STATE aBoardState, IDF3::IDF_VERSION aIdfVersion )
{
@ -415,7 +430,8 @@ bool IDF_DRILL_DATA::read( std::istream& aBoardFile, IDF3::IDF_UNIT aBoardUnit,
{
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"invalid IDF file\n"
"* Violation of specification: comment within a section (DRILLED HOLES)" ) );
"* Violation of specification: comment within a section (DRILLED "
"HOLES)" ) );
}
idx = 0;
@ -435,6 +451,7 @@ bool IDF_DRILL_DATA::read( std::istream& aBoardFile, IDF3::IDF_UNIT aBoardUnit,
istr.str( token );
istr >> dia;
if( istr.fail() )
{
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
@ -464,18 +481,21 @@ bool IDF_DRILL_DATA::read( std::istream& aBoardFile, IDF3::IDF_UNIT aBoardUnit,
{
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"invalid IDF file\n"
"* Violation of specification: X position in DRILLED HOLES section must not be in quotes" ) );
"* Violation of specification: X position in DRILLED HOLES section "
"must not be in quotes" ) );
}
istr.clear();
istr.str( token );
istr >> x;
if( istr.fail() )
{
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"invalid IDF file\n"
"* Violation of specification: X position in DRILLED HOLES section is not numeric" ) );
"* Violation of specification: X position in DRILLED HOLES section is "
"not numeric" ) );
}
if( !GetIDFString( iline, token, quoted, idx ) )
@ -489,18 +509,21 @@ bool IDF_DRILL_DATA::read( std::istream& aBoardFile, IDF3::IDF_UNIT aBoardUnit,
{
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"invalid IDF file\n"
"* Violation of specification: Y position in DRILLED HOLES section must not be in quotes" ) );
"* Violation of specification: Y position in DRILLED HOLES section "
"must not be in quotes" ) );
}
istr.clear();
istr.str( token );
istr >> y;
if( istr.fail() )
{
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"invalid IDF file\n"
"* Violation of specification: Y position in DRILLED HOLES section is not numeric" ) );
"* Violation of specification: Y position in DRILLED HOLES section is "
"not numeric" ) );
}
if( aIdfVersion > IDF_V2 )
@ -546,7 +569,8 @@ bool IDF_DRILL_DATA::read( std::istream& aBoardFile, IDF3::IDF_UNIT aBoardUnit,
{
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"invalid IDFv2 file\n"
"* Violation of specification: missing HOLE TYPE for drilled hole" ) );
"* Violation of specification: missing HOLE TYPE for drilled "
"hole" ) );
}
}
@ -558,7 +582,8 @@ bool IDF_DRILL_DATA::read( std::istream& aBoardFile, IDF3::IDF_UNIT aBoardUnit,
{
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"invalid IDFv3 file\n"
"* Violation of specification: missing HOLE TYPE for drilled hole" ) );
"* Violation of specification: missing HOLE TYPE for drilled "
"hole" ) );
}
else
{
@ -631,7 +656,8 @@ bool IDF_DRILL_DATA::read( std::istream& aBoardFile, IDF3::IDF_UNIT aBoardUnit,
{
ostringstream ostr;
ostr << "invalid IDFv3 file\n";
ostr << "* Violation of specification: invalid OWNER for drilled hole ('" << token << "')";
ostr << "* Violation of specification: invalid OWNER for drilled hole ('" << token
<< "')";
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
@ -664,6 +690,7 @@ bool IDF_DRILL_DATA::read( std::istream& aBoardFile, IDF3::IDF_UNIT aBoardUnit,
return true;
}
void IDF_DRILL_DATA::write( std::ostream& aBoardFile, IDF3::IDF_UNIT aBoardUnit )
{
std::string holestr;
@ -673,19 +700,19 @@ void IDF_DRILL_DATA::write( std::ostream& aBoardFile, IDF3::IDF_UNIT aBoardUnit
switch( khole )
{
case PIN: holestr = "PIN"; break;
case VIA: holestr = "VIA"; break;
case TOOL: holestr = "TOOL"; break;
case OTHER: holestr = "\"" + holetype + "\""; break;
default: holestr = "MTG"; break;
case PIN: holestr = "PIN"; break;
case VIA: holestr = "VIA"; break;
case TOOL: holestr = "TOOL"; break;
case OTHER: holestr = "\"" + holetype + "\""; break;
default: holestr = "MTG"; break;
}
switch( kref )
{
case BOARD: refstr = "BOARD"; break;
case PANEL: refstr = "PANEL"; break;
case REFDES: refstr = "\"" + refdes + "\""; break;
default: refstr = "NOREFDES"; break;
case BOARD: refstr = "BOARD"; break;
case PANEL: refstr = "PANEL"; break;
case REFDES: refstr = "\"" + refdes + "\""; break;
default: refstr = "NOREFDES"; break;
}
if( plating == PTH )
@ -695,26 +722,26 @@ void IDF_DRILL_DATA::write( std::ostream& aBoardFile, IDF3::IDF_UNIT aBoardUnit
switch( owner )
{
case MCAD: ownstr = "MCAD"; break;
case ECAD: ownstr = "ECAD"; break;
default: ownstr = "UNOWNED"; break;
case MCAD: ownstr = "MCAD"; break;
case ECAD: ownstr = "ECAD"; break;
default: ownstr = "UNOWNED"; break;
}
if( aBoardUnit == UNIT_MM )
{
aBoardFile << std::setiosflags( std::ios::fixed ) << std::setprecision( 3 ) << dia << " "
<< std::setprecision( 5 ) << x << " " << y << " "
<< pltstr.c_str() << " " << refstr.c_str() << " "
<< holestr.c_str() << " " << ownstr.c_str() << "\n";
<< std::setprecision( 5 ) << x << " " << y << " " << pltstr.c_str() << " "
<< refstr.c_str() << " " << holestr.c_str() << " " << ownstr.c_str() << "\n";
}
else
{
aBoardFile << std::setiosflags( std::ios::fixed ) << std::setprecision( 1 ) << (dia / IDF_THOU_TO_MM) << " "
<< std::setprecision( 1 ) << (x / IDF_THOU_TO_MM) << " " << (y / IDF_THOU_TO_MM) << " "
<< pltstr.c_str() << " " << refstr.c_str() << " "
<< holestr.c_str() << " " << ownstr.c_str() << "\n";
aBoardFile << std::setiosflags( std::ios::fixed ) << std::setprecision( 1 )
<< ( dia / IDF_THOU_TO_MM ) << " " << std::setprecision( 1 )
<< ( x / IDF_THOU_TO_MM ) << " " << ( y / IDF_THOU_TO_MM ) << " "
<< pltstr.c_str() << " " << refstr.c_str() << " " << holestr.c_str() << " "
<< ownstr.c_str() << "\n";
}
} // IDF_DRILL_DATA::Write( aBoardFile, unitMM )
}
double IDF_DRILL_DATA::GetDrillDia() const
@ -722,43 +749,48 @@ double IDF_DRILL_DATA::GetDrillDia() const
return dia;
}
double IDF_DRILL_DATA::GetDrillXPos() const
{
return x;
}
double IDF_DRILL_DATA::GetDrillYPos() const
{
return y;
}
IDF3::KEY_PLATING IDF_DRILL_DATA::GetDrillPlating()
{
return plating;
}
const std::string& IDF_DRILL_DATA::GetDrillRefDes()
{
switch( kref )
{
case BOARD: refdes = "BOARD"; break;
case PANEL: refdes = "PANEL"; break;
case REFDES: break;
default: refdes = "NOREFDES"; break;
case BOARD: refdes = "BOARD"; break;
case PANEL: refdes = "PANEL"; break;
case REFDES: break;
default: refdes = "NOREFDES"; break;
}
return refdes;
}
const std::string& IDF_DRILL_DATA::GetDrillHoleType()
{
switch( khole )
{
case PIN: holetype = "PIN"; break;
case VIA: holetype = "VIA"; break;
case TOOL: holetype = "TOOL"; break;
case OTHER: break;
default: holetype = "MTG"; break;
case PIN: holetype = "PIN"; break;
case VIA: holetype = "VIA"; break;
case TOOL: holetype = "TOOL"; break;
case OTHER: break;
default: holetype = "MTG"; break;
}
return holetype;
@ -770,25 +802,22 @@ 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 );
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 );
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 );
fprintf( stdout, "printSeg(): LINE: p1(%.3f, %.3f) p2(%.3f, %.3f)\n", aSegment->startPoint.x,
aSegment->startPoint.y, aSegment->endPoint.x, aSegment->endPoint.y );
}
#endif
@ -836,8 +865,7 @@ double IDF3::CalcAngleDeg( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPo
}
void IDF3::GetOutline( std::list<IDF_SEGMENT*>& aLines,
IDF_OUTLINE& aOutline )
void IDF3::GetOutline( std::list<IDF_SEGMENT*>& aLines, IDF_OUTLINE& aOutline )
{
aOutline.Clear();
@ -869,9 +897,11 @@ void IDF3::GetOutline( std::list<IDF_SEGMENT*>& aLines,
}
aOutline.push( *idx );
#ifdef DEBUG_IDF
PrintSeg( *idx );
#endif
aLines.erase( idx );
// If the item is a circle then we're done
@ -900,9 +930,11 @@ void IDF3::GetOutline( std::list<IDF_SEGMENT*>& aLines,
else
{
matched = true;
#ifdef DEBUG_IDF
PrintSeg( *bl );
#endif
aOutline.push( *bl );
bl = aLines.erase( bl );
}
@ -932,9 +964,11 @@ void IDF3::GetOutline( std::list<IDF_SEGMENT*>& aLines,
{
matched = true;
(*bl)->SwapEnds();
#ifdef DEBUG_IDF
printSeg( *bl );
#endif
aOutline.push( *bl );
bl = aLines.erase( bl );
}
@ -959,9 +993,11 @@ void IDF3::GetOutline( std::list<IDF_SEGMENT*>& aLines,
if( seg )
{
complete = true;
#ifdef DEBUG_IDF
printSeg( seg );
#endif
aOutline.push( seg );
break;
}
@ -1009,8 +1045,8 @@ IDF_SEGMENT::IDF_SEGMENT( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoi
{
double diff = abs( aAngle ) - 360.0;
if( ( diff < MIN_ANG
&& diff > -MIN_ANG ) || ( aAngle < MIN_ANG && aAngle > -MIN_ANG ) || (!aFromKicad) )
if( ( diff < MIN_ANG && diff > -MIN_ANG ) || ( aAngle < MIN_ANG && aAngle > -MIN_ANG )
|| ( !aFromKicad ) )
{
angle = 0.0;
startPoint = aStartPoint;
@ -1169,6 +1205,7 @@ void IDF_SEGMENT::SwapEnds()
// change the direction of the arc
angle = -angle;
// calculate the new offset angle
offsetAngle = IDF3::CalcAngleDeg( center, startPoint );
}
@ -1201,15 +1238,13 @@ bool IDF_OUTLINE::IsCCW()
double a1 = outline.front()->angle;
double a2 = outline.back()->angle;
if( ( a1 < -MIN_ANG || a1 > MIN_ANG )
&& ( a2 < -MIN_ANG || a2 > MIN_ANG ) )
if( ( a1 < -MIN_ANG || a1 > MIN_ANG ) && ( a2 < -MIN_ANG || a2 > MIN_ANG ) )
{
// we have 2 arcs; the winding is determined by
// the longer cord. although the angles are in
// degrees, there is no need to convert to radians
// to determine the longer cord.
if( abs( a1 * outline.front()->radius ) >=
abs( a2 * outline.back()->radius ) )
if( abs( a1 * outline.front()->radius ) >= abs( a2 * outline.back()->radius ) )
{
// winding depends on a1
if( a1 < 0.0 )
@ -1258,7 +1293,6 @@ bool IDF_OUTLINE::IsCCW()
}
// returns true if the outline is a circle
bool IDF_OUTLINE::IsCircle()
{
if( outline.front()->IsCircle() )
@ -1293,8 +1327,10 @@ bool IDF_OUTLINE::push( IDF_SEGMENT* item )
// startPoint[N] != endPoint[N -1]
ERROR_IDF << "INVALID GEOMETRY\n";
cerr << "* disjoint segments (current start point != last end point)\n";
cerr << "* start point: " << item->startPoint.x << ", " << item->startPoint.y << "\n";
cerr << "* end point: " << outline.back()->endPoint.x << ", " << outline.back()->endPoint.y << "\n";
cerr << "* start point: " << item->startPoint.x << ", " << item->startPoint.y
<< "\n";
cerr << "* end point: " << outline.back()->endPoint.x << ", "
<< outline.back()->endPoint.y << "\n";
return false;
}
}
@ -1311,20 +1347,18 @@ bool IDF_OUTLINE::push( IDF_SEGMENT* item )
// arcs require special consideration since the winding depends on
// the arc length; the arc length is adequately represented by
// taking 2 cords from the endpoints to the midpoint of the arc.
oang = (oang + ang / 2.0) * M_PI / 180.0;
oang = ( oang + ang / 2.0 ) * M_PI / 180.0;
double midx = outline.back()->center.x + radius * cos( oang );
double midy = outline.back()->center.y + radius * sin( oang );
dir += ( outline.back()->endPoint.x - midx )
* ( outline.back()->endPoint.y + midy );
dir += ( outline.back()->endPoint.x - midx ) * ( outline.back()->endPoint.y + midy );
dir += ( midx - outline.back()->startPoint.x )
* ( midy + outline.back()->startPoint.y );
dir += ( midx - outline.back()->startPoint.x ) * ( midy + outline.back()->startPoint.y );
}
else
{
dir += ( outline.back()->endPoint.x - outline.back()->startPoint.x )
* ( outline.back()->endPoint.y + outline.back()->startPoint.y );
* ( outline.back()->endPoint.y + outline.back()->startPoint.y );
}
return true;

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014 Cirilo Bernardo
* Copyright (C) 2014 Cirilo Bernardo
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -39,18 +40,16 @@
using namespace std;
void make_vcyl( bool inch, bool axial, double dia, double length,
double z, double wireDia );
void make_vcyl( bool inch, bool axial, double dia, double length, double z, double wireDia );
void make_hcyl( bool inch, bool axial, double dia, double length,
double z, double wireDia );
void make_hcyl( bool inch, bool axial, double dia, double length, double z, double wireDia );
void writeAxialCyl( FILE* fp, bool inch, double dia, double length, double wireDia, double pitch );
void writeRadialCyl( FILE* fp, bool inch, double dia, double length, double wireDia,
double pitch, double lead );
void writeRadialCyl( FILE* fp, bool inch, double dia, double length, double wireDia, double pitch,
double lead );
int main( int argc, char **argv )
int main( int argc, char** argv )
{
// IDF implicitly requires the C locale
setlocale( LC_ALL, "C" );
@ -81,18 +80,19 @@ int main( int argc, char **argv )
cout << " *** only required for horizontal orientation with radial leads\n\n";
}
char orientation = '\0';
bool inch = false; // default mm
char orientation = '\0';
bool inch = false; // default mm
double dia = 0.0;
double length = 0.0;
double extraZ = 0.0;
double wireDia = 0.0;
bool axial = false;
bool axial = false;
stringstream tstr;
string line;
string line;
line.clear();
while( line.compare( "mm" ) && line.compare( "in" ) )
{
cout << "* Units (mm,in): ";
@ -104,8 +104,9 @@ int main( int argc, char **argv )
inch = true;
line.clear();
while( line.compare( "H" ) && line.compare( "h" )
&& line.compare( "V" ) && line.compare( "v" ) )
while( line.compare( "H" ) && line.compare( "h" ) && line.compare( "V" )
&& line.compare( "v" ) )
{
cout << "* Orientation (H,V): ";
line.clear();
@ -140,6 +141,7 @@ int main( int argc, char **argv )
// cylinder dimensions
ok = false;
while( !ok )
{
cout << "* Diameter: ";
@ -151,11 +153,13 @@ int main( int argc, char **argv )
tstr.str( line );
tstr >> dia;
if( !tstr.fail() && dia > 0.0 )
ok = true;
}
ok = false;
while( !ok )
{
cout << "* Length: ";
@ -167,11 +171,13 @@ int main( int argc, char **argv )
tstr.str( line );
tstr >> length;
if( !tstr.fail() && length > 0.0 )
ok = true;
}
ok = false;
while( !ok )
{
cout << "* Board offset: ";
@ -183,11 +189,13 @@ int main( int argc, char **argv )
tstr.str( line );
tstr >> extraZ;
if( !tstr.fail() && extraZ >= 0.0 )
ok = true;
}
ok = false;
while( ( axial || orientation == 'h' ) && !ok )
{
cout << "* Wire diameter: ";
@ -199,6 +207,7 @@ int main( int argc, char **argv )
tstr.str( line );
tstr >> wireDia;
if( !tstr.fail() && wireDia > 0.0 )
{
if( wireDia < dia )
@ -210,14 +219,9 @@ int main( int argc, char **argv )
switch( orientation )
{
case 'v':
make_vcyl( inch, axial, dia, length, extraZ, wireDia );
break;
case 'h':
make_hcyl( inch, axial, dia, length, extraZ, wireDia );
break;
default:
break;
case 'v': make_vcyl( inch, axial, dia, length, extraZ, wireDia ); break;
case 'h': make_hcyl( inch, axial, dia, length, extraZ, wireDia ); break;
default: break;
}
setlocale( LC_ALL, "" );
@ -225,13 +229,12 @@ int main( int argc, char **argv )
}
void make_vcyl( bool inch, bool axial, double dia, double length,
double z, double wireDia )
void make_vcyl( bool inch, bool axial, double dia, double length, double z, double wireDia )
{
bool ok = false;
bool left = false;
bool ok = false;
bool left = false;
stringstream tstr;
string line;
string line;
double pitch = 0.0;
@ -246,9 +249,10 @@ void make_vcyl( bool inch, bool axial, double dia, double length,
tstr.str( line );
tstr >> pitch;
if( !tstr.fail() && pitch > 0.0 )
{
if( (pitch - wireDia) <= (dia / 2.0) )
if( ( pitch - wireDia ) <= ( dia / 2.0 ) )
{
cout << "* WARNING: Pitch must be > dia/2 + wireDia\n";
}
@ -260,6 +264,7 @@ void make_vcyl( bool inch, bool axial, double dia, double length,
}
ok = false;
while( axial && !ok )
{
cout << "* Pin side (L,R): ";
@ -270,10 +275,12 @@ void make_vcyl( bool inch, bool axial, double dia, double length,
if( !line.compare( "l" ) || !line.compare( "L" ) )
{
left = true;
ok = true;
ok = true;
}
else if( !line.compare( "r" ) || !line.compare( "R" ) )
{
ok = true;
}
}
line.clear();
@ -304,14 +311,14 @@ void make_vcyl( bool inch, bool axial, double dia, double length,
if( inch )
{
fprintf( fp, "# dia: %d THOU\n", (int) (dia * 1000) );
fprintf( fp, "# length: %d THOU\n", (int) (length * 1000) );
fprintf( fp, "# board offset: %d THOU\n", (int) (z * 1000) );
fprintf( fp, "# dia: %d THOU\n", (int) ( dia * 1000 ) );
fprintf( fp, "# length: %d THOU\n", (int) ( length * 1000 ) );
fprintf( fp, "# board offset: %d THOU\n", (int) ( z * 1000 ) );
if( axial )
{
fprintf( fp, "# wire dia: %d THOU\n", (int) (wireDia * 1000) );
fprintf( fp, "# pitch: %d THOU\n", (int) (pitch * 1000) );
fprintf( fp, "# wire dia: %d THOU\n", (int) ( wireDia * 1000 ) );
fprintf( fp, "# pitch: %d THOU\n", (int) ( pitch * 1000 ) );
}
}
else
@ -331,8 +338,7 @@ void make_vcyl( bool inch, bool axial, double dia, double length,
if( !axial )
{
fprintf( fp, "\"CYLV_%s_RAD\" \"D%.3f_H%.3f_Z%.3f\" ", inch ? "IN" : "MM",
dia, length, z );
fprintf( fp, "\"CYLV_%s_RAD\" \"D%.3f_H%.3f_Z%.3f\" ", inch ? "IN" : "MM", dia, length, z );
}
else
{
@ -341,7 +347,7 @@ void make_vcyl( bool inch, bool axial, double dia, double length,
}
if( inch )
fprintf( fp, "THOU %d\n", (int) ((length + z) * 1000) );
fprintf( fp, "THOU %d\n", (int) ( ( length + z ) * 1000 ) );
else
fprintf( fp, "MM %.3f\n", length + z );
@ -350,7 +356,7 @@ void make_vcyl( bool inch, bool axial, double dia, double length,
fprintf( fp, "0 0 0 0\n" );
if( inch )
fprintf( fp, "0 %d 0 360\n", (int) (dia * 500) );
fprintf( fp, "0 %d 0 360\n", (int) ( dia * 500 ) );
else
fprintf( fp, "0 %.3f 0 360\n", dia / 2.0 );
@ -369,8 +375,8 @@ void make_vcyl( bool inch, bool axial, double dia, double length,
if( inch )
{
dia *= 1000.0;
pitch *= 1000.0;
dia *= 1000.0;
pitch *= 1000.0;
wireDia *= 1000.0;
}
@ -393,7 +399,9 @@ void make_vcyl( bool inch, bool axial, double dia, double length,
{
li = '1';
fullAng = -360.0;
for( int i = 0; i < 4; ++i ) px[i] = -px[i];
for( int i = 0; i < 4; ++i )
px[i] = -px[i];
}
@ -403,8 +411,7 @@ void make_vcyl( bool inch, bool axial, double dia, double length,
fprintf( fp, "%c %d %d %.3f\n", li, (int) px[1], (int) py[1],
fullAng * ( 1 - ang / M_PI ) );
fprintf( fp, "%c %d %d 0\n", li, (int) px[2], (int) py[2] );
fprintf( fp, "%c %d %d %s\n", li, (int) px[3], (int) py[3],
left ? "-180" : "180" );
fprintf( fp, "%c %d %d %s\n", li, (int) px[3], (int) py[3], left ? "-180" : "180" );
fprintf( fp, "%c %d %d 0\n", li, (int) px[0], (int) py[0] );
}
else
@ -412,27 +419,25 @@ void make_vcyl( bool inch, bool axial, double dia, double length,
fprintf( fp, "%c %.3f %.3f 0\n", li, px[0], py[0] );
fprintf( fp, "%c %.3f %.3f %.3f\n", li, px[1], py[1], fullAng * ( 1 - ang / M_PI ) );
fprintf( fp, "%c %.3f %.3f 0\n", li, px[2], py[2] );
fprintf( fp, "%c %.3f %.3f %s\n", li, px[3], py[3],
left ? "-180" : "180" );
fprintf( fp, "%c %.3f %.3f %s\n", li, px[3], py[3], left ? "-180" : "180" );
fprintf( fp, "%c %.3f %.3f 0\n", li, px[0], py[0] );
}
fprintf( fp, ".END_ELECTRICAL\n" );
fclose( fp );
return;
}
void make_hcyl( bool inch, bool axial, double dia, double length,
double z, double wireDia )
void make_hcyl( bool inch, bool axial, double dia, double length, double z, double wireDia )
{
stringstream tstr;
string line;
string line;
double pitch = 0.0;
double lead = 0.0; // lead length for radial leads
double lead = 0.0; // lead length for radial leads
bool ok = false;
while( !ok )
{
if( axial )
@ -447,11 +452,12 @@ void make_hcyl( bool inch, bool axial, double dia, double length,
tstr.str( line );
tstr >> pitch;
if( !tstr.fail() && pitch > 0.0 )
{
if( axial )
{
if( (pitch - wireDia) <= length )
if( ( pitch - wireDia ) <= length )
{
cout << "* WARNING: Axial pitch must be > length + wireDia\n";
}
@ -462,7 +468,7 @@ void make_hcyl( bool inch, bool axial, double dia, double length,
}
else
{
if( (pitch + wireDia) >= dia )
if( ( pitch + wireDia ) >= dia )
{
cout << "* WARNING: Radial pitch must be < dia - wireDia\n";
}
@ -479,6 +485,7 @@ void make_hcyl( bool inch, bool axial, double dia, double length,
}
ok = false;
while( !axial && !ok )
{
cout << "* Lead length: ";
@ -490,6 +497,7 @@ void make_hcyl( bool inch, bool axial, double dia, double length,
tstr.str( line );
tstr >> lead;
if( !tstr.fail() && lead > 0.0 )
{
if( lead < wireDia )
@ -500,6 +508,7 @@ void make_hcyl( bool inch, bool axial, double dia, double length,
}
line.clear();
while( line.empty() || line.find( ".idf" ) == string::npos )
{
cout << "* File name (*.idf): ";
@ -524,13 +533,14 @@ void make_hcyl( bool inch, bool axial, double dia, double length,
if( inch )
{
fprintf( fp, "# dia: %d THOU\n", (int) (dia * 1000) );
fprintf( fp, "# length: %d THOU\n", (int) (length * 1000) );
fprintf( fp, "# extra height: %d THOU\n", (int) (z * 1000) );
fprintf( fp, "# wire dia: %d THOU\n", (int) (wireDia * 1000) );
fprintf( fp, "# pitch: %d THOU\n", (int) (pitch * 1000) );
fprintf( fp, "# dia: %d THOU\n", (int) ( dia * 1000 ) );
fprintf( fp, "# length: %d THOU\n", (int) ( length * 1000 ) );
fprintf( fp, "# extra height: %d THOU\n", (int) ( z * 1000 ) );
fprintf( fp, "# wire dia: %d THOU\n", (int) ( wireDia * 1000 ) );
fprintf( fp, "# pitch: %d THOU\n", (int) ( pitch * 1000 ) );
if( !axial )
fprintf( fp, "# lead: %d THOU\n", (int) (lead * 1000) );
fprintf( fp, "# lead: %d THOU\n", (int) ( lead * 1000 ) );
}
else
{
@ -539,6 +549,7 @@ void make_hcyl( bool inch, bool axial, double dia, double length,
fprintf( fp, "# extra height: %.3f mm\n", z );
fprintf( fp, "# wire dia: %.3f mm\n", wireDia );
fprintf( fp, "# pitch: %.3f mm\n", pitch );
if( !axial )
fprintf( fp, "# lead: %.3f mm\n", lead );
}
@ -547,8 +558,8 @@ void make_hcyl( bool inch, bool axial, double dia, double length,
if( axial )
{
fprintf( fp, "\"CYLH_%s_AXI\" \"D%.3f_H%.3f_Z%.3f_WD%.3f_P%.3f\" ",
inch ? "IN" : "MM", dia, length, z, wireDia, pitch );
fprintf( fp, "\"CYLH_%s_AXI\" \"D%.3f_H%.3f_Z%.3f_WD%.3f_P%.3f\" ", inch ? "IN" : "MM", dia,
length, z, wireDia, pitch );
}
else
{
@ -558,7 +569,7 @@ void make_hcyl( bool inch, bool axial, double dia, double length,
if( inch )
{
fprintf( fp, "THOU %d\n", (int) ((dia + z) * 1000) );
fprintf( fp, "THOU %d\n", (int) ( ( dia + z ) * 1000 ) );
dia *= 1000.0;
length *= 1000.0;
wireDia *= 1000.0;
@ -578,12 +589,10 @@ void make_hcyl( bool inch, bool axial, double dia, double length,
fprintf( fp, ".END_ELECTRICAL\n" );
fclose( fp );
return;
}
void writeAxialCyl( FILE* fp, bool inch, double dia, double length,
double wireDia, double pitch )
void writeAxialCyl( FILE* fp, bool inch, double dia, double length, double wireDia, double pitch )
{
double x1, y1;
double x2, y2;
@ -625,23 +634,20 @@ void writeAxialCyl( FILE* fp, bool inch, double dia, double length,
fprintf( fp, "0 %.3f %.3f 0\n", -x1, y1 );
fprintf( fp, "0 %.3f %.3f 0\n", x1, y1 );
}
return;
}
void writeRadialCyl( FILE* fp, bool inch, double dia, double length,
double wireDia, double pitch, double lead )
void writeRadialCyl( FILE* fp, bool inch, double dia, double length, double wireDia, double pitch,
double lead )
{
double x1, y1;
double x2, y2;
double x3;
// center is between the mounting holes
// which are on a horizontal line
// center is between the mounting holes which are on a horizontal line
y1 = lead + length;
y2 = lead;
x1 = dia / 2.0;
x2 = ( pitch + wireDia ) /2.0;
x2 = ( pitch + wireDia ) / 2.0;
x3 = x2 - wireDia;
if( inch )
@ -676,6 +682,4 @@ void writeRadialCyl( FILE* fp, bool inch, double dia, double length,
fprintf( fp, "0 %.3f %.3f 0\n", x1, y1 );
fprintf( fp, "0 %.3f %.3f 0\n", -x1, y1 );
}
return;
}

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014-2017 Cirilo Bernardo
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2020-2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -32,8 +32,9 @@
using namespace std;
using namespace IDF3;
// fetch a line from the given input file and trim the ends
bool IDF3::FetchIDFLine( std::istream& aModel, std::string& aLine, bool& isComment, std::streampos& aFilePos )
bool IDF3::FetchIDFLine( std::istream& aModel, std::string& aLine, bool& isComment,
std::streampos& aFilePos )
{
aLine = "";
aFilePos = aModel.tellg();
@ -68,9 +69,8 @@ bool IDF3::FetchIDFLine( std::istream& aModel, std::string& aLine, bool& isComme
}
// extract an IDF string and move the index to point to the character after the substring
bool IDF3::GetIDFString( const std::string& aLine, std::string& aIDFString,
bool& hasQuotes, int& aIndex )
bool IDF3::GetIDFString( const std::string& aLine, std::string& aIDFString, bool& hasQuotes,
int& aIndex )
{
// 1. drop all leading spaces
// 2. if the first character is '"', read until the next '"',
@ -97,6 +97,7 @@ bool IDF3::GetIDFString( const std::string& aLine, std::string& aIDFString,
{
hasQuotes = true;
++idx;
while( idx < len && aLine[idx] != '"' )
ostr << aLine[idx++];
@ -145,7 +146,6 @@ bool IDF3::CompareToken( const char* aTokenString, const std::string& aInputStri
}
// parse a string for an IDF3::KEY_OWNER
bool IDF3::ParseOwner( const std::string& aToken, IDF3::KEY_OWNER& aOwner )
{
if( CompareToken( "UNOWNED", aToken ) )
@ -209,35 +209,36 @@ bool IDF3::WriteLayersText( std::ostream& aBoardFile, IDF3::IDF_LAYER aLayer )
{
switch( aLayer )
{
case LYR_TOP:
aBoardFile << "TOP";
break;
case LYR_TOP:
aBoardFile << "TOP";
break;
case LYR_BOTTOM:
aBoardFile << "BOTTOM";
break;
case LYR_BOTTOM:
aBoardFile << "BOTTOM";
break;
case LYR_BOTH:
aBoardFile << "BOTH";
break;
case LYR_BOTH:
aBoardFile << "BOTH";
break;
case LYR_INNER:
aBoardFile << "INNER";
break;
case LYR_INNER:
aBoardFile << "INNER";
break;
case LYR_ALL:
aBoardFile << "ALL";
break;
case LYR_ALL:
aBoardFile << "ALL";
break;
default:
do{
std::ostringstream ostr;
ostr << "invalid IDF layer: " << aLayer;
default:
do
{
std::ostringstream ostr;
ostr << "invalid IDF layer: " << aLayer;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
} while( 0 );
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
} while( 0 );
break;
break;
}
return !aBoardFile.fail();
@ -248,20 +249,20 @@ std::string IDF3::GetPlacementString( IDF3::IDF_PLACEMENT aPlacement )
{
switch( aPlacement )
{
case PS_UNPLACED:
return "UNPLACED";
case PS_UNPLACED:
return "UNPLACED";
case PS_PLACED:
return "PLACED";
case PS_PLACED:
return "PLACED";
case PS_MCAD:
return "MCAD";
case PS_MCAD:
return "MCAD";
case PS_ECAD:
return "ECAD";
case PS_ECAD:
return "ECAD";
default:
break;
default:
break;
}
std::ostringstream ostr;
@ -275,23 +276,23 @@ std::string IDF3::GetLayerString( IDF3::IDF_LAYER aLayer )
{
switch( aLayer )
{
case LYR_TOP:
return "TOP";
case LYR_TOP:
return "TOP";
case LYR_BOTTOM:
return "BOTTOM";
case LYR_BOTTOM:
return "BOTTOM";
case LYR_BOTH:
return "BOTH";
case LYR_BOTH:
return "BOTH";
case LYR_INNER:
return "INNER";
case LYR_INNER:
return "INNER";
case LYR_ALL:
return "ALL";
case LYR_ALL:
return "ALL";
default:
break;
default:
break;
}
std::ostringstream ostr;
@ -300,21 +301,22 @@ std::string IDF3::GetLayerString( IDF3::IDF_LAYER aLayer )
return ostr.str();
}
std::string IDF3::GetOwnerString( IDF3::KEY_OWNER aOwner )
{
switch( aOwner )
{
case IDF3::UNOWNED:
return "UNOWNED";
case IDF3::UNOWNED:
return "UNOWNED";
case IDF3::MCAD:
return "MCAD";
case IDF3::MCAD:
return "MCAD";
case IDF3::ECAD:
return "ECAD";
case IDF3::ECAD:
return "ECAD";
default:
break;
default:
break;
}
ostringstream ostr;

View File

@ -1,7 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014-2017 Cirilo Bernardo
* Copyright (C) 2014-2017 Cirilo Bernardo
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -30,17 +31,18 @@
#include <idf_common.h>
/**
* Macro TO_UTF8
* converts a wxString to a UTF8 encoded C string for all wxWidgets build modes.
* Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
*
* wxstring is a wxString, not a wxT() or _(). The scope of the return value
* is very limited and volatile, but can be used with printf() style functions well.
*
* NOTE: Taken from KiCad include/macros.h
*/
#define TO_UTF8( wxstring ) ( (const char*) (wxstring).utf8_str() )
/**
* function FROM_UTF8
* converts a UTF8 encoded C string to a wxString for all wxWidgets build modes.
* Convert a UTF8 encoded C string to a wxString for all wxWidgets build modes.
*
* NOTE: Taken from KiCad include/macros.h
*/
static inline wxString FROM_UTF8( const char* cstring )
@ -70,102 +72,89 @@ namespace IDF3
{
/**
* Function FetchIDFLine
* retrieves a single line from an IDF file and performs minimal processing. If a comment symbol
* is encountered then it is removed and a single leading space is removed if present; all trailing
* spaces are removed. If the line is not a comment then all leading and trailing spaces are stripped.
* Retrieve a single line from an IDF file and performs minimal processing.
*
* @param aModel is an open IDFv3 file
* @param aLine (output) is the line retrieved from the file
* @param isComment (output) is set to true if the line is a comment
* @param aFilePos (output) is set to the beginning of the line in case the file needs to be rewound
* If a comment symbol is encountered then it is removed and a single leading space is removed
* if present; all trailing spaces are removed. If the line is not a comment then all leading
* and trailing spaces are stripped.
*
* @return bool: true if a line was read and was not empty; otherwise false
* @param[in] aModel is an open IDFv3 file.
* @param[out] aLine is the line retrieved from the file.
* @param[out] isComment is set to true if the line is a comment.
* @param[out] aFilePosis set to the beginning of the line in case the file needs to be rewound.
* @return true if a line was read and was not empty; otherwise false.
*/
bool FetchIDFLine( std::istream& aModel, std::string& aLine, bool& isComment, std::streampos& aFilePos );
bool FetchIDFLine( std::istream& aModel, std::string& aLine, bool& isComment,
std::streampos& aFilePos );
/**
* Function GetIDFString
* parses a line retrieved via FetchIDFLine() and returns the first IDF string found from the starting
* point aIndex
* Parse a line retrieved via FetchIDFLine() and returns the first IDF string found from the
* starting point aIndex.
*
* @param aLine is the line to parse
* @param aIDFString (output) is the IDF string retrieved
* @param hasQuotes (output) is true if the string was in quotation marks
* @param aIndex (input/output) is the index into the input line
*
* @return bool: true if a string was retrieved, otherwise false
* @param[in] aLine is the line to parse.
* @param[out] aIDFString is the IDF string retrieved.
* @param[out] hasQuotes is true if the string was in quotation marks.
* @param[in,out] aIndex is the index into the input line.
* @return true if a string was retrieved, otherwise false.
*/
bool GetIDFString( const std::string& aLine, std::string& aIDFString,
bool& hasQuotes, int& aIndex );
bool GetIDFString( const std::string& aLine, std::string& aIDFString, bool& hasQuotes,
int& aIndex );
/**
* Function CompareToken
* performs a case-insensitive comparison of a token string and an input string
* Perform a case-insensitive comparison of a token string and an input string.
*
* @param aToken is an IDF token such as ".HEADER"
* @param aInputString is a string typically retrieved via GetIDFString
*
* @return bool: true if the token and input string match
* @param aToken is an IDF token such as ".HEADER".
* @param aInputString is a string typically retrieved via GetIDFString.
* @return true if the token and input string match.
*/
bool CompareToken( const char* aTokenString, const std::string& aInputString );
/**
* Function ParseOwner
* parses the input string for a valid IDF Owner type
* Parse the input string for a valid IDF Owner type.
*
* @param aToken is the string to be parsed
* @param aOwner (output) is the IDF Owner class
*
* @return bool: true if a valid OWNER was found, otherwise false
* @param[in] aToken is the string to be parsed.
* @param[out] aOwner is the IDF Owner class.
* @return true if a valid OWNER was found, otherwise false.
*/
bool ParseOwner( const std::string& aToken, IDF3::KEY_OWNER& aOwner );
/**
* Function ParseIDFLayer
* parses an input string for a valid IDF layer specification
* Parse an input string for a valid IDF layer specification.
*
* @param aToken is the string to be parsed
* @param aLayer (output) is the IDF Layer type or group
*
* @return bool: true if a valid IDF Layer type was found, otherwise false
* @param[in] aToken is the string to be parsed.
* @param[out] aLayer is the IDF Layer type or group.
* @return true if a valid IDF Layer type was found, otherwise false.
*/
bool ParseIDFLayer( const std::string& aToken, IDF3::IDF_LAYER& aLayer );
/**
* Function WriteLayersText
* writes out text corresponding to the given IDF Layer type
* Write out text corresponding to the given IDF Layer type.
*
* @param aBoardFile is an IDFv3 file open for output
* @param aLayer is the IDF Layer type
*
* @return bool: true if the data was successfully written, otherwise false
* @param[in] aBoardFile is an IDFv3 file open for output.
* @param aLayer is the IDF Layer type.
* @return true if the data was successfully written, otherwise false
*/
bool WriteLayersText( std::ostream& aBoardFile, IDF3::IDF_LAYER aLayer );
/**
* Function GetPlacementString
* returns a string representing the given IDF Placement type
* Return a string representing the given IDF Placement type.
*
* @param aPlacement is the IDF placement type to encode as a string
*
* @return string: the string representation of aPlacement
* @param aPlacement is the IDF placement type to encode as a string.
* @return the string representation of aPlacement.
*/
std::string GetPlacementString( IDF3::IDF_PLACEMENT aPlacement );
/**
* Function GetLayerString
* returns a string representing the given IDF Layer type
* Return a string representing the given IDF Layer type.
*
* @param aLayer is the IDF layer type to encode as a string
*
* @return string: the string representation of aLayer
* @param aLayer is the IDF layer type to encode as a string.
* @return the string representation of aLayer.
*/
std::string GetLayerString( IDF3::IDF_LAYER aLayer );

View File

@ -1,7 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014 Cirilo Bernardo
* Copyright (C) 2014 Cirilo Bernardo
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -33,13 +34,11 @@
using namespace std;
void writeLeaded( FILE* fp, double width, double length,
double wireDia, double pitch, bool inch );
void writeLeaded( FILE* fp, double width, double length, double wireDia, double pitch, bool inch );
void writeLeadless( FILE* fp, double width, double length,
double chamfer, bool inch );
void writeLeadless( FILE* fp, double width, double length, double chamfer, bool inch );
int main( int argc, char **argv )
int main( int argc, char** argv )
{
// IDF implicitly requires the C locale
setlocale( LC_ALL, "C" );
@ -64,20 +63,21 @@ int main( int argc, char **argv )
cout << " ** only required for leaded components\n\n";
}
bool inch = false; // default mm
bool inch = false; // default mm
double width = 0.0;
double length = 0.0;
double height = 0.0;
double wireDia = 0.0;
double pitch = 0.0;
double chamfer = 0.0;
bool leaded = false;
bool ok = false;
bool leaded = false;
bool ok = false;
stringstream tstr;
string line;
string line;
line.clear();
while( line.compare( "mm" ) && line.compare( "in" ) )
{
cout << "* Units (mm,in): ";
@ -89,6 +89,7 @@ int main( int argc, char **argv )
inch = true;
ok = false;
while( !ok )
{
cout << "* Width: ";
@ -100,11 +101,13 @@ int main( int argc, char **argv )
tstr.str( line );
tstr >> width;
if( !tstr.fail() && width >= 0.001 )
ok = true;
}
ok = false;
while( !ok )
{
cout << "* Length: ";
@ -116,11 +119,13 @@ int main( int argc, char **argv )
tstr.str( line );
tstr >> length;
if( !tstr.fail() && length > 0.0 )
ok = true;
}
ok = false;
while( !ok )
{
cout << "* Height: ";
@ -132,11 +137,13 @@ int main( int argc, char **argv )
tstr.str( line );
tstr >> height;
if( !tstr.fail() && height >= 0.001 )
ok = true;
}
ok = false;
while( !ok )
{
cout << "* Chamfer (0 for none): ";
@ -148,6 +155,7 @@ int main( int argc, char **argv )
tstr.str( line );
tstr >> chamfer;
if( !tstr.fail() && chamfer >= 0.0 )
{
if( chamfer > width / 3.0 || chamfer > length / 3.0 )
@ -160,6 +168,7 @@ int main( int argc, char **argv )
if( chamfer < 1e-6 )
{
ok = false;
while( !ok )
{
cout << "* Leaded: Y, N: ";
@ -181,6 +190,7 @@ int main( int argc, char **argv )
}
ok = false;
while( leaded && !ok )
{
cout << "* Wire dia.: ";
@ -192,6 +202,7 @@ int main( int argc, char **argv )
tstr.str( line );
tstr >> wireDia;
if( !tstr.fail() && wireDia >= 0.001 )
{
if( wireDia >= length )
@ -202,6 +213,7 @@ int main( int argc, char **argv )
}
ok = false;
while( leaded && !ok )
{
cout << "* Pitch: ";
@ -213,6 +225,7 @@ int main( int argc, char **argv )
tstr.str( line );
tstr >> pitch;
if( !tstr.fail() && pitch >= 0.001 )
{
if( pitch <= ( length + wireDia ) / 2.0 )
@ -223,6 +236,7 @@ int main( int argc, char **argv )
}
line.clear();
while( line.empty() || line.find( ".idf" ) == string::npos )
{
cout << "* File name (*.idf): ";
@ -266,8 +280,8 @@ int main( int argc, char **argv )
}
fprintf( fp, ".ELECTRICAL\n" );
fprintf( fp, "\"RECT%sIN\" \"W%d_L%d_H%d", leaded ? "L" : "",
(int) width, (int) length, (int) height );
fprintf( fp, "\"RECT%sIN\" \"W%d_L%d_H%d", leaded ? "L" : "", (int) width, (int) length,
(int) height );
if( leaded )
fprintf( fp, "_D%d_P%d\" ", (int) wireDia, (int) pitch );
@ -293,8 +307,8 @@ int main( int argc, char **argv )
}
fprintf( fp, ".ELECTRICAL\n" );
fprintf( fp, "\"RECT%sMM\" \"W%.3f_L%.3f_H%.3f_", leaded ? "L" : "",
width, length, height );
fprintf( fp, "\"RECT%sMM\" \"W%.3f_L%.3f_H%.3f_", leaded ? "L" : "", width, length,
height );
if( leaded )
fprintf( fp, "D%.3f_P%.3f\" ", wireDia, pitch );
@ -318,8 +332,7 @@ int main( int argc, char **argv )
}
void writeLeaded( FILE* fp, double width, double length,
double wireDia, double pitch, bool inch )
void writeLeaded( FILE* fp, double width, double length, double wireDia, double pitch, bool inch )
{
if( inch )
{
@ -365,12 +378,10 @@ void writeLeaded( FILE* fp, double width, double length,
fprintf( fp, "0 %.3f %.3f 0\n", x1, -y1 );
fprintf( fp, "0 %.3f %.3f 180\n", x1, y1 );
}
return;
}
void writeLeadless( FILE* fp, double width, double length,
double chamfer, bool inch )
void writeLeadless( FILE* fp, double width, double length, double chamfer, bool inch )
{
if( chamfer < 0.001 )
{
@ -428,6 +439,4 @@ void writeLeadless( FILE* fp, double width, double length,
fprintf( fp, "0 %.3f %.3f 0\n", x, -y );
fprintf( fp, "0 %.3f %.3f 0\n", x, y );
}
return;
}

View File

@ -2,6 +2,7 @@
* file: vrml_layer.cpp
*
* This program source code file is part of KiCad, a free EDA CAD application.
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* Copyright (C) 2013-2017 Cirilo Bernardo
*
@ -100,13 +101,13 @@ int VRML_LAYER::calcNSides( double aRadius, double aAngle )
if( csides < 2 * maxSeg )
csides /= 2;
else
csides = (((double) csides) * minSegLength / maxSegLength );
csides = ( ( (double) csides ) * minSegLength / maxSegLength );
}
if( csides < 3 )
csides = 3;
if( (csides & 1) == 0 )
if( ( csides & 1 ) == 0 )
csides += 1;
return csides;
@ -147,7 +148,7 @@ static void CALLBACK vrml_tess_err( GLenum errorID, void* user_data )
static void CALLBACK vrml_tess_combine( GLdouble coords[3], VERTEX_3D* vertex_data[4],
GLfloat weight[4], void** outData, void* user_data )
GLfloat weight[4], void** outData, void* user_data )
{
VRML_LAYER* lp = (VRML_LAYER*) user_data;
@ -232,6 +233,7 @@ void VRML_LAYER::GetArcParams( int& aMaxSeg, double& aMinLength, double& aMaxLen
aMaxLength = maxSegLength;
}
bool VRML_LAYER::SetArcParams( int aMaxSeg, double aMinLength, double aMaxLength )
{
if( aMaxSeg < 8 )
@ -247,7 +249,6 @@ bool VRML_LAYER::SetArcParams( int aMaxSeg, double aMinLength, double aMaxLength
}
// clear all data
void VRML_LAYER::Clear( void )
{
int i;
@ -275,7 +276,6 @@ void VRML_LAYER::Clear( void )
}
// clear ephemeral data in between invocations of the tesselation routine
void VRML_LAYER::clearTmp( void )
{
unsigned int i;
@ -315,9 +315,7 @@ void VRML_LAYER::clearTmp( void )
}
// create a new contour to be populated; returns an index
// into the contour list or -1 if there are problems
int VRML_LAYER::NewContour( bool aPlatedHole )
int VRML_LAYER::NewContour( bool aPlatedHole )
{
if( fix )
return -1;
@ -333,9 +331,6 @@ int VRML_LAYER::NewContour( bool aPlatedHole )
}
// adds a vertex to the existing list and places its index in
// an existing contour; returns true if OK,
// false otherwise (indexed contour does not exist)
bool VRML_LAYER::AddVertex( int aContourID, double aXpos, double aYpos )
{
if( fix )
@ -372,8 +367,6 @@ bool VRML_LAYER::AddVertex( int aContourID, double aXpos, double aYpos )
}
// ensure the winding of a contour with respect to the normal (0, 0, 1);
// set 'hole' to true to ensure a hole (clockwise winding)
bool VRML_LAYER::EnsureWinding( int aContourID, bool aHoleFlag )
{
if( aContourID < 0 || (unsigned int) aContourID >= contours.size() )
@ -408,8 +401,7 @@ bool VRML_LAYER::EnsureWinding( int aContourID, bool aHoleFlag )
}
bool VRML_LAYER::AppendCircle( double aXpos, double aYpos,
double aRadius, int aContourID,
bool VRML_LAYER::AppendCircle( double aXpos, double aYpos, double aRadius, int aContourID,
bool aHoleFlag )
{
if( aContourID < 0 || (unsigned int) aContourID >= contours.size() )
@ -465,10 +457,8 @@ bool VRML_LAYER::AppendCircle( double aXpos, double aYpos,
}
// adds a circle to the existing list; if 'hole' is true the contour is
// a hole. Returns true if OK.
bool VRML_LAYER::AddCircle( double aXpos, double aYpos, double aRadius,
bool aHoleFlag, bool aPlatedHole )
bool VRML_LAYER::AddCircle( double aXpos, double aYpos, double aRadius, bool aHoleFlag,
bool aPlatedHole )
{
int pad;
@ -487,10 +477,7 @@ bool VRML_LAYER::AddCircle( double aXpos, double aYpos, double aRadius,
}
// adds a slotted pad with orientation given by angle; if 'hole' is true the
// contour is a hole. Returns true if OK.
bool VRML_LAYER::AddSlot( double aCenterX, double aCenterY,
double aSlotLength, double aSlotWidth,
bool VRML_LAYER::AddSlot( double aCenterX, double aCenterY, double aSlotLength, double aSlotWidth,
double aAngle, bool aHoleFlag, bool aPlatedHole )
{
aAngle *= M_PI / 180.0;
@ -577,7 +564,7 @@ bool VRML_LAYER::AddSlot( double aCenterX, double aCenterY,
bool VRML_LAYER::AddPolygon( const std::vector< wxRealPoint >& aPolySet, double aCenterX,
double aCenterY, double aAngle )
double aCenterY, double aAngle )
{
int pad = NewContour( false );
@ -639,7 +626,6 @@ bool VRML_LAYER::AppendArc( double aCenterX, double aCenterY, double aRadius,
}
// adds an arc with the given center, start point, pen width, and angle (degrees).
bool VRML_LAYER::AddArc( double aCenterX, double aCenterY, double aStartX, double aStartY,
double aArcWidth, double aAngle, bool aHoleFlag, bool aPlatedHole )
{
@ -754,8 +740,6 @@ bool VRML_LAYER::AddArc( double aCenterX, double aCenterY, double aStartX, doubl
}
// tesselates the contours in preparation for a 3D output;
// returns true if all was fine, false otherwise
bool VRML_LAYER::Tesselate( VRML_LAYER* holes, bool aHolesOnly )
{
if( !tess )
@ -1001,7 +985,6 @@ bool VRML_LAYER::pushOutline( VRML_LAYER* holes )
}
// writes out the vertex list for a planar feature
bool VRML_LAYER::WriteVertices( double aZcoord, std::ostream& aOutFile, int aPrecision )
{
if( ordmap.size() < 3 )
@ -1045,10 +1028,8 @@ bool VRML_LAYER::WriteVertices( double aZcoord, std::ostream& aOutFile, int aPre
}
// writes out the vertex list for a 3D feature; top and bottom are the
// Z values for the top and bottom; top must be > bottom
bool VRML_LAYER::Write3DVertices( double aTopZ, double aBottomZ,
std::ostream& aOutFile, int aPrecision )
bool VRML_LAYER::Write3DVertices( double aTopZ, double aBottomZ, std::ostream& aOutFile,
int aPrecision )
{
if( ordmap.size() < 3 )
{
@ -1132,9 +1113,6 @@ bool VRML_LAYER::Write3DVertices( double aTopZ, double aBottomZ,
}
// writes out the index list;
// 'top' indicates the vertex ordering and should be
// true for a polygon visible from above the PCB
bool VRML_LAYER::WriteIndices( bool aTopFlag, std::ostream& aOutFile )
{
if( triplets.empty() )
@ -1182,7 +1160,6 @@ bool VRML_LAYER::WriteIndices( bool aTopFlag, std::ostream& aOutFile )
}
// writes out the index list for a 3D feature
bool VRML_LAYER::Write3DIndices( std::ostream& aOutFile, bool aIncludePlatedHoles )
{
if( outline.empty() )
@ -1229,14 +1206,17 @@ bool VRML_LAYER::Write3DIndices( std::ostream& aOutFile, bool aIncludePlatedHole
while( tbeg != tend )
{
if( (i++ & 7) == 4 )
if( ( i++ & 7 ) == 4 )
{
i = 1;
aOutFile << ",\n" << (tbeg->i2 + idx2) << ", " << (tbeg->i1 + idx2) << ", " << (tbeg->i3 + idx2) << ", -1";
aOutFile << ",\n"
<< ( tbeg->i2 + idx2 ) << ", " << ( tbeg->i1 + idx2 ) << ", "
<< ( tbeg->i3 + idx2 ) << ", -1";
}
else
{
aOutFile << ", " << (tbeg->i2 + idx2) << ", " << (tbeg->i1 + idx2) << ", " << (tbeg->i3 + idx2) << ", -1";
aOutFile << ", " << ( tbeg->i2 + idx2 ) << ", " << ( tbeg->i1 + idx2 ) << ", "
<< ( tbeg->i3 + idx2 ) << ", -1";
}
++tbeg;
@ -1245,7 +1225,6 @@ bool VRML_LAYER::Write3DIndices( std::ostream& aOutFile, bool aIncludePlatedHole
else
mark = ' ';
// print out indices for the walls joining top to bottom
int lastPoint;
int curPoint;
@ -1258,6 +1237,7 @@ bool VRML_LAYER::Write3DIndices( std::ostream& aOutFile, bool aIncludePlatedHole
std::list<int>::const_iterator cend;
i = 2;
while( obeg != oend )
{
cp = *obeg;
@ -1288,16 +1268,20 @@ bool VRML_LAYER::Write3DIndices( std::ostream& aOutFile, bool aIncludePlatedHole
if( !holes_only )
{
if( (i++ & 3) == 2 )
if( ( i++ & 3 ) == 2 )
{
i = 1;
aOutFile << mark << "\n" << curPoint << ", " << lastPoint << ", " << curPoint + idx2;
aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint << ", " << lastPoint + idx2 << ", -1";
aOutFile << mark << "\n"
<< curPoint << ", " << lastPoint << ", " << curPoint + idx2;
aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint << ", "
<< lastPoint + idx2 << ", -1";
}
else
{
aOutFile << mark << " " << curPoint << ", " << lastPoint << ", " << curPoint + idx2;
aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint << ", " << lastPoint + idx2 << ", -1";
aOutFile << mark << " " << curPoint << ", " << lastPoint << ", "
<< curPoint + idx2;
aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint << ", "
<< lastPoint + idx2 << ", -1";
}
}
else
@ -1305,13 +1289,17 @@ bool VRML_LAYER::Write3DIndices( std::ostream& aOutFile, bool aIncludePlatedHole
if( (i++ & 3) == 2 )
{
i = 1;
aOutFile << mark << "\n" << curPoint << ", " << curPoint + idx2 << ", " << lastPoint;
aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint + idx2 << ", " << lastPoint << ", -1";
aOutFile << mark << "\n"
<< curPoint << ", " << curPoint + idx2 << ", " << lastPoint;
aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint + idx2 << ", "
<< lastPoint << ", -1";
}
else
{
aOutFile << mark << " " << curPoint << ", " << curPoint + idx2 << ", " << lastPoint;
aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint + idx2 << ", " << lastPoint << ", -1";
aOutFile << mark << " " << curPoint << ", " << curPoint + idx2 << ", "
<< lastPoint;
aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint + idx2 << ", "
<< lastPoint << ", -1";
}
}
@ -1328,28 +1316,32 @@ bool VRML_LAYER::Write3DIndices( std::ostream& aOutFile, bool aIncludePlatedHole
if( !holes_only )
{
if( (i++ & 3) == 2 )
if( ( i++ & 3 ) == 2 )
{
aOutFile << ",\n" << curPoint << ", " << lastPoint << ", " << curPoint + idx2;
aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint << ", " << lastPoint + idx2 << ", -1";
aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint << ", "
<< lastPoint + idx2 << ", -1";
}
else
{
aOutFile << ", " << curPoint << ", " << lastPoint << ", " << curPoint + idx2;
aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint << ", " << lastPoint + idx2 << ", -1";
aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint << ", "
<< lastPoint + idx2 << ", -1";
}
}
else
{
if( (i++ & 3) == 2 )
if( ( i++ & 3 ) == 2 )
{
aOutFile << ",\n" << curPoint << ", " << curPoint + idx2 << ", " << lastPoint;
aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint + idx2 << ", " << lastPoint << ", -1";
aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint + idx2 << ", "
<< lastPoint << ", -1";
}
else
{
aOutFile << ", " << curPoint << ", " << curPoint + idx2 << ", " << lastPoint;
aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint + idx2 << ", " << lastPoint << ", -1";
aOutFile << ", -1, " << curPoint + idx2 << ", " << lastPoint + idx2 << ", "
<< lastPoint << ", -1";
}
}
@ -1361,7 +1353,6 @@ bool VRML_LAYER::Write3DIndices( std::ostream& aOutFile, bool aIncludePlatedHole
}
// add a triangular facet (triplet) to the output index list
bool VRML_LAYER::addTriplet( VERTEX_3D* p0, VERTEX_3D* p1, VERTEX_3D* p2 )
{
double dx0 = p1->x - p0->x;
@ -1400,7 +1391,6 @@ bool VRML_LAYER::addTriplet( VERTEX_3D* p0, VERTEX_3D* p1, VERTEX_3D* p2 )
}
// add an extra vertex (to be called only by the COMBINE callback)
VERTEX_3D* VRML_LAYER::AddExtraVertex( double aXpos, double aYpos, bool aPlatedHole )
{
VERTEX_3D* vertex = new VERTEX_3D;
@ -1420,7 +1410,6 @@ VERTEX_3D* VRML_LAYER::AddExtraVertex( double aXpos, double aYpos, bool aPlatedH
}
// start a GL command list
void VRML_LAYER::glStart( GLenum cmd )
{
glcmd = cmd;
@ -1430,7 +1419,6 @@ void VRML_LAYER::glStart( GLenum cmd )
}
// process a vertex
void VRML_LAYER::glPushVertex( VERTEX_3D* vertex )
{
if( vertex->o < 0 )
@ -1443,51 +1431,51 @@ void VRML_LAYER::glPushVertex( VERTEX_3D* vertex )
}
// end a GL command list
void VRML_LAYER::glEnd( void )
{
switch( glcmd )
{
case GL_LINE_LOOP:
{
// add the loop to the list of outlines
std::list<int>* loop = new std::list<int>;
double firstX = 0.0;
double firstY = 0.0;
double lastX = 0.0;
double lastY = 0.0;
double curX, curY;
double area = 0.0;
if( vlist.size() > 0 )
{
// add the loop to the list of outlines
std::list<int>* loop = new std::list<int>;
double firstX = 0.0;
double firstY = 0.0;
double lastX = 0.0;
double lastY = 0.0;
double curX, curY;
double area = 0.0;
if( vlist.size() > 0 )
{
loop->push_back( vlist[0]->o );
firstX = vlist[0]->x;
firstY = vlist[0]->y;
lastX = firstX;
lastY = firstY;
}
for( size_t i = 1; i < vlist.size(); ++i )
{
loop->push_back( vlist[i]->o );
curX = vlist[i]->x;
curY = vlist[i]->y;
area += ( curX - lastX ) * ( curY + lastY );
lastX = curX;
lastY = curY;
}
area += ( firstX - lastX ) * ( firstY + lastY );
outline.push_back( loop );
if( area <= 0.0 )
solid.push_back( true );
else
solid.push_back( false );
loop->push_back( vlist[0]->o );
firstX = vlist[0]->x;
firstY = vlist[0]->y;
lastX = firstX;
lastY = firstY;
}
for( size_t i = 1; i < vlist.size(); ++i )
{
loop->push_back( vlist[i]->o );
curX = vlist[i]->x;
curY = vlist[i]->y;
area += ( curX - lastX ) * ( curY + lastY );
lastX = curX;
lastY = curY;
}
area += ( firstX - lastX ) * ( firstY + lastY );
outline.push_back( loop );
if( area <= 0.0 )
solid.push_back( true );
else
solid.push_back( false );
}
break;
case GL_TRIANGLE_FAN:
@ -1513,7 +1501,6 @@ void VRML_LAYER::glEnd( void )
}
// set the error message
void VRML_LAYER::SetGLError( GLenum errorID )
{
const char * msg = (const char*)gluErrorString( errorID );
@ -1533,7 +1520,6 @@ void VRML_LAYER::SetGLError( GLenum errorID )
}
// process a GL_TRIANGLE_FAN list
void VRML_LAYER::processFan( void )
{
if( vlist.size() < 3 )
@ -1551,7 +1537,6 @@ void VRML_LAYER::processFan( void )
}
// process a GL_TRIANGLE_STRIP list
void VRML_LAYER::processStrip( void )
{
// note: (source: http://www.opengl.org/wiki/Primitive)
@ -1584,7 +1569,6 @@ void VRML_LAYER::processStrip( void )
}
// process a GL_TRIANGLES list
void VRML_LAYER::processTri( void )
{
// notes:
@ -1624,7 +1608,6 @@ int VRML_LAYER::checkNContours( bool holes )
}
// push the internally held vertices
void VRML_LAYER::pushVertices( bool holes )
{
// push the internally held vertices
@ -1705,17 +1688,12 @@ VERTEX_3D* VRML_LAYER::getVertexByIndex( int aPointIndex, VRML_LAYER* holes )
}
// retrieve the total number of vertices
int VRML_LAYER::GetSize( void )
{
return vertices.size();
}
// Inserts all contours into the given tesselator; this results in the
// renumbering of all vertices from 'start'. Returns the end number.
// Take care when using this call since tesselators cannot work on
// the internal data concurrently
int VRML_LAYER::Import( int start, GLUtesselator* aTesselator )
{
if( start < 0 )
@ -1772,7 +1750,6 @@ int VRML_LAYER::Import( int start, GLUtesselator* aTesselator )
}
// return the vertex identified by index
VERTEX_3D* VRML_LAYER::GetVertexByIndex( int aPointIndex )
{
int i0 = vertices[0]->i;
@ -1787,7 +1764,6 @@ VERTEX_3D* VRML_LAYER::GetVertexByIndex( int aPointIndex )
}
// return the error string
const std::string& VRML_LAYER::GetError( void )
{
return error;
@ -1803,8 +1779,8 @@ void VRML_LAYER::SetVertexOffsets( double aXoffset, double aYoffset )
bool VRML_LAYER::Get3DTriangles( std::vector< double >& aVertexList,
std::vector< int > &aIndexPlane, std::vector< int > &aIndexSide,
double aTopZ, double aBotZ )
std::vector< int > &aIndexPlane, std::vector< int > &aIndexSide,
double aTopZ, double aBotZ )
{
aVertexList.clear();
aIndexPlane.clear();
@ -1897,6 +1873,7 @@ bool VRML_LAYER::Get3DTriangles( std::vector< double >& aVertexList,
std::list< int >::const_iterator cend;
i = 2;
while( obeg != oend )
{
cp = *obeg;
@ -1977,7 +1954,7 @@ bool VRML_LAYER::Get3DTriangles( std::vector< double >& aVertexList,
bool VRML_LAYER::Get2DTriangles( std::vector< double >& aVertexList,
std::vector< int > &aIndexPlane, double aHeight, bool aTopPlane )
std::vector< int > &aIndexPlane, double aHeight, bool aTopPlane )
{
aVertexList.clear();
aIndexPlane.clear();

View File

@ -3,7 +3,8 @@
*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013-2017 Cirilo Bernardo
* Copyright (C) 2013-2017 Cirilo Bernardo
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -28,8 +29,7 @@
*/
/*
* Classes and structures to support the tesselation of a
* PCB for VRML output.
* Classes and structures to support the tesselation of a PCB for VRML output.
*/
#ifndef VRML_LAYER_H
@ -92,6 +92,333 @@ struct TRIPLET_3D
class VRML_LAYER
{
public:
VRML_LAYER();
virtual ~VRML_LAYER();
/**
* Retrieve the parameters used in calculating the number of vertices in an arc.
*
* @param aMaxSeg is the maximum number of segments for an arc with cords of length aMinLength.
* @param aMinLength is the minimum length of cords in an arc.
* @param aMaxLength is the maximum length of cords in an arc.
*/
void GetArcParams( int& aMaxSeg, double& aMinLength, double& aMaxLength );
/**
* Set the parameters used in calculating the number of vertices in an arc.
*
* The default settings are reasonable for rendering for unit lengths of 1mm.
*
* @param aMaxSeg is the maximum number of segments for an arc with cords of length aMinLength.
* @param aMinLength is the minimum length of cords in an arc.
* @param aMaxLength is the maximum length of cords in an arc.
* @return true if the parameters were accepted.
*/
bool SetArcParams( int aMaxSeg, double aMinLength, double aMaxLength );
/**
* Reset the parameters used in calculating the number of vertices in an arc to default values.
*/
void ResetArcParams();
/**
* Rrase all data except for arc parameters.
*/
void Clear( void );
/**
* @return the total number of vertices indexed.
*/
int GetSize( void );
/**
* @return the number of stored contours.
*/
int GetNContours( void )
{
return contours.size();
}
/**
* Create a new list of vertices and returns an index to the list.
*
* @param aPlatedHole is true if the new contour will represent a plated hole.
* @return index to the list or -1 if the operation failed.
*/
int NewContour( bool aPlatedHole = false );
/**
* Add a point to the requested contour.
*
* @param aContour is an index previously returned by a call to NewContour().
* @param aXpos is the X coordinate of the vertex.
* @param aYpos is the Y coordinate of the vertex.
* @return true if the vertex was added.
*/
bool AddVertex( int aContourID, double aXpos, double aYpos );
/**
* Check the winding of a contour and ensures that it is a hole or a solid depending on the
* value of @param hole.
*
* @param aContour is an index to a contour as returned by NewContour().
* @param aHoleFlag determines if the contour must be a hole.
* @return true if the operation succeeded.
*/
bool EnsureWinding( int aContourID, bool aHoleFlag );
/**
* Add a circular contour to the specified (empty) contour.
*
* @param aXpos is the X coordinate of the hole center.
* @param aYpos is the Y coordinate of the hole center.
* @param aRadius is the radius of the hole.
* @param aContourID is the contour index.
* @param aHoleFlag determines if the contour to be created is a cutout.
* @return true if the new contour was successfully created.
*/
bool AppendCircle( double aXpos, double aYpos, double aRadius, int aContourID,
bool aHoleFlag = false );
/**
* Create a circular contour and adds it to the internal list.
*
* @param aXpos is the X coordinate of the hole center.
* @param aYpos is the Y coordinate of the hole center.
* @param aRadius is the radius of the hole.
* @param aHoleFlag determines if the contour to be created is a cutout.
* @param aPlatedHole is true if this is a plated hole.
* @return true if the new contour was successfully created.
*/
bool AddCircle( double aXpos, double aYpos, double aRadius, bool aHoleFlag = false,
bool aPlatedHole = false );
/**
* Create and add a slot feature to the list of contours.
*
* @param aCenterX is the X coordinate of the slot's center.
* @param aCenterY is the Y coordinate of the slot's center.
* @param aSlotLength is the length of the slot along the major axis.
* @param aSlotWidth is the width of the slot along the minor axis.
* @param aAngle (degrees) is the orientation of the slot.
* @param aHoleFlag determines whether the slot is a hole or a solid.
* @param aPlatedHole is true if this is a plated slot.
* @return true if the slot was successfully created.
*/
bool AddSlot( double aCenterX, double aCenterY, double aSlotLength, double aSlotWidth,
double aAngle, bool aHoleFlag = false, bool aPlatedHole = false );
/**
* Add an arc to the specified contour.
*
* @param aCenterX is the X coordinate of the arc's center.
* @param aCenterY is the Y coordinate of the arc's center.
* @param aRadius is the radius of the arc.
* @param aStartAngle (degrees) is the starting angle of the arc.
* @param aAngle (degrees) is the measure of the arc.
* @param aContourID is the contour's index.
* @return true if the slot was successfully created.
*/
bool AppendArc( double aCenterX, double aCenterY, double aRadius, double aStartAngle,
double aAngle, int aContourID );
/**
* Create a slotted arc and adds it to the internal list of contours.
*
* @param aCenterX is the X coordinate of the arc's center.
* @param aCenterY is the Y coordinate of the arc's center.
* @param aStartX is the X coordinate of the starting point.
* @param aStartY is the Y coordinate of the starting point.
* @param aArcWidth is the width of the arc.
* @param aAngle is the included angle (degrees).
* @param aHoleFlag determines whether the arc is to be a hole or a solid.
* @param aPlatedHole is true if this is a plated slotted arc.
* @return true if the feature was successfully created.
*/
bool AddArc( double aCenterX, double aCenterY, double aStartX, double aStartY,
double aArcWidth, double aAngle, bool aHoleFlag = false,
bool aPlatedHole = false );
/**
* Create an arbitrary polygon and adds it to the list of contours.
*
* @param aPolySet is the set of polygon points.
* @param aCenterX is the X coordinate of the polygon's center.
* @param aCenterY is the Y coordinate of the polygon's center.
* @param aAngle is the rotation angle (degrees) of the pad.
*/
bool AddPolygon( const std::vector< wxRealPoint >& aPolySet, double aCenterX, double aCenterY,
double aAngle );
/**
* Create a list of outline vertices as well as the vertex sets required to render the surface.
*
* @param holes is an optional pointer to cutouts to be imposed on the surface.
* @param aHolesOnly is true if the outline contains only holes.
* @return true if the operation succeeded.
*/
bool Tesselate( VRML_LAYER* holes = NULL, bool aHolesOnly = false );
/**
* Write out the list of vertices required to render a planar surface.
*
* @param aZcoord is the Z coordinate of the plane.
* @param aOutFile is the file to write to.
* @param aPrecision is the precision of the output coordinates.
* @return true if the operation succeeded.
*/
bool WriteVertices( double aZcoord, std::ostream& aOutFile, int aPrecision );
/**
* Write out the list of vertices required to render an extruded solid.
*
* @param aTopZ is the Z coordinate of the top plane.
* @param aBottomZ is the Z coordinate of the bottom plane.
* @param aOutFile is the file to write to.
* @param aPrecision is the precision of the output coordinates.
* @return true if the operation succeeded.
*/
bool Write3DVertices( double aTopZ, double aBottomZ, std::ostream& aOutFile, int aPrecision );
/**
* Write out the vertex sets required to render a planar surface.
*
* @param aTopFlag is true if the surface is to be visible from above; if false the surface
* will be visible from below.
* @param aOutFile is the file to write to.
* @return true if the operation succeeded.
*/
bool WriteIndices( bool aTopFlag, std::ostream& aOutFile );
/**
* Write out the vertex sets required to render an extruded solid.
*
* @param aOutFile is the file to write to.
* @param aIncludePlatedHoles is true if holes marked as plated should be rendered. Default
* is false since the user will usually render these holes in a
* different color.
* @return true if the operation succeeded.
*/
bool Write3DIndices( std::ostream& aOutFile, bool aIncludePlatedHoles = false );
/**
* Add an extra vertex as required by the GLU tesselator.
*
* @param aXpos is the X coordinate of the newly created point.
* @param aYpos is the Y coordinate of the newly created point.
* @param aPlatedHole is true if this point is part of a plated hole.
* @return is the new vertex or NULL if a vertex could not be created.
*/
VERTEX_3D* AddExtraVertex( double aXpos, double aYpos, bool aPlatedHole );
/**
* Invoked by the GLU tesselator callback to notify this object of the type of GL command
* which is applicable to the upcoming vertex list.
*
* @param cmd is the GL command.
*/
void glStart( GLenum cmd );
/**
* Invoked by the GLU tesselator callback; the supplied vertex is added to the internal list
* of vertices awaiting processing upon execution of glEnd()
*
* @param vertex is a vertex forming part of the GL command as previously set by glStart.
*/
void glPushVertex( VERTEX_3D* vertex );
/**
* Invoked by the GLU tesselator callback to notify this object that the vertex list is
* complete and ready for processing.
*/
void glEnd( void );
/**
* Set the error message according to the specified OpenGL error.
*/
void SetGLError( GLenum error_id );
/**
* Inserts all contours into the given tesselator.
*
* This results in the renumbering of all vertices from \a start. Take care when using
* this call since tesselators cannot work on the internal data concurrently.
*
* @param start is the starting number for vertex indices.
* @param tess is a pointer to a GLU Tesselator object.
* @return the number of vertices exported.
*/
int Import( int start, GLUtesselator* aTesselator );
/**
* Return a pointer to the requested vertex or NULL if no such vertex exists.
*
* @param aPointIndex is a vertex index.
* @return the requested vertex or NULL
*/
VERTEX_3D* GetVertexByIndex( int aPointIndex );
/**
* @return the error message related to the last failed operation.
*/
const std::string& GetError( void );
void SetVertexOffsets( double aXoffset, double aYoffset );
/**
* Allocate and populate the 3D vertex and index lists with triangular vertices which may
* be used for rendering a volume.
*
* @param aVertexList will store the vertices.
* @param aIndexPlane will store the indices for the top + bottom planes.
* @param aIndexSide will store the indices for the vertical wall.
* @param aTopZ is the top plane of the model.
* @param aBotZ is the bottom plane of the model.
*/
bool Get3DTriangles( std::vector< double >& aVertexList, std::vector< int >& aIndexPlane,
std::vector< int >& aIndexSide, double aTopZ, double aBotZ );
/**
* Allocate and populate the 3D vertex and index lists with triangular vertices which may
* be used for rendering a plane.
*
* @param aVertexList will store the vertices.
* @param aIndexPlane will store the indices for the plane.
* @param aHeight is the plane of the model.
* @param aTopPlane is true if the plane is a top plane (false = reverse indices).
*/
bool Get2DTriangles( std::vector< double >& aVertexList, std::vector< int > &aIndexPlane,
double aHeight, bool aTopPlane );
private:
void clearTmp( void ); // clear ephemeral data used by the tesselation routine
// add a triangular facet (triplet) to the output index list
bool addTriplet( VERTEX_3D* p0, VERTEX_3D* p1, VERTEX_3D* p2 );
// retrieve a vertex given its index; the vertex may be contained in the
// vertices vector, extra_verts vector, or foreign VRML_LAYER object
VERTEX_3D* getVertexByIndex( int aPointIndex, VRML_LAYER* holes );
void processFan( void ); // process a GL_TRIANGLE_FAN list
void processStrip( void ); // process a GL_TRIANGLE_STRIP list
void processTri( void ); // process a GL_TRIANGLES list
void pushVertices( bool holes ); // push the internal vertices
bool pushOutline( VRML_LAYER* holes ); // push the outline vertices
// calculate number of sides on an arc (angle is in radians)
int calcNSides( double aRadius, double aAngle );
// returns the number of solid or hole contours
int checkNContours( bool holes );
public:
/// set to true when a fault is encountered during tesselation
bool Fault;
private:
// Arc parameters
int maxArcSeg; // maximum number of arc segments in a small circle
@ -123,391 +450,8 @@ private:
VRML_LAYER* pholes; // pointer to another layer object used for tesselation;
// this object is normally expected to hold only holes
GLUtesselator* tess; // local instance of the GLU tesselator
GLenum glcmd; // current GL command type ( fan, triangle, tri-strip, loop )
void clearTmp( void ); // clear ephemeral data used by the tesselation routine
// add a triangular facet (triplet) to the output index list
bool addTriplet( VERTEX_3D* p0, VERTEX_3D* p1, VERTEX_3D* p2 );
// retrieve a vertex given its index; the vertex may be contained in the
// vertices vector, extra_verts vector, or foreign VRML_LAYER object
VERTEX_3D* getVertexByIndex( int aPointIndex, VRML_LAYER* holes );
void processFan( void ); // process a GL_TRIANGLE_FAN list
void processStrip( void ); // process a GL_TRIANGLE_STRIP list
void processTri( void ); // process a GL_TRIANGLES list
void pushVertices( bool holes ); // push the internal vertices
bool pushOutline( VRML_LAYER* holes ); // push the outline vertices
// calculate number of sides on an arc (angle is in radians)
int calcNSides( double aRadius, double aAngle );
// returns the number of solid or hole contours
int checkNContours( bool holes );
public:
/// set to true when a fault is encountered during tesselation
bool Fault;
VRML_LAYER();
virtual ~VRML_LAYER();
/**
* Function GetArcParams
* retrieves the parameters used in calculating the number of vertices in an arc
*
* @param aMaxSeg is the maximum number of segments for an arc with cords of length aMinLength
* @param aMinLength is the minimum length of cords in an arc
* @param aMaxLength is the maximum length of cords in an arc
*/
void GetArcParams( int& aMaxSeg, double& aMinLength, double& aMaxLength );
/**
* Function SetArcParams
* sets the parameters used in calculating the number of vertices in an arc.
* The default settings are reasonable for rendering for unit lengths of 1mm
*
* @param aMaxSeg is the maximum number of segments for an arc with cords of length aMinLength
* @param aMinLength is the minimum length of cords in an arc
* @param aMaxLength is the maximum length of cords in an arc
*
* @return bool: true if the parameters were accepted
*/
bool SetArcParams( int aMaxSeg, double aMinLength, double aMaxLength );
/**
* Resets the parameters used in calculating the number of vertices in an arc
* to default values
*/
void ResetArcParams();
/**
* Function Clear
* erases all data except for arc parameters.
*/
void Clear( void );
/**
* Function GetSize
* returns the total number of vertices indexed
*/
int GetSize( void );
/**
* Function GetNConours
* returns the number of stored contours
*/
int GetNContours( void )
{
return contours.size();
}
/**
* Function NewContour
* creates a new list of vertices and returns an index to the list
*
* @param aPlatedHole is true if the new contour will represent a plated hole
*
* @return int: index to the list or -1 if the operation failed
*/
int NewContour( bool aPlatedHole = false );
/**
* Function AddVertex
* adds a point to the requested contour
*
* @param aContour is an index previously returned by a call to NewContour()
* @param aXpos is the X coordinate of the vertex
* @param aYpos is the Y coordinate of the vertex
*
* @return bool: true if the vertex was added
*/
bool AddVertex( int aContourID, double aXpos, double aYpos );
/**
* Function EnsureWinding
* checks the winding of a contour and ensures that it is a hole or
* a solid depending on the value of @param hole
*
* @param aContour is an index to a contour as returned by NewContour()
* @param aHoleFlag determines if the contour must be a hole
*
* @return bool: true if the operation succeeded
*/
bool EnsureWinding( int aContourID, bool aHoleFlag );
/**
* Function AppendCircle
* adds a circular contour to the specified (empty) contour
*
* @param aXpos is the X coordinate of the hole center
* @param aYpos is the Y coordinate of the hole center
* @param aRadius is the radius of the hole
* @param aContourID is the contour index
* @param aHoleFlag determines if the contour to be created is a cutout
*
* @return bool: true if the new contour was successfully created
*/
bool AppendCircle( double aXpos, double aYpos, double aRadius,
int aContourID, bool aHoleFlag = false );
/**
* Function AddCircle
* creates a circular contour and adds it to the internal list
*
* @param aXpos is the X coordinate of the hole center
* @param aYpos is the Y coordinate of the hole center
* @param aRadius is the radius of the hole
* @param aHoleFlag determines if the contour to be created is a cutout
* @param aPlatedHole is true if this is a plated hole
*
* @return bool: true if the new contour was successfully created
*/
bool AddCircle( double aXpos, double aYpos, double aRadius,
bool aHoleFlag = false, bool aPlatedHole = false );
/**
* Function AddSlot
* creates and adds a slot feature to the list of contours
*
* @param aCenterX is the X coordinate of the slot's center
* @param aCenterY is the Y coordinate of the slot's center
* @param aSlotLength is the length of the slot along the major axis
* @param aSlotWidth is the width of the slot along the minor axis
* @param aAngle (degrees) is the orientation of the slot
* @param aHoleFlag determines whether the slot is a hole or a solid
* @param aPlatedHole is true if this is a plated slot
*
* @return bool: true if the slot was successfully created
*/
bool AddSlot( double aCenterX, double aCenterY, double aSlotLength, double aSlotWidth,
double aAngle, bool aHoleFlag = false, bool aPlatedHole = false );
/**
* Function AppendArc
* adds an arc to the specified contour
*
* @param aCenterX is the X coordinate of the arc's center
* @param aCenterY is the Y coordinate of the arc's center
* @param aRadius is the radius of the arc
* @param aStartAngle (degrees) is the starting angle of the arc
* @param aAngle (degrees) is the measure of the arc
* @param aContourID is the contour's index
*
* @return bool: true if the slot was successfully created
*/
bool AppendArc( double aCenterX, double aCenterY, double aRadius,
double aStartAngle, double aAngle, int aContourID );
/**
* Function AddArc
* creates a slotted arc and adds it to the internal list of contours
*
* @param aCenterX is the X coordinate of the arc's center
* @param aCenterY is the Y coordinate of the arc's center
* @param aStartX is the X coordinate of the starting point
* @param aStartY is the Y coordinate of the starting point
* @param aArcWidth is the width of the arc
* @param aAngle is the included angle (degrees)
* @param aHoleFlag determines whether the arc is to be a hole or a solid
* @param aPlatedHole is true if this is a plated slotted arc
*
* @return bool: true if the feature was successfully created
*/
bool AddArc( double aCenterX, double aCenterY,
double aStartX, double aStartY,
double aArcWidth, double aAngle,
bool aHoleFlag = false, bool aPlatedHole = false );
/**
* Function AddPolygon
* creates an arbitrary polygon and adds it to the list of contours
*
* @param aPolySet is the set of polygon points
* @param aCenterX is the X coordinate of the polygon's center
* @param aCenterY is the Y coordinate of the polygon's center
* @param aAngle is the rotation angle (degrees) of the pad
*/
bool AddPolygon( const std::vector< wxRealPoint >& aPolySet,
double aCenterX, double aCenterY, double aAngle );
/**
* Function Tesselate
* creates a list of outline vertices as well as the
* vertex sets required to render the surface.
*
* @param holes is an optional pointer to cutouts to be imposed on the
* surface.
* @param aHolesOnly is true if the outline contains only holes
*
* @return bool: true if the operation succeeded
*/
bool Tesselate( VRML_LAYER* holes = NULL, bool aHolesOnly = false );
/**
* Function WriteVertices
* writes out the list of vertices required to render a
* planar surface.
*
* @param aZcoord is the Z coordinate of the plane
* @param aOutFile is the file to write to
* @param aPrecision is the precision of the output coordinates
*
* @return bool: true if the operation succeeded
*/
bool WriteVertices( double aZcoord, std::ostream& aOutFile, int aPrecision );
/**
* Function Write3DVertices
* writes out the list of vertices required to render an extruded solid
*
* @param aTopZ is the Z coordinate of the top plane
* @param aBottomZ is the Z coordinate of the bottom plane
* @param aOutFile is the file to write to
* @param aPrecision is the precision of the output coordinates
*
* @return bool: true if the operation succeeded
*/
bool Write3DVertices( double aTopZ, double aBottomZ, std::ostream& aOutFile, int aPrecision );
/**
* Function WriteIndices
* writes out the vertex sets required to render a planar
* surface.
*
* @param aTopFlag is true if the surface is to be visible from above;
* if false the surface will be visible from below.
* @param aOutFile is the file to write to
*
* @return bool: true if the operation succeeded
*/
bool WriteIndices( bool aTopFlag, std::ostream& aOutFile );
/**
* Function Write3DIndices
* writes out the vertex sets required to render an extruded solid
*
* @param aOutFile is the file to write to
* @param aIncludePlatedHoles is true if holes marked as plated should
* be rendered. Default is false since the user will usually
* render these holes in a different color
*
* @return bool: true if the operation succeeded
*/
bool Write3DIndices( std::ostream& aOutFile, bool aIncludePlatedHoles = false );
/**
* Function AddExtraVertex
* adds an extra vertex as required by the GLU tesselator.
*
* @param aXpos is the X coordinate of the newly created point
* @param aYpos is the Y coordinate of the newly created point
* @param aPlatedHole is true if this point is part of a plated hole
*
* @return VERTEX_3D*: is the new vertex or NULL if a vertex
* could not be created.
*/
VERTEX_3D* AddExtraVertex( double aXpos, double aYpos, bool aPlatedHole );
/**
* Function glStart
* is invoked by the GLU tesselator callback to notify this object
* of the type of GL command which is applicable to the upcoming
* vertex list.
*
* @param cmd is the GL command
*/
void glStart( GLenum cmd );
/**
* Function glPushVertex
* is invoked by the GLU tesselator callback; the supplied vertex is
* added to the internal list of vertices awaiting processing upon
* execution of glEnd()
*
* @param vertex is a vertex forming part of the GL command as previously
* set by glStart
*/
void glPushVertex( VERTEX_3D* vertex );
/**
* Function glEnd
* is invoked by the GLU tesselator callback to notify this object
* that the vertex list is complete and ready for processing
*/
void glEnd( void );
/**
* Function SetGLError
* sets the error message according to the specified OpenGL error
*/
void SetGLError( GLenum error_id );
/**
* Function Import
* inserts all contours into the given tesselator; this
* results in the renumbering of all vertices from @param start.
* Take care when using this call since tesselators cannot work on
* the internal data concurrently.
*
* @param start is the starting number for vertex indices
* @param tess is a pointer to a GLU Tesselator object
*
* @return int: the number of vertices exported
*/
int Import( int start, GLUtesselator* aTesselator );
/**
* Function GetVertexByIndex
* returns a pointer to the requested vertex or
* NULL if no such vertex exists.
*
* @param aPointIndex is a vertex index
*
* @return VERTEX_3D*: the requested vertex or NULL
*/
VERTEX_3D* GetVertexByIndex( int aPointIndex );
/*
* Function GetError
* Returns the error message related to the last failed operation
*/
const std::string& GetError( void );
void SetVertexOffsets( double aXoffset, double aYoffset );
/**
* Function Get3DTriangles
* Allocates and populates the 3D vertex and index lists with
* triangular vertices which may be used for rendering a volume
*
* @param aVertexList will store the vertices
* @param aIndexPlane will store the indices for the top + bottom planes
* @param aIndexSide will store the indices for the vertical wall
* @param aTopZ is the top plane of the model
* @param aBotZ is the bottom plane of the model
*/
bool Get3DTriangles( std::vector< double >& aVertexList,
std::vector< int > &aIndexPlane, std::vector< int > &aIndexSide,
double aTopZ, double aBotZ );
/**
* Function Get2DTriangles
* Allocates and populates the 3D vertex and index lists with
* triangular vertices which may be used for rendering a plane
*
* @param aVertexList will store the vertices
* @param aIndexPlane will store the indices for the plane
* @param aHeight is the plane of the model
* @param aTopPlane is true if the plane is a top plane (false = reverse indices)
*/
bool Get2DTriangles( std::vector< double >& aVertexList,
std::vector< int > &aIndexPlane, double aHeight, bool aTopPlane );
GLUtesselator* tess; // local instance of the GLU tesselator
GLenum glcmd; // current GL command type ( fan, triangle, tri-strip, loop )
};
#endif // VRML_LAYER_H