Repository: meerk40t/svgelements

Issue:
Numerical Instability above the 1e-12 level for cubic bounding box.
```python
    def test_bbox_failure(self):
        p = Path(transform=Matrix(682.657124793113, 0.000000000003, -0.000000000003, 682.657124793113, 257913.248909660178, -507946.354527872754))
        p += CubicBezier(start=Point(-117.139521365,1480.99923469), control1=Point(-41.342266634,1505.62725567), control2=Point(40.3422666342,1505.62725567), end=Point(116.139521365,1480.99923469))
        bounds = p.bbox()
        self.assertNotAlmostEquals(bounds[1], bounds[3], delta=100)
```

This fails even though it's basically an arc and the y-range should be quite considerable.

See: meerk40t/meerk40t#1798



Comments:

Patch:
diff --git a/setup.cfg b/setup.cfg
index f1fdd39..ce62894 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
 [metadata]
 name = svgelements
-version = 1.9.1
+version = 1.9.2
 description = Svg Elements Parsing
 long_description_content_type=text/markdown
 long_description = file: README.md
@@ -10,14 +10,12 @@ classifiers =
     License :: OSI Approved :: MIT License
     Operating System :: OS Independent
     Programming Language :: Python
-    Programming Language :: Python :: 2.7
-    Programming Language :: Python :: 3.5
     Programming Language :: Python :: 3.6
     Programming Language :: Python :: 3.7
     Programming Language :: Python :: 3.8
     Programming Language :: Python :: 3.9
     Programming Language :: Python :: 3.10
-    Programming Language :: Python :: Implementation :: PyPy
+    Programming Language :: Python :: 3.11
     Topic :: Multimedia :: Graphics
     Topic :: Multimedia :: Graphics :: Editors :: Vector-Based
     Topic :: Software Development :: Libraries :: Python Modules
diff --git a/svgelements/svgelements.py b/svgelements/svgelements.py
index e89a99d..43f2a39 100644
--- a/svgelements/svgelements.py
+++ b/svgelements/svgelements.py
@@ -43,7 +43,7 @@ Though not required the Image class acquires new functionality if provided with
 and the Arc can do exact arc calculations if scipy is installed.
 """
 
-SVGELEMENTS_VERSION = "1.9.1"
+SVGELEMENTS_VERSION = "1.9.2"
 
 MIN_DEPTH = 5
 ERROR = 1e-12
@@ -4773,7 +4773,7 @@ class CubicBezier(Curve):
         local_extremizers = [0, 1]
         a = [c[v] for c in self]
         denom = a[0] - 3 * a[1] + 3 * a[2] - a[3]
-        if abs(denom) >= 1e-12:
+        if abs(denom) >= 1e-8:
             delta = (
                 a[1] * a[1] - (a[0] + a[1]) * a[2] + a[2] * a[2] + (a[0] - a[1]) * a[3]
             )


Test patch:
diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml
index fb8bd86..f046eba 100644
--- a/.github/workflows/unittests.yml
+++ b/.github/workflows/unittests.yml
@@ -29,13 +29,14 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        os: [ubuntu-18.04, macos-11]
-        python-version: [3.9]
+        os: [ubuntu-20.04, ubuntu-latest, macos-11]
+        python-version: ['3.9', '3.11']
         experimental: [false]
         include:
-          - os: ubuntu-18.04
+          - os: ubuntu-20.04
+            python-version: 3.6
+          - os: macos-11
             python-version: 3.6
-            experimental: false
 
     steps:
 
@@ -43,7 +44,7 @@ jobs:
       uses: actions/checkout@v2
 
     - name: Set up Python ${{ matrix.python-version }}
-      uses: actions/setup-python@v2
+      uses: actions/setup-python@v4
       with:
         python-version: ${{ matrix.python-version }}
 
diff --git a/test/test_cubic_bezier.py b/test/test_cubic_bezier.py
index 37ef038..6927487 100644
--- a/test/test_cubic_bezier.py
+++ b/test/test_cubic_bezier.py
@@ -74,3 +74,9 @@ class TestElementCubicBezierPoint(unittest.TestCase):
             bbox2 = cubic2.bbox()
             for a, b in zip(bbox1, bbox2):
                 self.assertAlmostEqual(a, b, delta=1e-5)
+
+    def test_cubic_bounds_issue_220(self):
+        p = Path(transform=Matrix(682.657124793113, 0.000000000003, -0.000000000003, 682.657124793113, 257913.248909660178, -507946.354527872754))
+        p += CubicBezier(start=Point(-117.139521365,1480.99923469), control1=Point(-41.342266634,1505.62725567), control2=Point(40.3422666342,1505.62725567), end=Point(116.139521365,1480.99923469))
+        bounds = p.bbox()
+        self.assertNotAlmostEquals(bounds[1], bounds[3], delta=100)