summaryrefslogtreecommitdiffstats
path: root/src/live_effects/lpe-spiro.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/live_effects/lpe-spiro.cpp')
-rw-r--r--src/live_effects/lpe-spiro.cpp196
1 files changed, 196 insertions, 0 deletions
diff --git a/src/live_effects/lpe-spiro.cpp b/src/live_effects/lpe-spiro.cpp
new file mode 100644
index 000000000..b7918a615
--- /dev/null
+++ b/src/live_effects/lpe-spiro.cpp
@@ -0,0 +1,196 @@
+#define INKSCAPE_LPE_SPIRO_C
+
+/*
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "live_effects/lpe-spiro.h"
+#include "display/curve.h"
+#include <libnr/n-art-bpath.h>
+
+#include "live_effects/bezctx.h"
+#include "live_effects/bezctx_intf.h"
+#include "live_effects/spiro.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)
+{
+ bezctx_ink *bi = (bezctx_ink *) bc;
+ sp_curve_moveto(bi->curve, 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);
+}
+
+void bezctx_ink_quadto(bezctx *bc, double xm, double ym, double x3, double y3)
+{
+ bezctx_ink *bi = (bezctx_ink *) bc;
+
+ double x0, y0;
+ double x1, y1;
+ double x2, y2;
+
+ NR::Point last = sp_curve_last_point(bi->curve);
+ x0 = last[NR::X];
+ y0 = last[NR::Y];
+ x1 = xm + (1./3) * (x0 - xm);
+ y1 = ym + (1./3) * (y0 - ym);
+ x2 = xm + (1./3) * (x3 - xm);
+ y2 = ym + (1./3) * (y3 - ym);
+
+ sp_curve_curveto(bi->curve, 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);
+}
+
+bezctx *
+new_bezctx_ink(SPCurve *curve) {
+ bezctx_ink *result = g_new(bezctx_ink, 1);
+ result->base.moveto = bezctx_ink_moveto;
+ result->base.lineto = bezctx_ink_lineto;
+ result->base.quadto = bezctx_ink_quadto;
+ result->base.curveto = bezctx_ink_curveto;
+ result->base.mark_knot = NULL;
+ result->curve = curve;
+ return &result->base;
+}
+
+
+
+
+namespace Inkscape {
+namespace LivePathEffect {
+
+LPESpiro::LPESpiro(LivePathEffectObject *lpeobject) :
+ Effect(lpeobject)
+{
+}
+
+LPESpiro::~LPESpiro()
+{
+}
+
+void
+LPESpiro::doEffect(SPCurve * curve)
+{
+ SPCurve *csrc = sp_curve_copy(curve);
+ sp_curve_reset(curve);
+ 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;
+ int ib = 0;
+ int ip = 0;
+ bool closed = false;
+ NR::Point pt(0, 0);
+ NArtBpath *first_in_subpath = NULL;
+ while(ib <= len) {
+ path [ip].x = bpath[ib].x3;
+ path [ip].y = bpath[ib].y3;
+ // std::cout << "==" << bpath[ib].code << " ip" << ip << " ib" << ib << "\n";
+ if (bpath[ib].code == NR_END || bpath[ib].code == NR_MOVETO_OPEN || bpath[ib].code == NR_MOVETO) {
+ if (ip != 0) { // run prev subpath
+ int sp_len = 0;
+ if (!closed) {
+ path[ip - 1].ty = '}';
+ sp_len = ip;
+ } else {
+ sp_len = ip - 1;
+ }
+ spiro_seg *s = NULL;
+ //for (int j = 0; j <= sp_len; j ++) printf ("%c\n", path[j].ty);
+ s = run_spiro(path, sp_len);
+ spiro_to_bpath(s, sp_len, bc);
+ free(s);
+ path[0].x = path[ip].x;
+ path[0].y = path[ip].y;
+ ip = 0;
+ }
+ if (bpath[ib].code == NR_MOVETO_OPEN) {
+ closed = false;
+ path[ip].ty = '{';
+ } else {
+ closed = true;
+ if (ib < len)
+ first_in_subpath = &(bpath[ib + 1]);
+ path[ip].ty = 'c';
+ }
+ } else {
+ // this point is not last, so makes sense to find a proper type for it
+ NArtBpath *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;
+ } else {
+ if (ib < len)
+ next = &(bpath[ib+1]);
+ else if (closed)
+ 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;
+ if (this_is_line) {
+ this_angle = atan2 (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;
+ if (next_is_line) {
+ next_angle = atan2 (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) {
+ if (this_is_line && !next_is_line) {
+ path[ip].ty = ']';
+ } else if (next_is_line && !this_is_line) {
+ path[ip].ty = '[';
+ } else {
+ path[ip].ty = 'c';
+ }
+ } else {
+ path[ip].ty = 'v';
+
+ }
+ if (closed && next == first_in_subpath) {
+ path[0].ty = path[ip].ty;
+ }
+ }
+ }
+ pt = NR::Point(bpath[ib].x3, bpath[ib].y3);
+ ip++;
+ ib++;
+ }
+ g_free (path);
+}
+
+}; //namespace LivePathEffect
+}; /* namespace Inkscape */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :