diff options
Diffstat (limited to 'src/live_effects/lpe-spiro.cpp')
| -rw-r--r-- | src/live_effects/lpe-spiro.cpp | 196 |
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 : |
