1 #define INKSCAPE_LPE_SPIRO_C
3 /*
4 * Released under GNU GPL, read the file 'COPYING' for more information
5 */
7 #include "live_effects/lpe-spiro.h"
8 #include "display/curve.h"
9 #include <libnr/n-art-bpath.h>
10 #include "nodepath.h"
12 #include "live_effects/bezctx.h"
13 #include "live_effects/bezctx_intf.h"
14 #include "live_effects/spiro.h"
16 typedef struct {
17 bezctx base;
18 SPCurve *curve;
19 int is_open;
20 } bezctx_ink;
22 void bezctx_ink_moveto(bezctx *bc, double x, double y, int /*is_open*/)
23 {
24 bezctx_ink *bi = (bezctx_ink *) bc;
25 bi->curve->moveto(x, y);
26 }
28 void bezctx_ink_lineto(bezctx *bc, double x, double y)
29 {
30 bezctx_ink *bi = (bezctx_ink *) bc;
31 bi->curve->lineto(x, y);
32 }
34 void bezctx_ink_quadto(bezctx *bc, double xm, double ym, double x3, double y3)
35 {
36 bezctx_ink *bi = (bezctx_ink *) bc;
38 double x0, y0;
39 double x1, y1;
40 double x2, y2;
42 NR::Point last = bi->curve->last_point();
43 x0 = last[NR::X];
44 y0 = last[NR::Y];
45 x1 = xm + (1./3) * (x0 - xm);
46 y1 = ym + (1./3) * (y0 - ym);
47 x2 = xm + (1./3) * (x3 - xm);
48 y2 = ym + (1./3) * (y3 - ym);
50 bi->curve->curveto(x1, y1, x2, y2, x3, y3);
51 }
53 void bezctx_ink_curveto(bezctx *bc, double x1, double y1, double x2, double y2,
54 double x3, double y3)
55 {
56 bezctx_ink *bi = (bezctx_ink *) bc;
57 bi->curve->curveto(x1, y1, x2, y2, x3, y3);
58 }
60 bezctx *
61 new_bezctx_ink(SPCurve *curve) {
62 bezctx_ink *result = g_new(bezctx_ink, 1);
63 result->base.moveto = bezctx_ink_moveto;
64 result->base.lineto = bezctx_ink_lineto;
65 result->base.quadto = bezctx_ink_quadto;
66 result->base.curveto = bezctx_ink_curveto;
67 result->base.mark_knot = NULL;
68 result->curve = curve;
69 return &result->base;
70 }
75 namespace Inkscape {
76 namespace LivePathEffect {
78 LPESpiro::LPESpiro(LivePathEffectObject *lpeobject) :
79 Effect(lpeobject)
80 {
81 }
83 LPESpiro::~LPESpiro()
84 {
85 }
87 void
88 LPESpiro::setup_nodepath(Inkscape::NodePath::Path *np)
89 {
90 sp_nodepath_show_handles(np, false);
91 // sp_nodepath_show_helperpath(np, false);
92 }
94 void
95 LPESpiro::doEffect(SPCurve * curve)
96 {
97 SPCurve *csrc = curve->copy();
98 curve->reset();
99 bezctx *bc = new_bezctx_ink(curve);
100 int len = SP_CURVE_LENGTH(csrc);
101 spiro_cp *path = g_new (spiro_cp, len + 1);
102 NArtBpath const *bpath = csrc->get_bpath();
103 int ib = 0;
104 int ip = 0;
105 bool closed = false;
106 NR::Point pt(0, 0);
107 NArtBpath const *first_in_subpath = NULL;
108 while(ib <= len) {
109 path [ip].x = bpath[ib].x3;
110 path [ip].y = bpath[ib].y3;
111 // std::cout << "==" << bpath[ib].code << " ip" << ip << " ib" << ib << "\n";
112 if (bpath[ib].code == NR_END || bpath[ib].code == NR_MOVETO_OPEN || bpath[ib].code == NR_MOVETO) {
113 if (ip != 0) { // run prev subpath
114 int sp_len = 0;
115 if (!closed) {
116 path[ip - 1].ty = '}';
117 sp_len = ip;
118 } else {
119 sp_len = ip - 1;
120 }
121 spiro_seg *s = NULL;
122 //for (int j = 0; j <= sp_len; j ++) printf ("%c\n", path[j].ty);
123 s = run_spiro(path, sp_len);
124 spiro_to_bpath(s, sp_len, bc);
125 free(s);
126 path[0].x = path[ip].x;
127 path[0].y = path[ip].y;
128 ip = 0;
129 }
130 if (bpath[ib].code == NR_MOVETO_OPEN) {
131 closed = false;
132 path[ip].ty = '{';
133 } else {
134 closed = true;
135 if (ib < len)
136 first_in_subpath = &(bpath[ib + 1]);
137 path[ip].ty = 'c';
138 }
139 } else {
140 // this point is not last, so makes sense to find a proper type for it
141 NArtBpath const *next = NULL;
142 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
143 if (closed)
144 next = first_in_subpath;
145 } else {
146 if (ib < len)
147 next = &(bpath[ib+1]);
148 else if (closed)
149 next = first_in_subpath;
150 }
151 if (next) {
152 bool this_is_line = bpath[ib].code == NR_LINETO ||
153 (NR::L2(NR::Point(bpath[ib].x3, bpath[ib].y3) - NR::Point(bpath[ib].x2, bpath[ib].y2)) < 1e-6);
154 bool next_is_line = next->code == NR_LINETO ||
155 (NR::L2(NR::Point(bpath[ib].x3, bpath[ib].y3) - NR::Point(next->x1, next->y1)) < 1e-6);
156 NR::Point this_angle (0, 0);
157 if (this_is_line) {
158 this_angle = NR::Point (bpath[ib].x3 - pt[NR::X], bpath[ib].y3 - pt[NR::Y]);
159 } else if (bpath[ib].code == NR_CURVETO) {
160 this_angle = NR::Point (bpath[ib].x3 - bpath[ib].x2, bpath[ib].y3 - bpath[ib].y2);
161 }
162 NR::Point next_angle (0, 0);
163 if (next_is_line) {
164 next_angle = NR::Point (next->x3 - bpath[ib].x3, next->y3 - bpath[ib].y3);
165 } else if (next->code == NR_CURVETO) {
166 next_angle = NR::Point (next->x1 - bpath[ib].x3, next->y1 - bpath[ib].y3);
167 }
168 double this_angle_L2 = NR::L2(this_angle);
169 double next_angle_L2 = NR::L2(next_angle);
170 double both_angles_L2 = NR::L2(this_angle + next_angle);
171 if (this_angle_L2 > 1e-6 &&
172 next_angle_L2 > 1e-6 &&
173 this_angle_L2 + next_angle_L2 - both_angles_L2 < 1e-3) {
174 if (this_is_line && !next_is_line) {
175 path[ip].ty = ']';
176 } else if (next_is_line && !this_is_line) {
177 path[ip].ty = '[';
178 } else {
179 path[ip].ty = 'c';
180 }
181 } else {
182 path[ip].ty = 'v';
184 }
185 if (closed && next == first_in_subpath) {
186 path[0].ty = path[ip].ty;
187 }
188 }
189 }
190 pt = NR::Point(bpath[ib].x3, bpath[ib].y3);
191 ip++;
192 ib++;
193 }
194 g_free (path);
195 }
197 }; //namespace LivePathEffect
198 }; /* namespace Inkscape */
200 /*
201 Local Variables:
202 mode:c++
203 c-file-style:"stroustrup"
204 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
205 indent-tabs-mode:nil
206 fill-column:99
207 End:
208 */
209 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :