Code

make faster 2geom bbox calc.
authorjohanengelen <johanengelen@users.sourceforge.net>
Mon, 23 Jun 2008 22:17:42 +0000 (22:17 +0000)
committerjohanengelen <johanengelen@users.sourceforge.net>
Mon, 23 Jun 2008 22:17:42 +0000 (22:17 +0000)
src/helper/geom.cpp

index 8a32386fc91f034371be504ccc81ab234da235fd..9373035984ce2d79a8cd9237a498fd223b108724 100644 (file)
 \r
 #include <2geom/pathvector.h>\r
 #include <2geom/transforms.h>\r
\r
+#include <2geom/rect.h>\r
+#include <2geom/coord.h>\r
+\r
+/* Fast bbox calculation */\r
+/* Thanks to Nathan Hurst for suggesting it */\r
+static void\r
+cubic_bbox (Geom::Coord x000, Geom::Coord y000, Geom::Coord x001, Geom::Coord y001, Geom::Coord x011, Geom::Coord y011, Geom::Coord x111, Geom::Coord y111, Geom::Rect &bbox)\r
+{\r
+    Geom::Coord a, b, c, D;\r
+\r
+    bbox[0].extendTo(x111);\r
+    bbox[1].extendTo(y111);\r
+\r
+    /*\r
+     * xttt = s * (s * (s * x000 + t * x001) + t * (s * x001 + t * x011)) + t * (s * (s * x001 + t * x011) + t * (s * x011 + t * x111))\r
+     * xttt = s * (s2 * x000 + s * t * x001 + t * s * x001 + t2 * x011) + t * (s2 * x001 + s * t * x011 + t * s * x011 + t2 * x111)\r
+     * xttt = s * (s2 * x000 + 2 * st * x001 + t2 * x011) + t * (s2 * x001 + 2 * st * x011 + t2 * x111)\r
+     * xttt = s3 * x000 + 2 * s2t * x001 + st2 * x011 + s2t * x001 + 2st2 * x011 + t3 * x111\r
+     * xttt = s3 * x000 + 3s2t * x001 + 3st2 * x011 + t3 * x111\r
+     * xttt = s3 * x000 + (1 - s) 3s2 * x001 + (1 - s) * (1 - s) * 3s * x011 + (1 - s) * (1 - s) * (1 - s) * x111\r
+     * xttt = s3 * x000 + (3s2 - 3s3) * x001 + (3s - 6s2 + 3s3) * x011 + (1 - 2s + s2 - s + 2s2 - s3) * x111\r
+     * xttt = (x000 - 3 * x001 + 3 * x011 -     x111) * s3 +\r
+     *        (       3 * x001 - 6 * x011 + 3 * x111) * s2 +\r
+     *        (                  3 * x011 - 3 * x111) * s  +\r
+     *        (                                 x111)\r
+     * xttt' = (3 * x000 - 9 * x001 +  9 * x011 - 3 * x111) * s2 +\r
+     *         (           6 * x001 - 12 * x011 + 6 * x111) * s  +\r
+     *         (                       3 * x011 - 3 * x111)\r
+     */\r
+\r
+    a = 3 * x000 - 9 * x001 + 9 * x011 - 3 * x111;\r
+    b = 6 * x001 - 12 * x011 + 6 * x111;\r
+    c = 3 * x011 - 3 * x111;\r
+\r
+    /*\r
+     * s = (-b +/- sqrt (b * b - 4 * a * c)) / 2 * a;\r
+     */\r
+    if (fabs (a) < Geom::EPSILON) {\r
+        /* s = -c / b */\r
+        if (fabs (b) > Geom::EPSILON) {\r
+            double s, t, xttt;\r
+            s = -c / b;\r
+            if ((s > 0.0) && (s < 1.0)) {\r
+                t = 1.0 - s;\r
+                xttt = s * s * s * x000 + 3 * s * s * t * x001 + 3 * s * t * t * x011 + t * t * t * x111;\r
+                bbox[0].extendTo(xttt);\r
+            }\r
+        }\r
+    } else {\r
+        /* s = (-b +/- sqrt (b * b - 4 * a * c)) / 2 * a; */\r
+        D = b * b - 4 * a * c;\r
+        if (D >= 0.0) {\r
+            Geom::Coord d, s, t, xttt;\r
+            /* Have solution */\r
+            d = sqrt (D);\r
+            s = (-b + d) / (2 * a);\r
+            if ((s > 0.0) && (s < 1.0)) {\r
+                t = 1.0 - s;\r
+                xttt = s * s * s * x000 + 3 * s * s * t * x001 + 3 * s * t * t * x011 + t * t * t * x111;\r
+                bbox[0].extendTo(xttt);\r
+            }\r
+            s = (-b - d) / (2 * a);\r
+            if ((s > 0.0) && (s < 1.0)) {\r
+                t = 1.0 - s;\r
+                xttt = s * s * s * x000 + 3 * s * s * t * x001 + 3 * s * t * t * x011 + t * t * t * x111;\r
+                bbox[0].extendTo(xttt);\r
+            }\r
+        }\r
+    }\r
+\r
+    a = 3 * y000 - 9 * y001 + 9 * y011 - 3 * y111;\r
+    b = 6 * y001 - 12 * y011 + 6 * y111;\r
+    c = 3 * y011 - 3 * y111;\r
+\r
+    if (fabs (a) < Geom::EPSILON) {\r
+        /* s = -c / b */\r
+        if (fabs (b) > Geom::EPSILON) {\r
+            double s, t, yttt;\r
+            s = -c / b;\r
+            if ((s > 0.0) && (s < 1.0)) {\r
+                t = 1.0 - s;\r
+                yttt = s * s * s * y000 + 3 * s * s * t * y001 + 3 * s * t * t * y011 + t * t * t * y111;\r
+                bbox[1].extendTo(yttt);\r
+            }\r
+        }\r
+    } else {\r
+        /* s = (-b +/- sqrt (b * b - 4 * a * c)) / 2 * a; */\r
+        D = b * b - 4 * a * c;\r
+        if (D >= 0.0) {\r
+            Geom::Coord d, s, t, yttt;\r
+            /* Have solution */\r
+            d = sqrt (D);\r
+            s = (-b + d) / (2 * a);\r
+            if ((s > 0.0) && (s < 1.0)) {\r
+                t = 1.0 - s;\r
+                yttt = s * s * s * y000 + 3 * s * s * t * y001 + 3 * s * t * t * y011 + t * t * t * y111;\r
+                bbox[1].extendTo(yttt);\r
+            }\r
+            s = (-b - d) / (2 * a);\r
+            if ((s > 0.0) && (s < 1.0)) {\r
+                t = 1.0 - s;\r
+                yttt = s * s * s * y000 + 3 * s * s * t * y001 + 3 * s * t * t * y011 + t * t * t * y111;\r
+                bbox[1].extendTo(yttt);\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
 Geom::Rect\r
 bounds_fast_transformed(Geom::PathVector const & pv, Geom::Matrix const & t)\r
 {\r
-    return Geom::bounds_fast(pv * t);\r
+    return bounds_exact_transformed(pv, t); //use this as it is faster for now! :)\r
+//    return Geom::bounds_fast(pv * t);\r
 }\r
 \r
 Geom::Rect\r
 bounds_exact_transformed(Geom::PathVector const & pv, Geom::Matrix const & t)\r
 {\r
-    return Geom::bounds_exact(pv * t);\r
+    Geom::Rect bbox;\r
+    \r
+    if (pv.empty())\r
+        return bbox;\r
+\r
+    Geom::Curve *temp = pv.front().front().transformed(t);\r
+    bbox = temp->boundsExact();\r
+    delete temp;\r
+\r
+    for (Geom::PathVector::const_iterator it = pv.begin(); it != pv.end(); ++it) {\r
+        bbox.expandTo(it->initialPoint() * t);\r
+\r
+        // don't loop including closing segment, since that segment can never increase the bbox\r
+        for (Geom::Path::const_iterator cit = it->begin(); cit != it->end_open(); ++cit) {\r
+            Geom::Curve const *c = &*cit;\r
+\r
+            if(Geom::LineSegment const *line_segment = dynamic_cast<Geom::LineSegment const *>(c))\r
+            {\r
+                bbox.expandTo( (*line_segment)[1] * t );\r
+            }\r
+            else if(Geom::CubicBezier const *cubic_bezier = dynamic_cast<Geom::CubicBezier const  *>(c))\r
+            {\r
+                Geom::Point c0 = (*cubic_bezier)[0] * t;\r
+                Geom::Point c1 = (*cubic_bezier)[1] * t;\r
+                Geom::Point c2 = (*cubic_bezier)[2] * t;\r
+                Geom::Point c3 = (*cubic_bezier)[3] * t;\r
+                cubic_bbox( c0[0], c0[1],\r
+                            c1[0], c1[1],\r
+                            c2[0], c2[1],\r
+                            c3[0], c3[1],\r
+                            bbox );\r
+            }\r
+            else\r
+            {\r
+                // should handle all not-so-easy curves:\r
+                Geom::Curve *ctemp = cit->transformed(t);\r
+                bbox.unionWith( ctemp->boundsExact());\r
+                delete ctemp;\r
+            }\r
+        }\r
+    }\r
+    //return Geom::bounds_exact(pv * t);\r
+    return bbox;\r
 }\r
 \r
 /*\r
@@ -37,4 +187,4 @@ bounds_exact_transformed(Geom::PathVector const & pv, Geom::Matrix const & t)
   fill-column:99\r
   End:\r
 */\r
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
\ No newline at end of file
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :\r