Files
kicad-source-mirror/utils/idftools/idf_outlines.cpp
T
Seth Hillbrand 0b2d4d4879 Revise Copyright statement to align with TLF
Recommendation is to avoid using the year nomenclature as this
information is already encoded in the git repo.  Avoids needing to
repeatly update.

Also updates AUTHORS.txt from current repo with contributor names
2025-01-01 14:12:04 -08:00

3653 lines
102 KiB
C++

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014-2017 Cirilo Bernardo
* Copyright The 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 )
{
try
{
op = new IDF_OUTLINE;
}
catch( std::bad_alloc& )
{
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() ) );
}
try
{
op = new IDF_OUTLINE;
}
catch( std::bad_alloc& )
{
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() ) );
}
try
{
op = new IDF_OUTLINE;
}
catch( std::bad_alloc& )
{
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;
try
{
if( ang > -MIN_ANG && ang < MIN_ANG )
{
sp = new IDF_SEGMENT( prePt, curPt );
}
else
{
sp = new IDF_SEGMENT( prePt, curPt, ang, false );
}
}
catch( std::bad_alloc& )
{
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*>* 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_SEGMENT* sp;
IDF_OUTLINE* ol;
p1.x = 1.5 * cos( a );
p1.y = 1.5 * sin( a );
try
{
ol = new IDF_OUTLINE;
}
catch( std::bad_alloc& )
{
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 );
}
try
{
sp = new IDF_SEGMENT( p1, p2 );
}
catch( std::bad_alloc& )
{
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 );
try
{
sp = new IDF_SEGMENT( p1, p2 );
}
catch( std::bad_alloc& )
{
Clear();
return false;
}
ol->push( sp );
outlines.push_back( ol );
return true;
}