0b2d4d4879
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
3653 lines
102 KiB
C++
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;
|
|
}
|