diff options
Diffstat (limited to 'utils/idftools/dxf2idf.cpp')
-rw-r--r-- | utils/idftools/dxf2idf.cpp | 460 |
1 files changed, 460 insertions, 0 deletions
diff --git a/utils/idftools/dxf2idf.cpp b/utils/idftools/dxf2idf.cpp new file mode 100644 index 0000000..7147cda --- /dev/null +++ b/utils/idftools/dxf2idf.cpp @@ -0,0 +1,460 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 Cirilo Bernardo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <cstdio> +#include <iostream> +#include <libdxfrw.h> +#include <dxf2idf.h> + +// differences in angle smaller than MIN_ANG are considered equal +#define MIN_ANG (0.01) + +// min and max bulge bracketing min. arc before transition to line segment +// and max. arc limit +// MIN_BULGE = 0.002 ~0.45 degrees +// MAX_BULGE = 2000 ~89.97 degrees +#define MIN_BULGE 0.002 +#define MAX_BULGE 2000.0 + +DXF2IDF::~DXF2IDF() +{ + while( !lines.empty() ) + { +#ifdef DEBUG_IDF + IDF3::printSeg( lines.back() ); +#endif + delete lines.back(); + lines.pop_back(); + } +} + + +bool DXF2IDF::ReadDxf( const std::string aFile ) +{ + dxfRW* reader = new dxfRW( aFile.c_str() ); + + if( !reader ) + return false; + + bool success = reader->read( this, true ); + + delete reader; + return success; +} + + +void DXF2IDF::addLine( const DRW_Line& data ) +{ + IDF_POINT p1, p2; + + p1.x = data.basePoint.x * m_scale; + p1.y = data.basePoint.y * m_scale; + p2.x = data.secPoint.x * m_scale; + p2.y = data.secPoint.y * m_scale; + + insertLine( p1, p2 ); + return; +} + + +void DXF2IDF::addCircle( const DRW_Circle& data ) +{ + IDF_POINT p1, p2; + + p1.x = data.basePoint.x * m_scale; + p1.y = data.basePoint.y * m_scale; + + p2.x = p1.x + data.radious * m_scale; + p2.y = p1.y; + + IDF_SEGMENT* seg = new IDF_SEGMENT( p1, p2, 360, true ); + + if( seg ) + lines.push_back( seg ); + + return; +} + + +void DXF2IDF::addArc( const DRW_Arc& data ) +{ + IDF_POINT p1, p2; + + p1.x = data.basePoint.x * m_scale; + p1.y = data.basePoint.y * m_scale; + + // note: DXF circles always run CCW + double ea = data.endangle; + + while( ea < data.staangle ) + ea += M_PI; + + p2.x = p1.x + cos( data.staangle ) * data.radious * m_scale; + p2.y = p1.y + sin( data.staangle ) * data.radious * m_scale; + + double angle = ( ea - data.staangle ) * 180.0 / M_PI; + + IDF_SEGMENT* seg = new IDF_SEGMENT( p1, p2, angle, true ); + + if( seg ) + lines.push_back( seg ); + + return; +} + + +bool DXF2IDF::WriteOutline( FILE* aFile, bool isInch ) +{ + if( lines.empty() ) + { + std::cerr << "* DXF2IDF: empty outline\n"; + return false; + } + + // 1. find lowest X value + // 2. string an outline together + // 3. emit warnings if more than 1 outline + IDF_OUTLINE outline; + + IDF3::GetOutline( lines, outline ); + + if( outline.empty() ) + { + std::cerr << "* DXF2IDF::WriteOutline(): no valid outline in file\n"; + return false; + } + + if( !lines.empty() ) + { + std::cerr << "* DXF2IDF::WriteOutline(): WARNING: more than 1 outline in file\n"; + std::cerr << "* Only the first outline will be used\n"; + } + + char loopDir = '1'; + + if( outline.IsCCW() ) + loopDir = '0'; + + std::list<IDF_SEGMENT*>::iterator bo; + std::list<IDF_SEGMENT*>::iterator eo; + + if( outline.size() == 1 ) + { + if( !outline.front()->IsCircle() ) + { + std::cerr << "* DXF2IDF::WriteOutline(): bad outline\n"; + return false; + } + + // NOTE: a circle always has an angle of 360, never -360, + // otherwise SolidWorks chokes on the file. + if( isInch ) + { + fprintf( aFile, "%c %d %d 0\n", loopDir, + (int) (1000 * outline.front()->startPoint.x), + (int) (1000 * outline.front()->startPoint.y) ); + fprintf( aFile, "%c %d %d 360\n", loopDir, + (int) (1000 * outline.front()->endPoint.x), + (int) (1000 * outline.front()->endPoint.y) ); + } + else + { + fprintf( aFile, "%c %.3f %.3f 0\n", loopDir, + outline.front()->startPoint.x, outline.front()->startPoint.y ); + fprintf( aFile, "%c %.3f %.3f 360\n", loopDir, + outline.front()->endPoint.x, outline.front()->endPoint.y ); + } + + return true; + } + + // ensure that the very last point is the same as the very first point + outline.back()-> endPoint = outline.front()->startPoint; + + bo = outline.begin(); + eo = outline.end(); + + // for the first item we write out both points + if( (*bo)->angle < MIN_ANG && (*bo)->angle > -MIN_ANG ) + { + if( isInch ) + { + fprintf( aFile, "%c %d %d 0\n", loopDir, + (int) (1000 * (*bo)->startPoint.x), + (int) (1000 * (*bo)->startPoint.y) ); + fprintf( aFile, "%c %d %d 0\n", loopDir, + (int) (1000 * (*bo)->endPoint.x), + (int) (1000 * (*bo)->endPoint.y) ); + } + else + { + fprintf( aFile, "%c %.3f %.3f 0\n", loopDir, + (*bo)->startPoint.x, (*bo)->startPoint.y ); + fprintf( aFile, "%c %.3f %.3f 0\n", loopDir, + (*bo)->endPoint.x, (*bo)->endPoint.y ); + } + } + else + { + if( isInch ) + { + fprintf( aFile, "%c %d %d 0\n", loopDir, + (int) (1000 * (*bo)->startPoint.x), + (int) (1000 * (*bo)->startPoint.y) ); + fprintf( aFile, "%c %d %d %.2f\n", loopDir, + (int) (1000 * (*bo)->endPoint.x), + (int) (1000 * (*bo)->endPoint.y), + (*bo)->angle ); + } + else + { + fprintf( aFile, "%c %.3f %.3f 0\n", loopDir, + (*bo)->startPoint.x, (*bo)->startPoint.y ); + fprintf( aFile, "%c %.3f %.3f %.2f\n", loopDir, + (*bo)->endPoint.x, (*bo)->endPoint.y, (*bo)->angle ); + } + } + + ++bo; + + // for all other segments we only write out the last point + while( bo != eo ) + { + if( isInch ) + { + if( (*bo)->angle < MIN_ANG && (*bo)->angle > -MIN_ANG ) + { + fprintf( aFile, "%c %d %d 0\n", loopDir, + (int) (1000 * (*bo)->endPoint.x), + (int) (1000 * (*bo)->endPoint.y) ); + } + else + { + fprintf( aFile, "%c %d %d %.2f\n", loopDir, + (int) (1000 * (*bo)->endPoint.x), + (int) (1000 * (*bo)->endPoint.y), + (*bo)->angle ); + } + } + else + { + if( (*bo)->angle < MIN_ANG && (*bo)->angle > -MIN_ANG ) + { + fprintf( aFile, "%c %.5f %.5f 0\n", loopDir, + (*bo)->endPoint.x, (*bo)->endPoint.y ); + } + else + { + fprintf( aFile, "%c %.5f %.5f %.2f\n", loopDir, + (*bo)->endPoint.x, (*bo)->endPoint.y, (*bo)->angle ); + } + } + + ++bo; + } + + return true; +} + + +void DXF2IDF::addHeader( const DRW_Header* data ) +{ + std::map<std::string, DRW_Variant*>::const_iterator it; + m_scale = 1.0; // assume no scale factor + + for( it = data->vars.begin(); it != data->vars.end(); ++it ) + { + std::string key = ( (*it).first ).c_str(); + + if( key == "$INSUNITS" ) + { + DRW_Variant* var = (*it).second; + + switch( var->content.i ) + { + case 1: // inches + m_scale = 25.4; + break; + + case 2: // feet + m_scale = 304.8; + break; + + case 5: // centimeters + m_scale = 10.0; + break; + + case 6: // meters + m_scale = 1000.0; + break; + + case 8: // microinches + m_scale = 2.54e-5; + break; + + case 9: // mils + m_scale = 0.0254; + break; + + case 10: // yards + m_scale = 914.4; + break; + + case 11: // Angstroms + m_scale = 1.0e-7; + break; + + case 12: // nanometers + m_scale = 1.0e-6; + break; + + case 13: // micrometers + m_scale = 1.0e-3; + break; + + case 14: // decimeters + m_scale = 100.0; + break; + + default: + // use the default of 1.0 for: + // 0: Unspecified Units + // 4: mm + // 3: miles + // 7: kilometers + // 15: decameters + // 16: hectometers + // 17: gigameters + // 18: AU + // 19: lightyears + // 20: parsecs + break; + } + } + } +} + + +void DXF2IDF::addLWPolyline(const DRW_LWPolyline& data ) +{ + IDF_POINT poly_start; + IDF_POINT seg_start; + IDF_POINT seg_end; + double bulge = 0.0; + + if( !data.vertlist.empty() ) + { + DRW_Vertex2D* vertex = data.vertlist[0]; + seg_start.x = vertex->x * m_scale; + seg_start.y = vertex->y * m_scale; + poly_start = seg_start; + bulge = vertex->bulge; + } + + for( size_t i = 1; i < data.vertlist.size(); ++i ) + { + DRW_Vertex2D* vertex = data.vertlist[i]; + seg_end.x = vertex->x * m_scale; + seg_end.y = vertex->y * m_scale; + + if( std::abs( bulge ) < MIN_BULGE ) + insertLine( seg_start, seg_end ); + else + insertArc( seg_start, seg_end, bulge ); + + seg_start = seg_end; + bulge = vertex->bulge; + } + + // Polyline flags bit 0 indicates closed (1) or open (0) polyline + if( data.flags & 1 ) + { + if( std::abs( bulge ) < MIN_BULGE ) + insertLine( seg_start, poly_start ); + else + insertArc( seg_start, poly_start, bulge ); + } + + return; +} + + +void DXF2IDF::addPolyline(const DRW_Polyline& data ) +{ + IDF_POINT poly_start; + IDF_POINT seg_start; + IDF_POINT seg_end; + + if( !data.vertlist.empty() ) + { + DRW_Vertex* vertex = data.vertlist[0]; + seg_start.x = vertex->basePoint.x * m_scale; + seg_start.y = vertex->basePoint.y * m_scale; + poly_start = seg_start; + } + + for( size_t i = 1; i < data.vertlist.size(); ++i ) + { + DRW_Vertex* vertex = data.vertlist[i]; + seg_end.x = vertex->basePoint.x * m_scale; + seg_end.y = vertex->basePoint.y * m_scale; + insertLine( seg_start, seg_end ); + seg_start = seg_end; + } + + // Polyline flags bit 0 indicates closed (1) or open (0) polyline + if( data.flags & 1 ) + insertLine( seg_start, poly_start ); + + return; +} + + +void DXF2IDF::insertLine( const IDF_POINT& aSegStart, const IDF_POINT& aSegEnd ) +{ + IDF_SEGMENT* seg = new IDF_SEGMENT( aSegStart, aSegEnd ); + + if( seg ) + lines.push_back( seg ); + + return; +} + + +void DXF2IDF::insertArc( const IDF_POINT& aSegStart, const IDF_POINT& aSegEnd, + double aBulge ) +{ + if( aBulge < -MAX_BULGE ) + aBulge = -MAX_BULGE; + else if( aBulge > MAX_BULGE ) + aBulge = MAX_BULGE; + + double ang = 720.0 * atan( aBulge ) / M_PI; + + IDF_SEGMENT* seg = new IDF_SEGMENT( aSegStart, aSegEnd, ang, false ); + + if( seg ) + lines.push_back( seg ); + + return; +} |