From 6632cb056c5ae1770f03b03b4e872197ba6bb8ea Mon Sep 17 00:00:00 2001
From: jean-pierre charras <jp.charras@wanadoo.fr>
Date: Sun, 17 Oct 2021 17:40:52 +0200
Subject: [PATCH] Fix issues with arcs in kicad2step, due to last kicad_pcb
 format changes. Fixes #9409 https://gitlab.com/kicad/code/kicad/issues/9409

---
 utils/kicad2step/CMakeLists.txt     |  5 ++++-
 utils/kicad2step/pcb/kicadcurve.cpp | 32 +++++++++++++++++++++++++++++
 utils/kicad2step/pcb/kicadcurve.h   |  2 ++
 3 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/utils/kicad2step/CMakeLists.txt b/utils/kicad2step/CMakeLists.txt
index af6119f534..cc1aa849c9 100644
--- a/utils/kicad2step/CMakeLists.txt
+++ b/utils/kicad2step/CMakeLists.txt
@@ -29,7 +29,9 @@ add_library( kicad2step_lib STATIC
 target_include_directories( kicad2step_lib PUBLIC
     ${CMAKE_CURRENT_SOURCE_DIR}
     ${CMAKE_SOURCE_DIR}/include # for core
-    ${Boost_INCLUDE_DIR}
+    ${Boost_INCLUDE_DIR}        # see commit 03bce554
+    ${CMAKE_SOURCE_DIR}/libs/kimath/include
+    ${INC_AFTER}
 )
 
 target_link_libraries( kicad2step_lib
@@ -37,6 +39,7 @@ target_link_libraries( kicad2step_lib
     ${wxWidgets_LIBRARIES}
     ${OCC_LIBRARIES}
     ${ZLIB_LIBRARIES}
+    kimath
 )
 
 set( K2S_FILES
diff --git a/utils/kicad2step/pcb/kicadcurve.cpp b/utils/kicad2step/pcb/kicadcurve.cpp
index da836b8885..66086ef555 100644
--- a/utils/kicad2step/pcb/kicadcurve.cpp
+++ b/utils/kicad2step/pcb/kicadcurve.cpp
@@ -30,6 +30,7 @@
 #include <cmath>
 #include <iostream>
 #include <sstream>
+#include <../../../libs/kimath/include/geometry/shape_arc.h>
 
 
 KICADCURVE::KICADCURVE()
@@ -40,6 +41,7 @@ KICADCURVE::KICADCURVE()
     m_layer = LAYER_NONE;
     m_startangle = 0.0;
     m_endangle = 0.0;
+    m_arcHasMiddlePoint = false;
 
     return;
 }
@@ -142,6 +144,13 @@ bool KICADCURVE::Read( SEXPR::SEXPR* aEntry, CURVE_TYPE aCurveType )
             if( !Get2DCoordinate( child, m_end ) )
                 return false;
         }
+        else if( text == "mid" )
+        {
+            if( !Get2DCoordinate( child, m_middle ) )
+                return false;
+
+            m_arcHasMiddlePoint = true;
+        }
         else if( text == "angle" )
         {
             if( child->GetNumberOfChildren() < 2
@@ -177,6 +186,29 @@ bool KICADCURVE::Read( SEXPR::SEXPR* aEntry, CURVE_TYPE aCurveType )
         }
     }
 
+    // New arcs are defined by start middle and end points instead of center,
+    // start and arc angle
+    // So convert new params to old params
+    if( CURVE_ARC == aCurveType && m_arcHasMiddlePoint )
+    {
+        // To caculate old params, we are using SHAPE_ARC, but SHAPE_ARC use
+        // integer coords. So to avoid truncations, use a scaling factor.
+        // 1e5 is enough.
+        const double scale = 1e5;
+        SHAPE_ARC new_arc( VECTOR2I( m_start.x*scale, m_start.y*scale ),
+                           VECTOR2I( m_middle.x*scale, m_middle.y*scale ),
+                           VECTOR2I( m_end.x*scale, m_end.y*scale ), 0 );
+
+        VECTOR2I center = new_arc.GetCenter();
+        m_start.x = center.x/scale;
+        m_start.y = center.y/scale;
+        m_end.x = new_arc.GetP0().x/scale;
+        m_end.y = new_arc.GetP0().y/scale;
+        m_ep.x = new_arc.GetP1().x/scale;
+        m_ep.y = new_arc.GetP1().y/scale;
+        m_angle = new_arc.GetCentralAngle() / 180.0 * M_PI;
+    }
+
     return true;
 }
 
diff --git a/utils/kicad2step/pcb/kicadcurve.h b/utils/kicad2step/pcb/kicadcurve.h
index aecccafeac..e81aa431d1 100644
--- a/utils/kicad2step/pcb/kicadcurve.h
+++ b/utils/kicad2step/pcb/kicadcurve.h
@@ -55,6 +55,7 @@ public:
     LAYERS     m_layer;         // layer of the glyph
     DOUBLET    m_start;         // start point of line or center for arc and circle
     DOUBLET    m_end;           // end point of line, first point on arc or circle
+    DOUBLET    m_middle;        // middle point on arc for recent files
     DOUBLET    m_ep;            // actual endpoint, to be computed in the case of arcs
     DOUBLET    m_bezierctrl1;   // for bezier curve only first control point
     DOUBLET    m_bezierctrl2;   // for bezier curve only second control point
@@ -62,6 +63,7 @@ public:
     double     m_angle;         // subtended angle of arc
     double     m_startangle;
     double     m_endangle;
+    bool       m_arcHasMiddlePoint; // true if an arc id defined by 3 points
 
     std::vector<DOUBLET> m_poly; // vector of polygon points
 };