Code

Rename LPE: mirror reflect --> mirror symmetry
[inkscape.git] / src / live_effects / lpe-spiro.cpp
index 7bbeef7d2bf73a4c264e0b89cf9b23084d409d13..30c7b162cc083420ce6931f401dfc25374bd650b 100644 (file)
 #include "live_effects/bezctx_intf.h"
 #include "live_effects/spiro.h"
 
+// For handling un-continuous paths:
+#include <2geom/pathvector.h>
+#include <2geom/matrix.h>
+#include "message-stack.h"
+#include "inkscape.h"
+#include "desktop.h"
+
 typedef struct {
     bezctx base;
     SPCurve *curve;
@@ -88,23 +95,25 @@ void
 LPESpiro::setup_nodepath(Inkscape::NodePath::Path *np)
 {
     sp_nodepath_show_handles(np, false);
-    sp_nodepath_show_helperpath(np, false);
+//    sp_nodepath_show_helperpath(np, false);
 }
 
 void
 LPESpiro::doEffect(SPCurve * curve)
 {
+    Geom::PathVector original_pathv = curve->get_pathvector();
+
     SPCurve *csrc = curve->copy();
     curve->reset();
     bezctx *bc = new_bezctx_ink(curve);
     int len = SP_CURVE_LENGTH(csrc);
     spiro_cp *path = g_new (spiro_cp, len + 1);
-    NArtBpath *bpath = csrc->_bpath;
+    NArtBpath const *bpath = csrc->get_bpath();
     int ib = 0;
     int ip = 0;
     bool closed = false;
     NR::Point pt(0, 0);
-    NArtBpath *first_in_subpath = NULL;
+    NArtBpath const *first_in_subpath = NULL;
     while(ib <= len) {
         path [ip].x = bpath[ib].x3;
         path [ip].y = bpath[ib].y3;
@@ -138,7 +147,7 @@ LPESpiro::doEffect(SPCurve * curve)
             }
         } else {
                 // this point is not last, so makes sense to find a proper type for it
-                NArtBpath *next = NULL;
+                NArtBpath const *next = NULL;
                 if (ib < len && (bpath[ib+1].code == NR_END || bpath[ib+1].code == NR_MOVETO_OPEN || bpath[ib+1].code == NR_MOVETO)) { // end of subpath
                     if (closed)
                         next = first_in_subpath;
@@ -150,22 +159,27 @@ LPESpiro::doEffect(SPCurve * curve)
                 }
                 if (next) {
                     bool this_is_line = bpath[ib].code == NR_LINETO ||
-                        (NR::L2(NR::Point(bpath[ib].x3, bpath[ib].y3) - NR::Point(bpath[ib].x2, bpath[ib].y2)) < 0.001);
+                        (NR::L2(NR::Point(bpath[ib].x3, bpath[ib].y3) - NR::Point(bpath[ib].x2, bpath[ib].y2)) < 1e-6);
                     bool next_is_line = next->code == NR_LINETO ||
-                        (NR::L2(NR::Point(bpath[ib].x3, bpath[ib].y3) - NR::Point(next->x1, next->y1)) < 0.001);
-                    double this_angle = NR_HUGE;
+                        (NR::L2(NR::Point(bpath[ib].x3, bpath[ib].y3) - NR::Point(next->x1, next->y1)) < 1e-6);
+                    NR::Point this_angle (0, 0);
                     if (this_is_line) {
-                        this_angle = atan2 (bpath[ib].x3 - pt[NR::X], bpath[ib].y3 - pt[NR::Y]);
+                        this_angle = NR::Point (bpath[ib].x3 - pt[NR::X], bpath[ib].y3 - pt[NR::Y]);
                     } else if (bpath[ib].code == NR_CURVETO) {
-                        this_angle = atan2 (bpath[ib].x3 - bpath[ib].x2, bpath[ib].y3 - bpath[ib].y2);
+                        this_angle = NR::Point (bpath[ib].x3 - bpath[ib].x2, bpath[ib].y3 - bpath[ib].y2);
                     }
-                    double next_angle = NR_HUGE;
+                    NR::Point next_angle (0, 0);
                     if (next_is_line) {
-                        next_angle = atan2 (next->x3 - bpath[ib].x3, next->y3 - bpath[ib].y3);
+                        next_angle = NR::Point (next->x3 - bpath[ib].x3, next->y3 - bpath[ib].y3);
                     } else if (next->code == NR_CURVETO) {
-                        next_angle = atan2 (next->x1 - bpath[ib].x3, next->y1 - bpath[ib].y3);
+                        next_angle = NR::Point (next->x1 - bpath[ib].x3, next->y1 - bpath[ib].y3);
                     }
-                    if (this_angle != NR_HUGE && next_angle != NR_HUGE && fabs(this_angle - next_angle) < 0.001) {
+                    double this_angle_L2 = NR::L2(this_angle);
+                    double next_angle_L2 = NR::L2(next_angle);
+                    double both_angles_L2 = NR::L2(this_angle + next_angle);
+                    if (this_angle_L2 > 1e-6 &&
+                        next_angle_L2 > 1e-6 &&
+                        this_angle_L2 + next_angle_L2 - both_angles_L2 < 1e-3) {
                         if (this_is_line && !next_is_line) {
                             path[ip].ty = ']';
                         } else if (next_is_line && !this_is_line) {
@@ -187,6 +201,18 @@ LPESpiro::doEffect(SPCurve * curve)
         ib++;
     }
     g_free (path);
+
+    // FIXME: refactor the spiro code such that it cannot generate non-continous paths!
+    // sometimes, the code above generates a path that is not continuous. if so, undo the effect by resetting the original path.
+    try {
+        curve->get_pathvector() * Geom::identity(); // tests for continuity, this makes LPE Spiro slower of course :-(
+    }
+    catch (Geom::ContinuityError & e) {
+        g_warning("Exception during LPE Spiro execution. \n %s", e.what());
+        SP_ACTIVE_DESKTOP->messageStack()->flash( Inkscape::WARNING_MESSAGE,
+            _("An exception occurred during execution of the Spiro Path Effect.") );
+        curve->set_pathvector(original_pathv);
+    }
 }
 
 }; //namespace LivePathEffect