kicad/utils/idftools/idf_outlines.cpp

3633 lines
101 KiB
C++

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* 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
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <iostream>
#include <iomanip>
#include <sstream>
#include <cmath>
#include <utility>
#include <idf_helpers.h>
#include <idf_outlines.h>
#include <idf_parser.h>
using namespace IDF3;
using namespace std;
static std::string GetOutlineTypeString( IDF3::OUTLINE_TYPE aOutlineType )
{
switch( aOutlineType )
{
case OTLN_BOARD:
return ".BOARD_OUTLINE";
case OTLN_OTHER:
return ".OTHER_OUTLINE";
case OTLN_PLACE:
return ".PLACEMENT_OUTLINE";
case OTLN_ROUTE:
return ".ROUTE_OUTLINE";
case OTLN_PLACE_KEEPOUT:
return ".PLACE_KEEPOUT";
case OTLN_ROUTE_KEEPOUT:
return ".ROUTE_KEEPOUT";
case OTLN_VIA_KEEPOUT:
return ".VIA_KEEPOUT";
case OTLN_GROUP_PLACE:
return ".PLACE_REGION";
case OTLN_COMPONENT:
return "COMPONENT OUTLINE";
default:
break;
}
std::ostringstream ostr;
ostr << "[INVALID OUTLINE TYPE VALUE]:" << aOutlineType;
return ostr.str();
}
#ifndef DISABLE_IDF_OWNERSHIP
static bool CheckOwnership( int aSourceLine, const char* aSourceFunc,
IDF3_BOARD* aParent, IDF3::KEY_OWNER aOwnerCAD,
IDF3::OUTLINE_TYPE aOutlineType, std::string& aErrorString )
{
if( aParent == nullptr )
{
ostringstream ostr;
ostr << "* " << __FILE__ << ":" << aSourceLine << ":" << aSourceFunc << "():\n";
ostr << "* BUG: outline's parent not set; cannot enforce ownership rules\n";
ostr << "* outline type: " << GetOutlineTypeString( aOutlineType );
aErrorString = ostr.str();
return false;
}
// note: component outlines have no owner so we don't care about
// who modifies them
if( aOwnerCAD == UNOWNED || aOutlineType == IDF3::OTLN_COMPONENT )
return true;
IDF3::CAD_TYPE parentCAD = aParent->GetCadType();
if( aOwnerCAD == MCAD && parentCAD == CAD_MECH )
return true;
if( aOwnerCAD == ECAD && parentCAD == CAD_ELEC )
return true;
do
{
ostringstream ostr;
ostr << __FILE__ << ":" << aSourceLine << ":" << aSourceFunc << "():\n";
ostr << "* ownership violation; CAD type is ";
if( parentCAD == CAD_MECH )
ostr << "MCAD ";
else
ostr << "ECAD ";
ostr << "while outline owner is " << GetOwnerString( aOwnerCAD ) << "\n";
ostr << "* outline type: " << GetOutlineTypeString( aOutlineType );
aErrorString = ostr.str();
} while( 0 );
return false;
}
#endif
BOARD_OUTLINE::BOARD_OUTLINE()
{
outlineType = OTLN_BOARD;
single = false;
owner = UNOWNED;
parent = nullptr;
thickness = 0.0;
unit = UNIT_MM;
}
BOARD_OUTLINE::~BOARD_OUTLINE()
{
clear();
}
IDF3::OUTLINE_TYPE BOARD_OUTLINE::GetOutlineType( void )
{
return outlineType;
}
void BOARD_OUTLINE::readOutlines( std::istream& aBoardFile, IDF3::IDF_VERSION aIdfVersion )
{
// reads the outline data from a file
double x, y, ang;
double dLoc = 1e-5; // distances are equal when closer than 0.1 micron
bool comment = false;
bool quoted = false;
bool closed = false;
int idx = 0;
int loopidx = -1;
int tmp = 0;
int npts = 0;
std::string iline;
std::string entry;
std::stringstream tstr;
IDF_OUTLINE* op = nullptr;
IDF_SEGMENT* sp = nullptr;
IDF_POINT prePt;
IDF_POINT curPt;
std::streampos pos;
// destroy any existing outline data
clearOutlines();
while( aBoardFile.good() )
{
if( !FetchIDFLine( aBoardFile, iline, comment, pos ) )
continue;
idx = 0;
GetIDFString( iline, entry, quoted, idx );
if( quoted )
{
ostringstream ostr;
ostr << "\n* invalid outline: RECORD 3, FIELD 1 of " <<
GetOutlineTypeString( outlineType );
ostr << " is quoted\n";
ostr << "* line: '" << iline << "'";
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
// check for the end of the section
if( entry.size() >= 5 && CompareToken( ".END_", entry.substr( 0, 5 ) ) )
{
// rewind to the start of the last line; the routine invoking
// this is responsible for checking that the current '.END_ ...'
// matches the section header.
if( aBoardFile.eof() )
aBoardFile.clear();
aBoardFile.seekg( pos );
if( outlines.size() > 0 )
{
if( npts > 0 && !closed )
{
ostringstream ostr;
ostr << "invalid outline (not closed)\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
// verify winding
if( !single )
{
if( !outlines.front()->IsCCW() )
{
ERROR_IDF << "invalid IDF3 file (BOARD_OUTLINE)\n";
cerr << "* WARNING: first outline is not in CCW order\n";
return;
}
if( outlines.size() > 1 && outlines.back()->IsCCW() &&
!outlines.back()->IsCircle() )
{
ERROR_IDF << "invalid IDF3 file (BOARD_OUTLINE)\n";
cerr << "* WARNING: final cutout does not have points in CW order\n";
cerr << "* file position: " << pos << "\n";
return;
}
}
}
return;
}
tstr.clear();
tstr << entry;
tstr >> tmp;
if( tstr.fail() )
{
if( outlineType == OTLN_COMPONENT && CompareToken( "PROP", entry ) )
{
aBoardFile.seekg( pos );
return;
}
do
{
ostringstream ostr;
ostr << "\n* invalid outline: RECORD 3, FIELD 1 of " <<
GetOutlineTypeString( outlineType );
ostr << " is not numeric\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
} while( 0 );
}
if( tmp != loopidx )
{
// index change
if( npts > 0 && !closed )
{
ostringstream ostr;
ostr << "invalid outline ( outline # " << loopidx << " not closed)\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( tmp < 0 )
{
ostringstream ostr;
ostr << "\n* invalid outline: RECORD 3, FIELD 1 of " <<
GetOutlineTypeString( outlineType );
ostr << " is invalid\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( loopidx == -1 )
{
// first outline
if( single )
{
// outline may have a Loop Index of 0 or 1
if( tmp == 0 || tmp == 1 )
{
op = new IDF_OUTLINE;
if( op == nullptr )
{
clearOutlines();
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"memory allocation failed" ) );
}
outlines.push_back( op );
loopidx = tmp;
}
else
{
ostringstream ostr;
ostr << "\n* invalid outline: RECORD 3, FIELD 1 of " <<
GetOutlineTypeString( outlineType );
ostr << " is invalid (must be 0 or 1)\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
}
else
{
// outline *MUST* have a Loop Index of 0
if( tmp != 0 )
{
ostringstream ostr;
ostr << "\n* invalid outline: RECORD 3, FIELD 1 of " <<
GetOutlineTypeString( outlineType );
ostr << " is invalid (must be 0)\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
op = new IDF_OUTLINE;
if( op == nullptr )
{
clearOutlines();
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"memory allocation failed" ) );
}
outlines.push_back( op );
loopidx = tmp;
}
}
else
{
// outline for cutout
if( single )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType );
ostr << " section may only have one outline\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( tmp - loopidx != 1 )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType );
ostr << " section must have cutouts in numeric order from 1 onwards\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
// verify winding of previous outline
if( ( loopidx == 0 && !op->IsCCW() )
|| ( loopidx > 0 && op->IsCCW() && !op->IsCircle() ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation of loop point order rules by Loop Index " << loopidx <<
"\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
op = new IDF_OUTLINE;
if( op == nullptr )
{
clearOutlines();
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"memory allocation failed" ) );
}
outlines.push_back( op );
loopidx = tmp;
}
// end of index change code
npts = 0;
closed = false;
}
if( op == nullptr )
{
ostringstream ostr;
ostr << "\n* invalid outline: RECORD 3, FIELD 1 of " <<
GetOutlineTypeString( outlineType );
ostr << " is invalid\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( !GetIDFString( iline, entry, quoted, idx ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: RECORD 3, FIELD 2 of ";
ostr << GetOutlineTypeString( outlineType ) << " does not exist\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( quoted )
{
ostringstream ostr;
ostr << "\n* invalid outline: RECORD 3, FIELD 2 of ";
ostr << GetOutlineTypeString( outlineType ) << " must not be in quotes\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
tstr.clear();
tstr << entry;
tstr >> x;
if( tstr.fail() )
{
ostringstream ostr;
ostr << "\n* invalid outline: RECORD 3, FIELD 2 of ";
ostr << GetOutlineTypeString( outlineType ) << " is an invalid X value\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( !GetIDFString( iline, entry, quoted, idx ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: RECORD 3, FIELD 3 of ";
ostr << GetOutlineTypeString( outlineType ) << " does not exist\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( quoted )
{
ostringstream ostr;
ostr << "\n* invalid outline: RECORD 3, FIELD 3 of ";
ostr << GetOutlineTypeString( outlineType ) << " must not be in quotes\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
tstr.clear();
tstr << entry;
tstr >> y;
if( tstr.fail() )
{
ostringstream ostr;
ostr << "\n* invalid outline: RECORD 3, FIELD 3 of ";
ostr << GetOutlineTypeString( outlineType ) << " is an invalid Y value\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( !GetIDFString( iline, entry, quoted, idx ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: RECORD 3, FIELD 4 of ";
ostr << GetOutlineTypeString( outlineType ) << " does not exist\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( quoted )
{
ostringstream ostr;
ostr << "\n* invalid outline: RECORD 3, FIELD 4 of ";
ostr << GetOutlineTypeString( outlineType ) << " must not be in quotes\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
tstr.clear();
tstr << entry;
tstr >> ang;
if( tstr.fail() )
{
ostringstream ostr;
ostr << "\n* invalid outline: RECORD 3, FIELD 4 of ";
ostr << GetOutlineTypeString( outlineType ) << " is not a valid angle\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
// the line was successfully read; convert to mm if necessary
if( unit == UNIT_THOU )
{
x *= IDF_THOU_TO_MM;
y *= IDF_THOU_TO_MM;
}
else if( ( aIdfVersion == IDF_V2 ) && ( unit == UNIT_TNM ) )
{
x *= IDF_TNM_TO_MM;
y *= IDF_TNM_TO_MM;
}
else if( unit != UNIT_MM )
{
ostringstream ostr;
ostr << "\n* BUG: invalid UNIT type: " << unit;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( npts++ == 0 )
{
// first point
prePt.x = x;
prePt.y = y;
// ensure that the first point is not an arc specification
if( ang < -MIN_ANG || ang > MIN_ANG )
{
ostringstream ostr;
ostr << "\n* invalid outline: RECORD 3 of ";
ostr << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: first point of an outline has a non-zero angle\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
}
else
{
// Nth point
if( closed )
{
ostringstream ostr;
ostr << "\n* invalid outline: RECORD 3 of ";
ostr << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: adding a segment to a closed outline\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
curPt.x = x;
curPt.y = y;
if( ang > -MIN_ANG && ang < MIN_ANG )
{
sp = new IDF_SEGMENT( prePt, curPt );
}
else
{
sp = new IDF_SEGMENT( prePt, curPt, ang, false );
}
if( sp == nullptr )
{
clearOutlines();
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"memory allocation failed" ) );
}
if( sp->IsCircle() )
{
// this is a circle; the loop is closed
if( op->size() != 0 )
{
delete sp;
ostringstream ostr;
ostr << "\n* invalid outline: RECORD 3 of ";
ostr << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: adding a circle to a non-empty outline\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
closed = true;
}
else if( op->size() != 0 )
{
if( curPt.Matches( op->front()->startPoint, dLoc ) )
closed = true;
}
op->push( sp );
prePt.x = x;
prePt.y = y;
}
}
// NOTE:
// 1. ideally we would ensure that there are no arcs with a radius of 0
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"problems reading file (premature end of outline)" ) );
return;
}
bool BOARD_OUTLINE::writeComments( std::ostream& aBoardFile )
{
if( comments.empty() )
return true;
list< string >::const_iterator itS = comments.begin();
list< string >::const_iterator itE = comments.end();
while( itS != itE )
{
aBoardFile << "# " << *itS << "\n";
++itS;
}
return !aBoardFile.fail();
}
bool BOARD_OUTLINE::writeOwner( std::ostream& aBoardFile )
{
switch( owner )
{
case ECAD:
aBoardFile << "ECAD\n";
break;
case MCAD:
aBoardFile << "MCAD\n";
break;
default:
aBoardFile << "UNOWNED\n";
break;
}
return !aBoardFile.fail();
}
void BOARD_OUTLINE::writeOutline( std::ostream& aBoardFile, IDF_OUTLINE* aOutline, size_t aIndex )
{
std::list<IDF_SEGMENT*>::iterator bo;
std::list<IDF_SEGMENT*>::iterator eo;
if( !aOutline )
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"\n* BUG: nullptr outline pointer" ) );
if( aOutline->size() == 1 )
{
if( !aOutline->front()->IsCircle() )
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"bad outline (single segment item, not circle)" ) );
if( single )
aIndex = 0;
// NOTE: a circle always has an angle of 360, never -360,
// otherwise SolidWorks chokes on the file.
if( unit != UNIT_THOU )
{
aBoardFile << aIndex << " " << setiosflags(ios::fixed) << setprecision(5)
<< aOutline->front()->startPoint.x << " "
<< aOutline->front()->startPoint.y << " 0\n";
aBoardFile << aIndex << " " << setiosflags(ios::fixed) << setprecision(5)
<< aOutline->front()->endPoint.x << " "
<< aOutline->front()->endPoint.y << " 360\n";
}
else
{
aBoardFile << aIndex << " " << setiosflags(ios::fixed) << setprecision(1)
<< (aOutline->front()->startPoint.x / IDF_THOU_TO_MM) << " "
<< (aOutline->front()->startPoint.y / IDF_THOU_TO_MM) << " 0\n";
aBoardFile << aIndex << " " << setiosflags(ios::fixed) << setprecision(1)
<< (aOutline->front()->endPoint.x / IDF_THOU_TO_MM) << " "
<< (aOutline->front()->endPoint.y / IDF_THOU_TO_MM) << " 360\n";
}
return;
}
if( single )
{
// only indices 0 (CCW) and 1 (CW) are valid; set the index according to
// the outline's winding
if( aOutline->IsCCW() )
aIndex = 0;
else
aIndex = 1;
}
// check if we must reverse things
if( ( aOutline->IsCCW() && ( aIndex > 0 ) ) || ( ( !aOutline->IsCCW() ) && ( aIndex == 0 ) ) )
{
eo = aOutline->begin();
bo = aOutline->end();
--bo;
// ensure that the very last point is the same as the very first point
if( aOutline->size() > 1 )
{
std::list<IDF_SEGMENT*>::iterator to = eo;
++to;
(*to)->startPoint = (*eo)->endPoint;
}
// for the first item we write out both points
if( unit != UNIT_THOU )
{
if( aOutline->front()->angle < MIN_ANG && aOutline->front()->angle > -MIN_ANG )
{
aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 5 )
<< aOutline->front()->endPoint.x << " " << aOutline->front()->endPoint.y
<< " 0\n";
aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 5 )
<< aOutline->front()->startPoint.x << " "
<< aOutline->front()->startPoint.y << " 0\n";
}
else
{
aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 5 )
<< aOutline->front()->endPoint.x << " " << aOutline->front()->endPoint.y
<< " 0\n";
aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 5 )
<< aOutline->front()->startPoint.x << " "
<< aOutline->front()->startPoint.y << " " << setprecision( 3 )
<< -aOutline->front()->angle << "\n";
}
}
else
{
if( aOutline->front()->angle < MIN_ANG && aOutline->front()->angle > -MIN_ANG )
{
aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 1 )
<< ( aOutline->front()->endPoint.x / IDF_THOU_TO_MM ) << " "
<< ( aOutline->front()->endPoint.y / IDF_THOU_TO_MM ) << " 0\n";
aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 1 )
<< ( aOutline->front()->startPoint.x / IDF_THOU_TO_MM ) << " "
<< ( aOutline->front()->startPoint.y / IDF_THOU_TO_MM ) << " 0\n";
}
else
{
aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 1 )
<< ( aOutline->front()->endPoint.x / IDF_THOU_TO_MM ) << " "
<< ( aOutline->front()->endPoint.y / IDF_THOU_TO_MM ) << " 0\n";
aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 1 )
<< ( aOutline->front()->startPoint.x / IDF_THOU_TO_MM ) << " "
<< ( aOutline->front()->startPoint.y / IDF_THOU_TO_MM ) << " "
<< setprecision( 3 ) << -aOutline->front()->angle << "\n";
}
}
// for all other segments we only write out the start point
while( bo != eo )
{
if( unit != UNIT_THOU )
{
if( ( *bo )->angle < MIN_ANG && ( *bo )->angle > -MIN_ANG )
{
aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 5 )
<< ( *bo )->startPoint.x << " " << ( *bo )->startPoint.y << " 0\n";
}
else
{
aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 5 )
<< ( *bo )->startPoint.x << " " << ( *bo )->startPoint.y << " "
<< setprecision( 3 ) << -( *bo )->angle << "\n";
}
}
else
{
if( ( *bo )->angle < MIN_ANG && ( *bo )->angle > -MIN_ANG )
{
aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 1 )
<< ( ( *bo )->startPoint.x / IDF_THOU_TO_MM ) << " "
<< ( ( *bo )->startPoint.y / IDF_THOU_TO_MM ) << " 0\n";
}
else
{
aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 1 )
<< ( ( *bo )->startPoint.x / IDF_THOU_TO_MM ) << " "
<< ( ( *bo )->startPoint.y / IDF_THOU_TO_MM ) << " "
<< setprecision( 3 ) << -( *bo )->angle << "\n";
}
}
--bo;
}
}
else
{
// ensure that the very last point is the same as the very first point
if( aOutline->size() > 1 )
aOutline->back()-> endPoint = aOutline->front()->startPoint;
bo = aOutline->begin();
eo = aOutline->end();
// for the first item we write out both points
if( unit != UNIT_THOU )
{
if( ( *bo )->angle < MIN_ANG && ( *bo )->angle > -MIN_ANG )
{
aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 5 )
<< ( *bo )->startPoint.x << " " << ( *bo )->startPoint.y << " 0\n";
aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 5 )
<< ( *bo )->endPoint.x << " " << ( *bo )->endPoint.y << " 0\n";
}
else
{
aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 5 )
<< ( *bo )->startPoint.x << " " << ( *bo )->startPoint.y << " 0\n";
aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 5 )
<< ( *bo )->endPoint.x << " " << ( *bo )->endPoint.y << " "
<< setprecision( 3 ) << ( *bo )->angle << "\n";
}
}
else
{
if( ( *bo )->angle < MIN_ANG && ( *bo )->angle > -MIN_ANG )
{
aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 1 )
<< ( ( *bo )->startPoint.x / IDF_THOU_TO_MM ) << " "
<< ( ( *bo )->startPoint.y / IDF_THOU_TO_MM ) << " 0\n";
aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 1 )
<< ( ( *bo )->endPoint.x / IDF_THOU_TO_MM ) << " "
<< ( ( *bo )->endPoint.y / IDF_THOU_TO_MM ) << " 0\n";
}
else
{
aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 1 )
<< ( ( *bo )->startPoint.x / IDF_THOU_TO_MM ) << " "
<< ( ( *bo )->startPoint.y / IDF_THOU_TO_MM ) << " 0\n";
aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 1 )
<< ( ( *bo )->endPoint.x / IDF_THOU_TO_MM ) << " "
<< ( ( *bo )->endPoint.y / IDF_THOU_TO_MM ) << " " << setprecision( 3 )
<< ( *bo )->angle << "\n";
}
}
++bo;
// for all other segments we only write out the last point
while( bo != eo )
{
if( unit != UNIT_THOU )
{
if( ( *bo )->angle < MIN_ANG && ( *bo )->angle > -MIN_ANG )
{
aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 5 )
<< ( *bo )->endPoint.x << " " << ( *bo )->endPoint.y << " 0\n";
}
else
{
aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 5 )
<< ( *bo )->endPoint.x << " " << ( *bo )->endPoint.y << " "
<< setprecision( 3 ) << ( *bo )->angle << "\n";
}
}
else
{
if( ( *bo )->angle < MIN_ANG && ( *bo )->angle > -MIN_ANG )
{
aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 1 )
<< ( ( *bo )->endPoint.x / IDF_THOU_TO_MM ) << " "
<< ( ( *bo )->endPoint.y / IDF_THOU_TO_MM ) << " 0\n";
}
else
{
aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 1 )
<< ( ( *bo )->endPoint.x / IDF_THOU_TO_MM ) << " "
<< ( ( *bo )->endPoint.y / IDF_THOU_TO_MM ) << " "
<< setprecision( 3 ) << ( *bo )->angle << "\n";
}
}
++bo;
}
}
}
void BOARD_OUTLINE::writeOutlines( std::ostream& aBoardFile )
{
if( outlines.empty() )
return;
int idx = 0;
std::list< IDF_OUTLINE* >::iterator itS = outlines.begin();
std::list< IDF_OUTLINE* >::iterator itE = outlines.end();
while( itS != itE )
{
writeOutline( aBoardFile, *itS, idx++ );
++itS;
}
}
bool BOARD_OUTLINE::SetUnit( IDF3::IDF_UNIT aUnit )
{
// note: although UNIT_TNM is accepted here without reservation,
// this can only affect data being read from a file.
if( aUnit != UNIT_MM && aUnit != UNIT_THOU && aUnit != UNIT_TNM )
{
ostringstream ostr;
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
ostr << "* BUG: invalid IDF UNIT (must be one of UNIT_MM or UNIT_THOU): " << aUnit << "\n";
ostr << "* outline type: " << GetOutlineTypeString( outlineType );
errormsg = ostr.str();
return false;
}
unit = aUnit;
return true;
}
IDF3::IDF_UNIT BOARD_OUTLINE::GetUnit( void )
{
return unit;
}
bool BOARD_OUTLINE::setThickness( double aThickness )
{
if( aThickness < 0.0 )
{
ostringstream ostr;
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
ostr << "* BUG: aThickness < 0.0\n";
ostr << "* outline type: " << GetOutlineTypeString( outlineType );
errormsg = ostr.str();
return false;
}
thickness = aThickness;
return true;
}
bool BOARD_OUTLINE::SetThickness( double aThickness )
{
#ifndef DISABLE_IDF_OWNERSHIP
if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
return false;
#endif
return setThickness( aThickness );
}
double BOARD_OUTLINE::GetThickness( void )
{
return thickness;
}
void BOARD_OUTLINE::readData( std::istream& aBoardFile, const std::string& aHeader,
IDF3::IDF_VERSION aIdfVersion )
{
// BOARD_OUTLINE (PANEL_OUTLINE)
// .BOARD_OUTLINE [OWNER]
// [thickness]
// [outlines]
// check RECORD 1
std::string token;
bool quoted = false;
int idx = 0;
std::streampos pos;
pos = aBoardFile.tellg();
if( !GetIDFString( aHeader, token, quoted, idx ) )
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"invalid invocation: blank header line" ) );
if( quoted )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: section names may not be in quotes\n";
ostr << "* line: '" << aHeader << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( !CompareToken( ".BOARD_OUTLINE", token ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: not a board outline\n";
ostr << "* line: '" << aHeader << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( !GetIDFString( aHeader, token, quoted, idx ) )
{
if( aIdfVersion > IDF_V2 )
ERROR_IDF << "no OWNER; setting to UNOWNED\n";
owner = UNOWNED;
}
else
{
if( !ParseOwner( token, owner ) )
{
ERROR_IDF << "invalid OWNER (reverting to UNOWNED): " << token << "\n";
owner = UNOWNED;
}
}
// check RECORD 2
std::string iline;
bool comment = false;
while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) );
if( ( !aBoardFile.good() && !aBoardFile.eof() ) || iline.empty() )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: premature end\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
idx = 0;
if( comment )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: comment within .BOARD_OUTLINE section\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( !GetIDFString( iline, token, quoted, idx ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: no thickness specified\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
std::stringstream teststr;
teststr << token;
teststr >> thickness;
if( teststr.fail() )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: invalid RECORD 2 (thickness)\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( unit == UNIT_THOU )
{
thickness *= IDF_THOU_TO_MM;
}
else if( ( aIdfVersion == IDF_V2 ) && ( unit == UNIT_TNM ) )
{
thickness *= IDF_TNM_TO_MM;
}
else if( unit != UNIT_MM )
{
ostringstream ostr;
ostr << "\n* BUG: invalid UNIT type: " << unit;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
// for some unknown reason IDF allows 0 or negative thickness, but this
// is a problem so we fix it here
if( thickness <= 0.0 )
{
if( thickness == 0.0 )
{
ERROR_IDF << "\n* WARNING: setting board thickness to default 1.6mm (";
cerr << thickness << ")\n";
thickness = 1.6;
}
else
{
thickness = -thickness;
ERROR_IDF << "\n* WARNING: setting board thickness to positive number (";
cerr << thickness << ")\n";
}
}
// read RECORD 3 values
readOutlines( aBoardFile, aIdfVersion );
// check RECORD 4
while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) );
if( ( !aBoardFile.good() && aBoardFile.eof() ) || iline.empty() )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: premature end\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
idx = 0;
if( comment )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: comment within section\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( !CompareToken( ".END_BOARD_OUTLINE", iline ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: no .END_BOARD_OUTLINE found\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
}
void BOARD_OUTLINE::writeData( std::ostream& aBoardFile )
{
writeComments( aBoardFile );
// note: a BOARD_OUTLINE section is required, even if it is empty
aBoardFile << ".BOARD_OUTLINE ";
writeOwner( aBoardFile );
if( unit != UNIT_THOU )
aBoardFile << setiosflags( ios::fixed ) << setprecision( 5 ) << thickness << "\n";
else
aBoardFile << setiosflags( ios::fixed ) << setprecision( 1 )
<< ( thickness / IDF_THOU_TO_MM ) << "\n";
writeOutlines( aBoardFile );
aBoardFile << ".END_BOARD_OUTLINE\n\n";
}
void BOARD_OUTLINE::clear( void )
{
comments.clear();
clearOutlines();
owner = UNOWNED;
return;
}
bool BOARD_OUTLINE::Clear( void )
{
#ifndef DISABLE_IDF_OWNERSHIP
if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
return false;
#endif
clear();
return true;
}
void BOARD_OUTLINE::setParent( IDF3_BOARD* aParent )
{
parent = aParent;
}
IDF3_BOARD* BOARD_OUTLINE::GetParent( void )
{
return parent;
}
bool BOARD_OUTLINE::addOutline( IDF_OUTLINE* aOutline )
{
std::list< IDF_OUTLINE* >::iterator itS = outlines.begin();
std::list< IDF_OUTLINE* >::iterator itE = outlines.end();
try
{
while( itS != itE )
{
if( *itS == aOutline )
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"duplicate outline pointer" ) );
++itS;
}
outlines.push_back( aOutline );
}
catch( const std::exception& e )
{
errormsg = e.what();
return false;
}
return true;
}
bool BOARD_OUTLINE::AddOutline( IDF_OUTLINE* aOutline )
{
#ifndef DISABLE_IDF_OWNERSHIP
if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
return false;
#endif
return addOutline( aOutline );
}
bool BOARD_OUTLINE::DelOutline( IDF_OUTLINE* aOutline )
{
std::list< IDF_OUTLINE* >::iterator itS = outlines.begin();
std::list< IDF_OUTLINE* >::iterator itE = outlines.end();
if( !aOutline )
{
ostringstream ostr;
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
ostr << "* BUG: nullptr aOutline pointer\n";
ostr << "* outline type: " << GetOutlineTypeString( outlineType );
errormsg = ostr.str();
return false;
}
if( outlines.empty() )
{
errormsg.clear();
return false;
}
// if there are more than 1 outlines it makes no sense to delete
// the first outline (board outline) since that would have the
// undesirable effect of substituting a cutout outline as the board outline
if( aOutline == outlines.front() )
{
if( outlines.size() > 1 )
{
ostringstream ostr;
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
ostr << "* BUG: attempting to delete first outline in list\n";
ostr << "* outline type: " << GetOutlineTypeString( outlineType );
errormsg = ostr.str();
return false;
}
outlines.clear();
return true;
}
while( itS != itE )
{
if( *itS == aOutline )
{
outlines.erase( itS );
return true;
}
++itS;
}
errormsg.clear();
return false;
}
bool BOARD_OUTLINE::DelOutline( size_t aIndex )
{
std::list< IDF_OUTLINE* >::iterator itS = outlines.begin();
if( outlines.empty() )
{
errormsg.clear();
return false;
}
if( aIndex >= outlines.size() )
{
ostringstream ostr;
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
ostr << "* BUG: index out of bounds (" << aIndex << " / " << outlines.size() << ")\n";
ostr << "* outline type: " << GetOutlineTypeString( outlineType );
errormsg = ostr.str();
return false;
}
if( aIndex == 0 )
{
// if there are more than 1 outlines it makes no sense to delete
// the first outline (board outline) since that would have the
// undesirable effect of substituting a cutout outline as the board outline
if( outlines.size() > 1 )
{
ostringstream ostr;
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
ostr << "* BUG: attempting to delete first outline in list\n";
ostr << "* outline type: " << GetOutlineTypeString( outlineType );
errormsg = ostr.str();
return false;
}
delete *itS;
outlines.clear();
return true;
}
for( ; aIndex > 0; --aIndex )
++itS;
delete *itS;
outlines.erase( itS );
return true;
}
const std::list< IDF_OUTLINE* >*const BOARD_OUTLINE::GetOutlines( void )
{
return &outlines;
}
size_t BOARD_OUTLINE::OutlinesSize( void )
{
return outlines.size();
}
IDF_OUTLINE* BOARD_OUTLINE::GetOutline( size_t aIndex )
{
if( aIndex >= outlines.size() )
{
ostringstream ostr;
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
ostr << "* aIndex (" << aIndex << ") is out of range (" << outlines.size() << ")";
errormsg = ostr.str();
return nullptr;
}
std::list< IDF_OUTLINE* >::iterator itS = outlines.begin();
for( ; aIndex > 0; --aIndex )
++itS;
return *itS;
}
IDF3::KEY_OWNER BOARD_OUTLINE::GetOwner( void )
{
return owner;
}
bool BOARD_OUTLINE::SetOwner( IDF3::KEY_OWNER aOwner )
{
#ifndef DISABLE_IDF_OWNERSHIP
if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
return false;
#endif
owner = aOwner;
return true;
}
bool BOARD_OUTLINE::IsSingle( void )
{
return single;
}
void BOARD_OUTLINE::clearOutlines( void )
{
std::list< IDF_OUTLINE* >::iterator itS = outlines.begin();
std::list< IDF_OUTLINE* >::iterator itE = outlines.end();
while( itS != itE )
{
delete *itS;
++itS;
}
outlines.clear();
}
void BOARD_OUTLINE::AddComment( const std::string& aComment )
{
if( aComment.empty() )
return;
comments.push_back( aComment );
}
size_t BOARD_OUTLINE::CommentsSize( void )
{
return comments.size();
}
std::list< std::string >* BOARD_OUTLINE::GetComments( void )
{
return &comments;
}
const std::string* BOARD_OUTLINE::GetComment( size_t aIndex )
{
if( aIndex >= comments.size() )
return nullptr;
std::list< std::string >::iterator itS = comments.begin();
for( ; aIndex > 0; --aIndex )
++itS;
return &(*itS);
}
bool BOARD_OUTLINE::DeleteComment( size_t aIndex )
{
if( aIndex >= comments.size() )
return false;
std::list< std::string >::iterator itS = comments.begin();
for( ; aIndex > 0; --aIndex )
++itS;
comments.erase( itS );
return true;
}
void BOARD_OUTLINE::ClearComments( void )
{
comments.clear();
}
OTHER_OUTLINE::OTHER_OUTLINE( IDF3_BOARD* aParent )
{
setParent( aParent );
outlineType = OTLN_OTHER;
side = LYR_INVALID;
single = false;
}
bool OTHER_OUTLINE::SetOutlineIdentifier( const std::string& aUniqueID )
{
#ifndef DISABLE_IDF_OWNERSHIP
if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
return false;
#endif
uniqueID = aUniqueID;
return true;
}
const std::string& OTHER_OUTLINE::GetOutlineIdentifier( void )
{
return uniqueID;
}
bool OTHER_OUTLINE::SetSide( IDF3::IDF_LAYER aSide )
{
#ifndef DISABLE_IDF_OWNERSHIP
if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
return false;
#endif
switch( aSide )
{
case LYR_TOP:
case LYR_BOTTOM:
side = aSide;
break;
default:
do
{
ostringstream ostr;
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
ostr << "* BUG: invalid side (" << aSide << "); must be one of TOP/BOTTOM\n";
ostr << "* outline type: " << GetOutlineTypeString( outlineType );
errormsg = ostr.str();
} while( 0 );
side = LYR_INVALID;
return false;
break;
}
return true;
}
IDF3::IDF_LAYER OTHER_OUTLINE::GetSide( void )
{
return side;
}
void OTHER_OUTLINE::readData( std::istream& aBoardFile, const std::string& aHeader,
IDF3::IDF_VERSION aIdfVersion )
{
// OTHER_OUTLINE/VIA_KEEPOUT
// .OTHER_OUTLINE [OWNER]
// [outline identifier] [thickness] [board side: Top/Bot] {not present in VA\IA KEEPOUT}
// [outline]
// check RECORD 1
std::string token;
bool quoted = false;
int idx = 0;
std::streampos pos = aBoardFile.tellg();
if( !GetIDFString( aHeader, token, quoted, idx ) )
{
ostringstream ostr;
ostr << "\n* BUG: invalid invocation: blank header line\n";
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( quoted )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: section names must not be in quotes\n";
ostr << "* line: '" << aHeader << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( outlineType == OTLN_OTHER )
{
if( !CompareToken( ".OTHER_OUTLINE", token ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* BUG: not an .OTHER outline\n";
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
}
else
{
if( !CompareToken( ".VIA_KEEPOUT", token ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* BUG: not a .VIA_KEEPOUT outline\n";
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
}
if( !GetIDFString( aHeader, token, quoted, idx ) )
{
if( aIdfVersion > IDF_V2 )
ERROR_IDF << "no OWNER; setting to UNOWNED\n";
owner = UNOWNED;
}
else
{
if( !ParseOwner( token, owner ) )
{
ERROR_IDF << "invalid OWNER (reverting to UNOWNED): " << token << "\n";
owner = UNOWNED;
}
}
std::string iline;
bool comment = false;
if( outlineType == OTLN_OTHER )
{
// check RECORD 2
// [outline identifier] [thickness] [board side: Top/Bot]
while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) );
if( ( !aBoardFile.good() && aBoardFile.eof() ) || iline.empty() )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: premature end\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
idx = 0;
if( comment )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: comment within .OTHER_OUTLINE section\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( !GetIDFString( iline, token, quoted, idx ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: no outline identifier\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
uniqueID = token;
if( !GetIDFString( iline, token, quoted, idx ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: no thickness\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
std::stringstream teststr;
teststr << token;
teststr >> thickness;
if( teststr.fail() )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: invalid thickness\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( unit == UNIT_THOU )
{
thickness *= IDF_THOU_TO_MM;
}
else if( ( aIdfVersion == IDF_V2 ) && ( unit == UNIT_TNM ) )
{
thickness *= IDF_TNM_TO_MM;
}
else if( unit != UNIT_MM )
{
ostringstream ostr;
ostr << "\n* BUG: invalid UNIT type: " << unit;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( aIdfVersion == IDF_V2 )
{
side = LYR_TOP;
}
else
{
if( !GetIDFString( iline, token, quoted, idx ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: no board side\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( !ParseIDFLayer( token, side ) || ( side != LYR_TOP && side != LYR_BOTTOM ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: invalid side (must be TOP or BOTTOM only)\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
}
}
// read RECORD 3 values
readOutlines( aBoardFile, aIdfVersion );
// check RECORD 4
while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) );
if( ( !aBoardFile.good() && aBoardFile.eof() ) || iline.empty() )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: premature end\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
idx = 0;
if( comment )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: comment within section\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( outlineType == OTLN_OTHER )
{
if( !CompareToken( ".END_OTHER_OUTLINE", iline ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: no .END_OTHER_OUTLINE found\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
}
else
{
if( !CompareToken( ".END_VIA_KEEPOUT", iline ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: no .END_VIA_KEEPOUT found\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
}
}
void OTHER_OUTLINE::writeData( std::ostream& aBoardFile )
{
// this section is optional; do not write if not required
if( outlines.empty() )
return;
writeComments( aBoardFile );
// write RECORD 1
if( outlineType == OTLN_OTHER )
aBoardFile << ".OTHER_OUTLINE ";
else
aBoardFile << ".VIA_KEEPOUT ";
writeOwner( aBoardFile );
// write RECORD 2
if( outlineType == OTLN_OTHER )
{
aBoardFile << "\"" << uniqueID << "\" ";
if( unit != UNIT_THOU )
aBoardFile << setiosflags( ios::fixed ) << setprecision( 5 ) << thickness << " ";
else
aBoardFile << setiosflags( ios::fixed ) << setprecision( 1 )
<< ( thickness / IDF_THOU_TO_MM ) << " ";
switch( side )
{
case LYR_TOP:
case LYR_BOTTOM:
WriteLayersText( aBoardFile, side );
break;
default:
do
{
ostringstream ostr;
ostr << "\n* invalid OTHER_OUTLINE side (neither top nor bottom): ";
ostr << side;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
} while( 0 );
break;
}
}
// write RECORD 3
writeOutlines( aBoardFile );
// write RECORD 4
if( outlineType == OTLN_OTHER )
aBoardFile << ".END_OTHER_OUTLINE\n\n";
else
aBoardFile << ".END_VIA_KEEPOUT\n\n";
}
bool OTHER_OUTLINE::Clear( void )
{
#ifndef DISABLE_IDF_OWNERSHIP
if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
return false;
#endif
clear();
side = LYR_INVALID;
uniqueID.clear();
return true;
}
ROUTE_OUTLINE::ROUTE_OUTLINE( IDF3_BOARD* aParent )
{
setParent( aParent );
outlineType = OTLN_ROUTE;
single = true;
layers = LYR_INVALID;
}
bool ROUTE_OUTLINE::SetLayers( IDF3::IDF_LAYER aLayer )
{
#ifndef DISABLE_IDF_OWNERSHIP
if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
return false;
#endif
layers = aLayer;
return true;
}
IDF3::IDF_LAYER ROUTE_OUTLINE::GetLayers( void )
{
return layers;
}
void ROUTE_OUTLINE::readData( std::istream& aBoardFile, const std::string& aHeader,
IDF3::IDF_VERSION aIdfVersion )
{
// ROUTE_OUTLINE (or ROUTE_KEEPOUT)
// .ROUTE_OUTLINE [OWNER]
// [layers]
// [outline]
// check RECORD 1
std::string token;
bool quoted = false;
int idx = 0;
std::streampos pos = aBoardFile.tellg();
if( !GetIDFString( aHeader, token, quoted, idx ) )
{
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"\n* BUG: invalid invocation; blank header line" ) );
}
if( quoted )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: section names must not be in quotes\n";
ostr << "* line: '" << aHeader << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( outlineType == OTLN_ROUTE )
{
if( !CompareToken( ".ROUTE_OUTLINE", token ) )
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"\n* BUG: not a ROUTE outline" ) );
}
else
{
if( !CompareToken( ".ROUTE_KEEPOUT", token ) )
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"\n* BUG: not a ROUTE KEEPOUT outline" ) );
}
if( !GetIDFString( aHeader, token, quoted, idx ) )
{
if( aIdfVersion > IDF_V2 )
ERROR_IDF << "no OWNER; setting to UNOWNED\n";
owner = UNOWNED;
}
else
{
if( !ParseOwner( token, owner ) )
{
ERROR_IDF << "invalid OWNER (reverting to UNOWNED): " << token << "\n";
owner = UNOWNED;
}
}
// check RECORD 2
// [layers: TOP, BOTTOM, BOTH, INNER, ALL]
std::string iline;
bool comment = false;
if( aIdfVersion > IDF_V2 || outlineType == OTLN_ROUTE_KEEPOUT )
{
while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) );
if( !aBoardFile.good() )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: premature end\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
idx = 0;
if( comment )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: comment within a section\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( !GetIDFString( iline, token, quoted, idx ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: no layers specification\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( quoted )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: layers specification must not be in quotes\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( !ParseIDFLayer( token, layers ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: invalid layers specification\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( aIdfVersion == IDF_V2 )
{
if( layers == LYR_INNER || layers == LYR_ALL )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: IDFv2 allows only TOP/BOTTOM/BOTH; layer was '";
ostr << token << "'\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
}
}
else
{
layers = LYR_ALL;
}
// read RECORD 3 values
readOutlines( aBoardFile, aIdfVersion );
// check RECORD 4
while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) );
if( ( !aBoardFile.good() && aBoardFile.eof() ) || iline.empty() )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: premature end\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
idx = 0;
if( comment )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: comment within section\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( outlineType == OTLN_ROUTE )
{
if( !CompareToken( ".END_ROUTE_OUTLINE", iline ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: no .END_ROUTE_OUTLINE found\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
}
else
{
if( !CompareToken( ".END_ROUTE_KEEPOUT", iline ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: no .END_ROUTE_KEEPOUT found\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
}
}
void ROUTE_OUTLINE::writeData( std::ostream& aBoardFile )
{
// this section is optional; do not write if not required
if( outlines.empty() )
return;
if( layers == LYR_INVALID )
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"layer not specified" ) );
writeComments( aBoardFile );
// write RECORD 1
if( outlineType == OTLN_ROUTE )
aBoardFile << ".ROUTE_OUTLINE ";
else
aBoardFile << ".ROUTE_KEEPOUT ";
writeOwner( aBoardFile );
// write RECORD 2
WriteLayersText( aBoardFile, layers );
aBoardFile << "\n";
// write RECORD 3
writeOutlines( aBoardFile );
// write RECORD 4
if( outlineType == OTLN_ROUTE )
aBoardFile << ".END_ROUTE_OUTLINE\n\n";
else
aBoardFile << ".END_ROUTE_KEEPOUT\n\n";
}
bool ROUTE_OUTLINE::Clear( void )
{
#ifndef DISABLE_IDF_OWNERSHIP
if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
return false;
#endif
clear();
layers = LYR_INVALID;
return true;
}
PLACE_OUTLINE::PLACE_OUTLINE( IDF3_BOARD* aParent )
{
setParent( aParent );
outlineType = OTLN_PLACE;
single = true;
thickness = -1.0;
side = LYR_INVALID;
}
bool PLACE_OUTLINE::SetSide( IDF3::IDF_LAYER aSide )
{
#ifndef DISABLE_IDF_OWNERSHIP
if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
return false;
#endif
switch( aSide )
{
case LYR_TOP:
case LYR_BOTTOM:
case LYR_BOTH:
side = aSide;
break;
default:
do
{
side = LYR_INVALID;
ostringstream ostr;
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
ostr << "* BUG: invalid layer (" << aSide << "): must be one of TOP/BOTTOM/BOTH\n";
ostr << "* outline type: " << GetOutlineTypeString( outlineType );
errormsg = ostr.str();
return false;
} while( 0 );
break;
}
return true;
}
IDF3::IDF_LAYER PLACE_OUTLINE::GetSide( void )
{
return side;
}
bool PLACE_OUTLINE::SetMaxHeight( double aHeight )
{
#ifndef DISABLE_IDF_OWNERSHIP
if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
return false;
#endif
if( aHeight < 0.0 )
{
thickness = 0.0;
do
{
ostringstream ostr;
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
ostr << "* BUG: invalid height (" << aHeight << "): must be >= 0.0";
ostr << "* outline type: " << GetOutlineTypeString( outlineType );
errormsg = ostr.str();
return false;
} while( 0 );
}
thickness = aHeight;
return true;
}
double PLACE_OUTLINE::GetMaxHeight( void )
{
return thickness;
}
void PLACE_OUTLINE::readData( std::istream& aBoardFile, const std::string& aHeader,
IDF3::IDF_VERSION aIdfVersion )
{
// PLACE_OUTLINE/KEEPOUT
// .PLACE_OUTLINE [OWNER]
// [board side: Top/Bot/Both] [height]
// [outline]
// check RECORD 1
std::string token;
bool quoted = false;
int idx = 0;
std::streampos pos = aBoardFile.tellg();
if( !GetIDFString( aHeader, token, quoted, idx ) )
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"\n* BUG: invalid invocation: blank header line\n" ) );
if( quoted )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: section name must not be in quotes\n";
ostr << "* line: '" << aHeader << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( outlineType == OTLN_PLACE )
{
if( !CompareToken( ".PLACE_OUTLINE", token ) )
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"\n* BUG: not a .PLACE_OUTLINE" ) );
}
else
{
if( !CompareToken( ".PLACE_KEEPOUT", token ) )
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"\n* BUG: not a .PLACE_KEEPOUT" ) );
}
if( !GetIDFString( aHeader, token, quoted, idx ) )
{
if( aIdfVersion > IDF_V2 )
ERROR_IDF << "no OWNER; setting to UNOWNED\n";
owner = UNOWNED;
}
else
{
if( !ParseOwner( token, owner ) )
{
ERROR_IDF << "invalid OWNER (reverting to UNOWNED): " << token << "\n";
owner = UNOWNED;
}
}
// check RECORD 2
// [board side: Top/Bot/Both] [height]
std::string iline;
bool comment = false;
if( aIdfVersion > IDF_V2 || outlineType == OTLN_PLACE_KEEPOUT )
{
while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) );
if( !aBoardFile.good() )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: premature end\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
idx = 0;
if( comment )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: comment within the section\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( !GetIDFString( iline, token, quoted, idx ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: no board side information\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( !ParseIDFLayer( token, side ) ||
( side != LYR_TOP && side != LYR_BOTTOM && side != LYR_BOTH ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: invalid board side: must be one of TOP/BOTTOM/BOTH\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( GetIDFString( iline, token, quoted, idx ) )
{
std::stringstream teststr;
teststr << token;
teststr >> thickness;
if( teststr.fail() )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: invalid height\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( thickness < 0.0 )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: thickness < 0\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( unit == UNIT_THOU )
{
thickness *= IDF_THOU_TO_MM;
}
else if( ( aIdfVersion == IDF_V2 ) && ( unit == UNIT_TNM ) )
{
thickness *= IDF_TNM_TO_MM;
}
else if( unit != UNIT_MM )
{
ostringstream ostr;
ostr << "\n* BUG: invalid UNIT type: " << unit;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( thickness < 0.0 )
thickness = 0.0;
}
else
{
// for OTLN_PLACE, thickness may be omitted, but is required for OTLN_PLACE_KEEPOUT
if( outlineType == OTLN_PLACE_KEEPOUT )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: missing thickness\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
thickness = -1.0;
}
}
else
{
side = LYR_TOP;
thickness = 0.0;
}
// read RECORD 3 values
readOutlines( aBoardFile, aIdfVersion );
// check RECORD 4
while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) );
if( ( !aBoardFile.good() && aBoardFile.eof() ) || iline.empty() )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: premature end\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
idx = 0;
if( comment )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: comment within section\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( outlineType == OTLN_PLACE )
{
if( !GetIDFString( iline, token, quoted, idx )
|| !CompareToken( ".END_PLACE_OUTLINE", token ) )
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"invalid .PLACE_OUTLINE section: no .END_PLACE_OUTLINE found" ) );
}
else
{
if( !GetIDFString( iline, token, quoted, idx )
|| !CompareToken( ".END_PLACE_KEEPOUT", token ) )
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"invalid .PLACE_KEEPOUT section: no .END_PLACE_KEEPOUT found" ) );
}
}
void PLACE_OUTLINE::writeData( std::ostream& aBoardFile )
{
// this section is optional; do not write if not required
if( outlines.empty() )
return;
writeComments( aBoardFile );
// write RECORD 1
if( outlineType == OTLN_PLACE )
aBoardFile << ".PLACE_OUTLINE ";
else
aBoardFile << ".PLACE_KEEPOUT ";
writeOwner( aBoardFile );
// write RECORD 2
switch( side )
{
case LYR_TOP:
case LYR_BOTTOM:
case LYR_BOTH:
WriteLayersText( aBoardFile, side );
break;
default:
do
{
ostringstream ostr;
ostr << "\n* invalid PLACE_OUTLINE/KEEPOUT side (";
ostr << side << "); must be one of TOP/BOTTOM/BOTH";
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
} while( 0 );
break;
}
// thickness is optional for OTLN_PLACE, but mandatory for OTLN_PLACE_KEEPOUT
if( thickness < 0.0 && outlineType == OTLN_PLACE_KEEPOUT )
{
aBoardFile << "\n";
}
else
{
aBoardFile << " ";
if( unit != UNIT_THOU )
aBoardFile << setiosflags( ios::fixed ) << setprecision( 5 ) << thickness << "\n";
else
aBoardFile << setiosflags( ios::fixed ) << setprecision( 1 )
<< ( thickness / IDF_THOU_TO_MM ) << "\n";
}
// write RECORD 3
writeOutlines( aBoardFile );
// write RECORD 4
if( outlineType == OTLN_PLACE )
aBoardFile << ".END_PLACE_OUTLINE\n\n";
else
aBoardFile << ".END_PLACE_KEEPOUT\n\n";
return;
}
bool PLACE_OUTLINE::Clear( void )
{
#ifndef DISABLE_IDF_OWNERSHIP
if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
return false;
#endif
clear();
thickness = 0.0;
side = LYR_INVALID;
return true;
}
ROUTE_KO_OUTLINE::ROUTE_KO_OUTLINE( IDF3_BOARD* aParent )
: ROUTE_OUTLINE( aParent )
{
outlineType = OTLN_ROUTE_KEEPOUT;
return;
}
PLACE_KO_OUTLINE::PLACE_KO_OUTLINE( IDF3_BOARD* aParent )
: PLACE_OUTLINE( aParent )
{
outlineType = OTLN_PLACE_KEEPOUT;
return;
}
VIA_KO_OUTLINE::VIA_KO_OUTLINE( IDF3_BOARD* aParent )
: OTHER_OUTLINE( aParent )
{
single = true;
outlineType = OTLN_VIA_KEEPOUT;
}
GROUP_OUTLINE::GROUP_OUTLINE( IDF3_BOARD* aParent )
{
setParent( aParent );
outlineType = OTLN_GROUP_PLACE;
thickness = 0.0;
side = LYR_INVALID;
single = true;
return;
}
bool GROUP_OUTLINE::SetSide( IDF3::IDF_LAYER aSide )
{
#ifndef DISABLE_IDF_OWNERSHIP
if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
return false;
#endif
switch( aSide )
{
case LYR_TOP:
case LYR_BOTTOM:
case LYR_BOTH:
side = aSide;
break;
default:
do
{
ostringstream ostr;
ostr << "invalid side (" << aSide << "); must be one of TOP/BOTTOM/BOTH\n";
ostr << "* outline type: " << GetOutlineTypeString( outlineType );
errormsg = ostr.str();
return false;
} while( 0 );
break;
}
return true;
}
IDF3::IDF_LAYER GROUP_OUTLINE::GetSide( void )
{
return side;
}
bool GROUP_OUTLINE::SetGroupName( std::string aGroupName )
{
#ifndef DISABLE_IDF_OWNERSHIP
if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
return false;
#endif
groupName = std::move( aGroupName );
return true;
}
const std::string& GROUP_OUTLINE::GetGroupName( void )
{
return groupName;
}
void GROUP_OUTLINE::readData( std::istream& aBoardFile, const std::string& aHeader,
IDF3::IDF_VERSION aIdfVersion )
{
// Placement Group
// .PLACE_REGION [OWNER]
// [side: Top/Bot/Both ] [component group name]
// [outline]
// check RECORD 1
std::string token;
bool quoted = false;
int idx = 0;
std::streampos pos = aBoardFile.tellg();
if( !GetIDFString( aHeader, token, quoted, idx ) )
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"\n* BUG: invalid invocation: blank header line" ) );
if( quoted )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: section name must not be in quotes\n";
ostr << "* line: '" << aHeader << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( !CompareToken( ".PLACE_REGION", token ) )
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, "\n* BUG: not a .PLACE_REGION" ) );
if( !GetIDFString( aHeader, token, quoted, idx ) )
{
if( aIdfVersion > IDF_V2 )
ERROR_IDF << "no OWNER; setting to UNOWNED\n";
owner = UNOWNED;
}
else
{
if( !ParseOwner( token, owner ) )
{
ERROR_IDF << "invalid OWNER (reverting to UNOWNED): " << token << "\n";
owner = UNOWNED;
}
}
std::string iline;
bool comment = false;
// check RECORD 2
// [side: Top/Bot/Both ] [component group name]
while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) );
if( !aBoardFile.good() )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: premature end\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
idx = 0;
if( comment )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: comment within section\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( !GetIDFString( iline, token, quoted, idx ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: no board side specified\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( !ParseIDFLayer( token, side ) ||
( side != LYR_TOP && side != LYR_BOTTOM && side != LYR_BOTH ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: invalid board side, must be one of TOP/BOTTOM/BOTH\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( !GetIDFString( iline, token, quoted, idx ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: no outline identifier\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
groupName = token;
// read RECORD 3 values
readOutlines( aBoardFile, aIdfVersion );
// check RECORD 4
while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) );
if( ( !aBoardFile.good() && aBoardFile.eof() ) || iline.empty() )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: premature end\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
idx = 0;
if( comment )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: comment within section\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( !GetIDFString( iline, token, quoted, idx ) || !CompareToken( ".END_PLACE_REGION", token ) )
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"\n* invalid .PLACE_REGION section: no .END_PLACE_REGION found" ) );
}
void GROUP_OUTLINE::writeData( std::ostream& aBoardFile )
{
// this section is optional; do not write if not required
if( outlines.empty() )
return;
writeComments( aBoardFile );
// write RECORD 1
aBoardFile << ".PLACE_REGION ";
writeOwner( aBoardFile );
// write RECORD 2
switch( side )
{
case LYR_TOP:
case LYR_BOTTOM:
case LYR_BOTH:
WriteLayersText( aBoardFile, side );
break;
default:
do
{
ostringstream ostr;
ostr << "\n* invalid PLACE_REGION side (must be TOP/BOTTOM/BOTH): ";
ostr << side;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
} while( 0 );
break;
}
aBoardFile << " \"" << groupName << "\"\n";
// write RECORD 3
writeOutlines( aBoardFile );
// write RECORD 4
aBoardFile << ".END_PLACE_REGION\n\n";
}
bool GROUP_OUTLINE::Clear( void )
{
#ifndef DISABLE_IDF_OWNERSHIP
if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
return false;
#endif
clear();
thickness = 0.0;
side = LYR_INVALID;
groupName.clear();
return true;
}
IDF3_COMP_OUTLINE::IDF3_COMP_OUTLINE( IDF3_BOARD* aParent )
{
setParent( aParent );
single = true;
outlineType = OTLN_COMPONENT;
compType = COMP_INVALID;
refNum = 0;
return;
}
void IDF3_COMP_OUTLINE::readProperties( std::istream& aLibFile )
{
bool quoted = false;
bool comment = false;
std::string iline;
std::string token;
std::streampos pos;
std::string pname; // property name
std::string pval; // property value
int idx = 0;
while( aLibFile.good() )
{
if( !FetchIDFLine( aLibFile, iline, comment, pos ) )
continue;
idx = 0;
if( comment )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: comment within section\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( !GetIDFString( iline, token, quoted, idx ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: bad property section (no PROP)\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( quoted )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: PROP or .END must not be quoted\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( token.size() >= 5 && CompareToken( ".END_", token.substr( 0, 5 ) ) )
{
if(aLibFile.eof())
aLibFile.clear();
aLibFile.seekg( pos );
return;
}
if( !CompareToken( "PROP", token ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: expecting PROP or .END_ELECTRICAL\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( !GetIDFString( iline, token, quoted, idx ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: no PROP name\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
pname = token;
if( !GetIDFString( iline, token, quoted, idx ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: no PROP value\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
pval = token;
if( props.insert( pair< string, string >(pname, pval) ).second == false )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: duplicate property name \"" << pname << "\"\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
}
}
bool IDF3_COMP_OUTLINE::writeProperties( std::ostream& aLibFile )
{
if( props.empty() )
return true;
std::map< std::string, std::string >::const_iterator itS = props.begin();
std::map< std::string, std::string >::const_iterator itE = props.end();
while( itS != itE )
{
aLibFile << "PROP " << "\"" << itS->first << "\" \""
<< itS->second << "\"\n";
++itS;
}
return !aLibFile.fail();
}
void IDF3_COMP_OUTLINE::readData( std::istream& aLibFile, const std::string& aHeader,
IDF3::IDF_VERSION aIdfVersion )
{
// .ELECTRICAL/.MECHANICAL
// [GEOM] [PART] [UNIT] [HEIGHT]
// [outline]
// [PROP] [prop name] [prop value]
// check RECORD 1
std::string token;
bool quoted = false;
int idx = 0;
std::streampos pos = aLibFile.tellg();
if( !GetIDFString( aHeader, token, quoted, idx ) )
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
"\n* BUG: invalid invocation: blank header line" ) );
if( quoted )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: section name must not be in quotes\n";
ostr << "* line: '" << aHeader << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( CompareToken( ".ELECTRICAL", token ) )
{
compType = COMP_ELEC;
}
else if( CompareToken( ".MECHANICAL", token ) )
{
compType = COMP_MECH;
}
else
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: expecting .ELECTRICAL or .MECHANICAL header\n";
ostr << "* line: '" << aHeader << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
// check RECORD 2
// [GEOM] [PART] [UNIT] [HEIGHT]
std::string iline;
bool comment = false;
while( aLibFile.good() && !FetchIDFLine( aLibFile, iline, comment, pos ) );
if( !aLibFile.good() )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: premature end\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
idx = 0;
if( comment )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: comment within section\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( !GetIDFString( iline, token, quoted, idx ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: no GEOMETRY NAME\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
geometry = token;
if( !GetIDFString( iline, token, quoted, idx ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: no PART NAME\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
part = token;
if( part.empty() && geometry.empty() )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: both GEOMETRY and PART names are empty\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( !GetIDFString( iline, token, quoted, idx ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: no UNIT type\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( CompareToken( "MM", token ) )
{
unit = UNIT_MM;
}
else if( CompareToken( "THOU", token ) )
{
unit = UNIT_THOU;
}
else if( aIdfVersion == IDF_V2 && !CompareToken( "TNM", token ) )
{
unit = UNIT_TNM;
}
else
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: invalid UNIT '" << token << "': must be one of MM or THOU\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( !GetIDFString( iline, token, quoted, idx ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: no height specified\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
std::istringstream teststr;
teststr.str( token );
teststr >> thickness;
if( teststr.fail() )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: invalid height '" << token << "'\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( unit == UNIT_THOU )
{
thickness *= IDF_THOU_TO_MM;
}
else if( ( aIdfVersion == IDF_V2 ) && ( unit == UNIT_TNM ) )
{
thickness *= IDF_TNM_TO_MM;
}
else if( unit != UNIT_MM )
{
ostringstream ostr;
ostr << "\n* BUG: invalid UNIT type: " << unit;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
// read RECORD 3 values
readOutlines( aLibFile, aIdfVersion );
if( compType == COMP_ELEC && aIdfVersion > IDF_V2 )
readProperties( aLibFile );
// check RECORD 4
while( aLibFile.good() && !FetchIDFLine( aLibFile, iline, comment, pos ) );
if( ( !aLibFile.good() && aLibFile.eof() ) && iline.empty() )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: premature end\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
idx = 0;
if( comment )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: comment within section\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
if( compType == COMP_ELEC )
{
if( !CompareToken( ".END_ELECTRICAL", iline ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: no .END_ELECTRICAL found\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
}
else
{
if( !CompareToken( ".END_MECHANICAL", iline ) )
{
ostringstream ostr;
ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
ostr << "* violation: no .END_MECHANICAL found\n";
ostr << "* line: '" << iline << "'\n";
ostr << "* file position: " << pos;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
}
}
void IDF3_COMP_OUTLINE::writeData( std::ostream& aLibFile )
{
if( refNum == 0 )
return; // nothing to do
if( compType != COMP_ELEC && compType != COMP_MECH )
{
ostringstream ostr;
ostr << "\n* component type not set or invalid: " << compType;
throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
}
writeComments( aLibFile );
// note: the outline section is required, even if it is empty
if( compType == COMP_ELEC )
aLibFile << ".ELECTRICAL\n";
else
aLibFile << ".MECHANICAL\n";
// RECORD 2
// [GEOM] [PART] [UNIT] [HEIGHT]
aLibFile << "\"" << geometry << "\" \"" << part << "\" ";
if( unit != UNIT_THOU )
aLibFile << "MM " << setiosflags( ios::fixed ) << setprecision( 5 ) << thickness << "\n";
else
aLibFile << "THOU " << setiosflags( ios::fixed ) << setprecision( 1 )
<< ( thickness / IDF_THOU_TO_MM ) << "\n";
writeOutlines( aLibFile );
if( compType == COMP_ELEC )
{
writeProperties( aLibFile );
aLibFile << ".END_ELECTRICAL\n\n";
}
else
{
aLibFile << ".END_MECHANICAL\n\n";
}
}
bool IDF3_COMP_OUTLINE::Clear( void )
{
#ifndef DISABLE_IDF_OWNERSHIP
if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
return false;
#endif
clear();
uid.clear();
geometry.clear();
part.clear();
compType = COMP_INVALID;
refNum = 0;
props.clear();
return true;
}
bool IDF3_COMP_OUTLINE::SetComponentClass( IDF3::COMP_TYPE aCompClass )
{
switch( aCompClass )
{
case COMP_ELEC:
case COMP_MECH:
compType = aCompClass;
break;
default:
do
{
ostringstream ostr;
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
ostr << "* BUG: invalid component class (must be ELECTRICAL or MECHANICAL): ";
ostr << aCompClass << "\n";
errormsg = ostr.str();
return false;
} while( 0 );
break;
}
return true;
}
IDF3::COMP_TYPE IDF3_COMP_OUTLINE::GetComponentClass( void )
{
return compType;
}
void IDF3_COMP_OUTLINE::SetGeomName( const std::string& aGeomName )
{
geometry = aGeomName;
uid.clear();
}
const std::string& IDF3_COMP_OUTLINE::GetGeomName( void )
{
return geometry;
}
void IDF3_COMP_OUTLINE::SetPartName( const std::string& aPartName )
{
part = aPartName;
uid.clear();
}
const std::string& IDF3_COMP_OUTLINE::GetPartName( void )
{
return part;
}
const std::string& IDF3_COMP_OUTLINE::GetUID( void )
{
if( !uid.empty() )
return uid;
if( geometry.empty() && part.empty() )
return uid;
uid = geometry + "_" + part;
return uid;
}
int IDF3_COMP_OUTLINE::incrementRef( void )
{
return ++refNum;
}
int IDF3_COMP_OUTLINE::decrementRef( void )
{
if( refNum == 0 )
{
ostringstream ostr;
ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
ostr << "* BUG: decrementing refNum beyond 0";
errormsg = ostr.str();
return -1;
}
--refNum;
return refNum;
}
bool IDF3_COMP_OUTLINE::CreateDefaultOutline( const std::string& aGeom, const std::string& aPart )
{
Clear();
if( aGeom.empty() && aPart.empty() )
{
geometry = "NOGEOM";
part = "NOPART";
uid = "NOGEOM_NOPART";
}
else
{
geometry = aGeom;
part = aPart;
uid = aGeom + "_" + aPart;
}
compType = COMP_ELEC;
thickness = 5.0;
unit = UNIT_MM;
// Create a star shape 5mm high with points on 5 and 3 mm circles
double a, da;
da = M_PI / 5.0;
a = da / 2.0;
IDF_POINT p1, p2;
IDF_OUTLINE* ol = new IDF_OUTLINE;
IDF_SEGMENT* sp;
p1.x = 1.5 * cos( a );
p1.y = 1.5 * sin( a );
if( ol == nullptr )
return false;
for( int i = 0; i < 10; ++i )
{
if( i & 1 )
{
p2.x = 2.5 * cos( a );
p2.y = 2.5 * sin( a );
}
else
{
p2.x = 1.5 * cos( a );
p2.y = 1.5 * sin( a );
}
sp = new IDF_SEGMENT( p1, p2 );
if( sp == nullptr )
{
Clear();
return false;
}
ol->push( sp );
a += da;
p1 = p2;
}
a = da / 2.0;
p2.x = 1.5 * cos( a );
p2.y = 1.5 * sin( a );
sp = new IDF_SEGMENT( p1, p2 );
if( sp == nullptr )
{
Clear();
return false;
}
ol->push( sp );
outlines.push_back( ol );
return true;
}