index b7918a615f0d628a43db45ed8632061e15235d66..30c7b162cc083420ce6931f401dfc25374bd650b 100644 (file)
#include "live_effects/lpe-spiro.h"
#include "display/curve.h"
#include <libnr/n-art-bpath.h>
+#include "nodepath.h"
#include "live_effects/bezctx.h"
#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;
int is_open;
} bezctx_ink;
-void bezctx_ink_moveto(bezctx *bc, double x, double y, int is_open)
+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)
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);
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 *
{
}
+void
+LPESpiro::setup_nodepath(Inkscape::NodePath::Path *np)
+{
+ sp_nodepath_show_handles(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;
}
} 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)
+ if (closed)
next = first_in_subpath;
} else {
if (ib < len)
next = first_in_subpath;
}
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);
- 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;
+ 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)) < 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)) < 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);
- }
- double next_angle = NR_HUGE;
+ this_angle = NR::Point (bpath[ib].x3 - bpath[ib].x2, bpath[ib].y3 - bpath[ib].y2);
+ }
+ 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);
- }
- if (this_angle != NR_HUGE && next_angle != NR_HUGE && fabs(this_angle - next_angle) < 0.001) {
+ next_angle = NR::Point (next->x1 - bpath[ib].x3, next->y1 - bpath[ib].y3);
+ }
+ 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) {
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