Wayne Stambaugh ede39780e2 Remove all debugging output that cannot be disabled.
The use of printf, wxLogDebug, and std::err/std::out causes excessive
debugging output which makes finding specific debugging messages more
difficult than it needs to be.

There is still some debugging output in test code that really needs to
be moved into a unit test.

Add debugging output section to the coding policy regarding debugging
output.
2020-08-18 10:17:36 -04:00

432 lines
11 KiB
C++

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014 Cirilo Bernardo
* Copyright (C) 2018-2020 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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 <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 )
{
DL_Dxf dxf_reader;
bool success = true;
if( !dxf_reader.in( aFile, this ) ) // if file open failed
success = false;
return success;
}
void DXF2IDF::addLine( const DL_LineData& aData )
{
IDF_POINT p1, p2;
p1.x = aData.x1 * m_scale;
p1.y = aData.y1 * m_scale;
p2.x = aData.x2 * m_scale;
p2.y = aData.y2 * m_scale;
insertLine( p1, p2 );
return;
}
void DXF2IDF::addCircle( const DL_CircleData& aData )
{
IDF_POINT p1, p2;
p1.x = aData.cx * m_scale;
p1.y = aData.cy * m_scale;
p2.x = p1.x + aData.radius * 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 DL_ArcData& aData )
{
IDF_POINT p1, p2;
p1.x = aData.cx * m_scale;
p1.y = aData.cy * m_scale;
// note: DXF circles always run CCW
double ea = aData.angle2;
while( ea < aData.angle1 )
ea += M_PI;
p2.x = p1.x + cos( aData.angle1 ) * aData.radius * m_scale;
p2.y = p1.y + sin( aData.angle1 ) * aData.radius * m_scale;
double angle = ( ea - aData.angle1 ) * 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() )
{
return false;
}
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() )
{
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::setVariableInt( const std::string& key, int value, int code )
{
// Called for every int variable in the DXF file (e.g. "$INSUNITS").
if( key == "$INSUNITS" ) // Drawing units
{
switch( value )
{
case 1: // inches
m_scale = 25.4;
break;
case 2: // feet
m_scale = 304.8;
break;
case 4: // mm
m_scale = 1.0;
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
// 3: miles
// 7: kilometers
// 15: decameters
// 16: hectometers
// 17: gigameters
// 18: AU
// 19: lightyears
// 20: parsecs
m_scale = 1.0;
break;
}
return;
}
}
void DXF2IDF::addPolyline(const DL_PolylineData& aData )
{
// Convert DXF Polylines into a series of Lines and Arcs.
// A Polyline (as opposed to a LWPolyline) may be a 3D line or
// even a 3D Mesh. The only type of Polyline which is guaranteed
// to import correctly is a 2D Polyline in X and Y, which is what
// we assume of all Polylines. The width used is the width of the Polyline.
// per-vertex line widths, if present, are ignored.
m_entityParseStatus = 1;
m_entity_flags = aData.flags;
m_entityType = DL_ENTITY_POLYLINE;
}
void DXF2IDF::addVertex( const DL_VertexData& aData )
{
if( m_entityParseStatus == 0 )
return; // Error
if( m_entityParseStatus == 1 ) // This is the first vertex of an entity
{
m_lastCoordinate.x = aData.x * m_scale;
m_lastCoordinate.y = aData.y * m_scale;
m_polylineStart = m_lastCoordinate;
m_bulgeVertex = aData.bulge;
m_entityParseStatus = 2;
return;
}
IDF_POINT seg_end;
seg_end.x = aData.x * m_scale;
seg_end.y = aData.y * m_scale;
insertLine( m_lastCoordinate, seg_end );
m_lastCoordinate = seg_end;
}
void DXF2IDF::endEntity()
{
if( m_entityType == DL_ENTITY_POLYLINE )
{
// Polyline flags bit 0 indicates closed (1) or open (0) polyline
if( m_entity_flags & 1 )
{
if( std::abs( m_bulgeVertex ) < MIN_BULGE )
insertLine( m_lastCoordinate, m_polylineStart );
else
insertArc( m_lastCoordinate, m_polylineStart, m_bulgeVertex );
}
}
m_entityType = 0 ;
m_entity_flags = 0;
m_entityParseStatus = 0;
}
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;
}