← Back to team overview

kicad-developers team mailing list archive

PATCH: IDF tools

 

The attached patch makes the following changes to the IDF
tool 'dxf2idf':

1. DXF units are now correctly scaled to mm
2. Polylines are now supported
3. LWPolylines are now supported

- Cirilo
=== modified file 'utils/idftools/dxf2idf.cpp'
--- utils/idftools/dxf2idf.cpp	2014-02-05 09:27:21 +0000
+++ utils/idftools/dxf2idf.cpp	2016-03-21 10:16:01 +0000
@@ -29,6 +29,13 @@
 // 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() )
@@ -60,22 +67,12 @@
 {
     IDF_POINT p1, p2;
 
-    p1.x = data.basePoint.x;
-    p1.y = data.basePoint.y;
-    p2.x = data.secPoint.x;
-    p2.y = data.secPoint.y;
-
-    IDF_SEGMENT* seg = new IDF_SEGMENT( p1, p2 );
-
-    if( !seg )
-    {
-        std::cerr << "* FAULT: could not add a linear segment to the outline\n";
-    }
-    else
-    {
-        lines.push_back( seg );
-    }
-
+    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;
 }
 
@@ -84,22 +81,16 @@
 {
     IDF_POINT p1, p2;
 
-    p1.x = data.basePoint.x;
-    p1.y = data.basePoint.y;
+    p1.x = data.basePoint.x * m_scale;
+    p1.y = data.basePoint.y * m_scale;
 
-    p2.x = p1.x + data.radious;
+    p2.x = p1.x + data.radious * m_scale;
     p2.y = p1.y;
 
     IDF_SEGMENT* seg = new IDF_SEGMENT( p1, p2, 360, true );
 
-    if( !seg )
-    {
-        std::cerr << "* FAULT: could not add a linear segment to the outline\n";
-    }
-    else
-    {
+    if( seg )
         lines.push_back( seg );
-    }
 
     return;
 }
@@ -109,8 +100,8 @@
 {
     IDF_POINT p1, p2;
 
-    p1.x = data.basePoint.x;
-    p1.y = data.basePoint.y;
+    p1.x = data.basePoint.x * m_scale;
+    p1.y = data.basePoint.y * m_scale;
 
     // note: DXF circles always run CCW
     double ea = data.endangle;
@@ -118,21 +109,15 @@
     while( ea < data.staangle )
         ea += M_PI;
 
-    p2.x = p1.x + cos( data.staangle ) * data.radious;
-    p2.y = p1.y + sin( data.staangle ) * data.radious;
+    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 )
-    {
-        std::cerr << "* FAULT: could not add a linear segment to the outline\n";
-    }
-    else
-    {
+    if( seg )
         lines.push_back( seg );
-    }
 
     return;
 }
@@ -290,3 +275,186 @@
 
     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;
+}

=== modified file 'utils/idftools/dxf2idf.h'
--- utils/idftools/dxf2idf.h	2015-02-24 09:07:40 +0000
+++ utils/idftools/dxf2idf.h	2016-03-21 10:15:55 +0000
@@ -32,6 +32,10 @@
 {
 private:
     std::list< IDF_SEGMENT* > lines;    // Unsorted list of graphical segments
+    double m_scale;                     // scaling factor to mm
+
+    void insertLine( const IDF_POINT& aSegStart, const IDF_POINT& aSegEnd );
+    void insertArc( const IDF_POINT& aSegStart, const IDF_POINT& aSegEnd, double aBulge );
 
 public:
     ~DXF2IDF();
@@ -41,12 +45,14 @@
 
 private:
     // DRW_Interface implemented callback functions
+    virtual void addHeader( const DRW_Header* data );
     virtual void addLine(const DRW_Line& data);
     virtual void addArc(const DRW_Arc& data );
     virtual void addCircle(const DRW_Circle& data );
+    virtual void addLWPolyline(const DRW_LWPolyline& data );
+    virtual void addPolyline(const DRW_Polyline& data );
 
     // DRW_Interface callbacks unsupported by DXF2IDF
-    virtual void addHeader( const DRW_Header* data ){}
     virtual void addLType( const DRW_LType& data ){}
     virtual void addLayer( const DRW_Layer& data ){}
     virtual void addDimStyle( const DRW_Dimstyle& data ){}
@@ -59,8 +65,6 @@
     virtual void addRay(const DRW_Ray& data ){}
     virtual void addXline(const DRW_Xline& data ){}
     virtual void addEllipse(const DRW_Ellipse& data ){}
-    virtual void addLWPolyline(const DRW_LWPolyline& data ){}
-    virtual void addPolyline(const DRW_Polyline& data ){}
     virtual void addSpline(const DRW_Spline* data ){}
     virtual void addKnot(const DRW_Entity&){}
     virtual void addInsert(const DRW_Insert& data ){}

=== modified file 'utils/idftools/idf_common.cpp'
--- utils/idftools/idf_common.cpp	2015-07-03 08:42:47 +0000
+++ utils/idftools/idf_common.cpp	2016-03-21 10:31:06 +0000
@@ -1141,8 +1141,10 @@
     else
         offAng -= M_PI_2;
 
-    if( ( angle > 180.0 ) || ( angle < -180.0 ) )
+    if( angle < -180.0 )
         offAng += M_PI;
+    else if( angle > 180 )
+        offAng -= M_PI;
 
     center.x = h * cos( offAng ) + xm;
     center.y = h * sin( offAng ) + ym;


Follow ups