packages feed

juicy-gcode 0.1.0.7 → 0.1.0.8

raw patch · 3 files changed

+55/−30 lines, 3 files

Files

ChangeLog.md view
@@ -1,41 +1,45 @@ # Revision history for juicy-gcode
 
-## 0.1.0.7  -- 2020-05-15
+## 0.1.0.8 -- 2020-05-19
 
-* Add support for the viewBox attribute
+- Fix unhandled bezier edge cases resulting NaNs in GCode
 
-## 0.1.0.6  -- 2020-05-11
+## 0.1.0.7 -- 2020-05-15
 
-* Add option to mirror Y axis
+- Add support for the viewBox attribute
 
-## 0.1.0.5.2  -- 2020-04-11
+## 0.1.0.6 -- 2020-05-11
 
-* Update dependencies
+- Add option to mirror Y axis
 
-## 0.1.0.5.1  -- 2018-08-08
+## 0.1.0.5.2 -- 2020-04-11
 
-* Update documentation
+- Update dependencies
 
-## 0.1.0.5  -- 2018-08-08
+## 0.1.0.5.1 -- 2018-08-08
 
-* Simplify special bezier curves to lines
+- Update documentation
 
-## 0.1.0.4  -- 2017-12-30
+## 0.1.0.5 -- 2018-08-08
 
-* Update LICENSE
+- Simplify special bezier curves to lines
 
-## 0.1.0.3  -- 2017-03-19
+## 0.1.0.4 -- 2017-12-30
 
-* Fix typo in cabal file
+- Update LICENSE
 
-## 0.1.0.2  -- 2017-03-18
+## 0.1.0.3 -- 2017-03-19
 
-* Fix generating arcs with negative I or J
+- Fix typo in cabal file
 
-## 0.1.0.1  -- 2016-10-31
+## 0.1.0.2 -- 2017-03-18
 
-* Minor changes to the package description and README.
+- Fix generating arcs with negative I or J
 
-## 0.1.0.0  -- 2016-10-30
+## 0.1.0.1 -- 2016-10-31
 
-* First version. Mostly feature complete, but not well tested.
+- Minor changes to the package description and README.
+
+## 0.1.0.0 -- 2016-10-30
+
+- First version. Mostly feature complete, but not well tested.
juicy-gcode.cabal view
@@ -1,5 +1,5 @@ name:                juicy-gcode
-version:             0.1.0.7
+version:             0.1.0.8
 license:             BSD3
 license-file:        LICENSE
 author:              dlacko
src/Approx.hs view
@@ -1,10 +1,12 @@ module Approx ( bezier2biarc
               ) where
-                    
+
 import qualified CubicBezier as B
 import qualified BiArc as BA          
 import qualified Line as L 
           
+import Data.Bool (bool)
+
 import Linear    
 import Data.Complex
 
@@ -15,10 +17,15 @@              -> Double
              -> [BA.BiArc]
 bezier2biarc mbezier samplingStep tolerance
-    = byInflection (B.realInflectionPoint i1) (B.realInflectionPoint i2)
-    where        
+    | (B._p1 mbezier) == (B._c1 mbezier)
+        = approxOne mbezier
+    | (B._p2 mbezier) == (B._c2 mbezier)
+        = approxOne mbezier
+    | otherwise 
+        = byInflection (B.realInflectionPoint i1) (B.realInflectionPoint i2)
+    where
         (i1, i2) = B.inflectionPoints mbezier
-    
+
         order a b | b < a = (b, a)
                   | otherwise = (a, b)
     
@@ -46,15 +53,26 @@         -- TODO: make it tail recursive
         approxOne :: B.CubicBezier -> [BA.BiArc]
         approxOne bezier
+            -- Edge case: start- and endpoints are the same
+            | (B._p1 bezier) == (B._p2 bezier)
+                = splitAndRecur 0.5
+            -- Edge case: control lines are parallel
+            | (L._m t1) == (L._m t2)
+                = splitAndRecur 0.5
+            -- Approximation is not close enough yet, refine
             | maxDistance > tolerance
-                = let (b1, b2) = B.bezierSplitAt bezier maxDistanceAt 
-                   in approxOne b1 ++ approxOne b2
+                = splitAndRecur maxDistanceAt
             | otherwise
                 = [biarc] 
             where
+                -- Edge case: P1==C1 or P2==C2
+                -- there is no derivative at P1 or P2, use the other control point
+                c1 = bool (B._c1 bezier) (B._c2 bezier) ((B._p1 bezier) == (B._c1 bezier))
+                c2 = bool (B._c2 bezier) (B._c1 bezier) ((B._p2 bezier) == (B._c2 bezier))
+
                 -- V: Intersection point of tangent lines
-                t1 = L.fromPoints (B._p1 bezier) (B._c1 bezier)
-                t2 = L.fromPoints (B._p2 bezier) (B._c2 bezier)
+                t1 = L.fromPoints (B._p1 bezier) c1
+                t2 = L.fromPoints (B._p2 bezier) c2
                 v = L.intersection t1 t2
 
                 -- G: incenter point of the triangle (P1, V, P2)
@@ -64,7 +82,7 @@                 g = (dP2V *^ B._p1 bezier + dP1V *^ B._p2 bezier + dP1P2 *^ v) ^/ (dP2V + dP1V + dP1P2)
 
                 -- Calculate the BiArc
-                biarc = BA.create (B._p1 bezier) (B._p1 bezier - B._c1 bezier) (B._p2 bezier) (B._p2 bezier - B._c2 bezier) g
+                biarc = BA.create (B._p1 bezier) (B._p1 bezier - c1) (B._p2 bezier) (B._p2 bezier - c2) g
                 
                 -- calculate the error
                 nrPointsToCheck = (BA.arcLength biarc) / samplingStep
@@ -80,4 +98,7 @@                     where
                         d = distance (BA.pointAt biarc t) (B.pointAt bezier t)
                         nt = t + parameterStep
+
+                splitAndRecur t = let (b1, b2) = B.bezierSplitAt bezier t
+                                   in approxOne b1 ++ approxOne b2