Code

Rename LPE: mirror reflect --> mirror symmetry
[inkscape.git] / src / live_effects / lpe-spiro.cpp
index 8708d091c6e718b53027aaf75a05a032dd2a0efe..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;
@@ -22,13 +29,13 @@ typedef struct {
 void bezctx_ink_moveto(bezctx *bc, double x, double y, int /*is_open*/)
 {
     bezctx_ink *bi = (bezctx_ink *) bc;
-    sp_curve_moveto(bi->curve, x, y);
+    bi->curve->moveto(x, y);
 }
 
 void bezctx_ink_lineto(bezctx *bc, double x, double y)
 {
     bezctx_ink *bi = (bezctx_ink *) bc;
-    sp_curve_lineto(bi->curve, x, y);
+    bi->curve->lineto(x, y);
 }
 
 void bezctx_ink_quadto(bezctx *bc, double xm, double ym, double x3, double y3)
@@ -39,7 +46,7 @@ void bezctx_ink_quadto(bezctx *bc, double xm, double ym, double x3, double y3)
     double x1, y1;
     double x2, y2;
 
-    NR::Point last = sp_curve_last_point(bi->curve);
+    NR::Point last = bi->curve->last_point();
     x0 = last[NR::X];
     y0 = last[NR::Y];
     x1 = xm + (1./3) * (x0 - xm);
@@ -47,14 +54,14 @@ void bezctx_ink_quadto(bezctx *bc, double xm, double ym, double x3, double y3)
     x2 = xm + (1./3) * (x3 - xm);
     y2 = ym + (1./3) * (y3 - ym);
 
-    sp_curve_curveto(bi->curve, x1, y1, x2, y2, x3, y3);
+    bi->curve->curveto(x1, y1, x2, y2, x3, y3);
 }
 
 void bezctx_ink_curveto(bezctx *bc, double x1, double y1, double x2, double y2,
                    double x3, double y3)
 {
     bezctx_ink *bi = (bezctx_ink *) bc;
-    sp_curve_curveto(bi->curve, x1, y1, x2, y2, x3, y3);
+    bi->curve->curveto(x1, y1, x2, y2, x3, y3);
 }
 
 bezctx *
@@ -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)
 {
-    SPCurve *csrc = sp_curve_copy(curve);
-    sp_curve_reset(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