Code

0925becbb55d6dde15287b91df1d68394b2149be
[inkscape.git] / src / live_effects / lpe-spiro.cpp
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>
11 #include "live_effects/bezctx.h"
12 #include "live_effects/bezctx_intf.h"
13 #include "live_effects/spiro.h"
15 typedef struct {
16     bezctx base;
17     SPCurve *curve;
18     int is_open;
19 } bezctx_ink;
21 void bezctx_ink_moveto(bezctx *bc, double x, double y, int is_open)
22 {
23     bezctx_ink *bi = (bezctx_ink *) bc;
24     sp_curve_moveto(bi->curve, x, y);
25 }
27 void bezctx_ink_lineto(bezctx *bc, double x, double y)
28 {
29     bezctx_ink *bi = (bezctx_ink *) bc;
30     sp_curve_lineto(bi->curve, x, y);
31 }
33 void bezctx_ink_quadto(bezctx *bc, double xm, double ym, double x3, double y3)
34 {
35     bezctx_ink *bi = (bezctx_ink *) bc;
37     double x0, y0;
38     double x1, y1;
39     double x2, y2;
41     NR::Point last = sp_curve_last_point(bi->curve);
42     x0 = last[NR::X];
43     y0 = last[NR::Y];
44     x1 = xm + (1./3) * (x0 - xm);
45     y1 = ym + (1./3) * (y0 - ym);
46     x2 = xm + (1./3) * (x3 - xm);
47     y2 = ym + (1./3) * (y3 - ym);
49     sp_curve_curveto(bi->curve, x1, y1, x2, y2, x3, y3);
50 }
52 void bezctx_ink_curveto(bezctx *bc, double x1, double y1, double x2, double y2,
53                     double x3, double y3)
54 {
55     bezctx_ink *bi = (bezctx_ink *) bc;
56     sp_curve_curveto(bi->curve, x1, y1, x2, y2, x3, y3);
57 }
59 bezctx *
60 new_bezctx_ink(SPCurve *curve) {
61     bezctx_ink *result = g_new(bezctx_ink, 1);
62     result->base.moveto = bezctx_ink_moveto;
63     result->base.lineto = bezctx_ink_lineto;
64     result->base.quadto = bezctx_ink_quadto;
65     result->base.curveto = bezctx_ink_curveto;
66     result->base.mark_knot = NULL;
67     result->curve = curve;
68     return &result->base;
69 }
74 namespace Inkscape {
75 namespace LivePathEffect {
77 LPESpiro::LPESpiro(LivePathEffectObject *lpeobject) :
78     Effect(lpeobject)
79 {
80 }
82 LPESpiro::~LPESpiro()
83 {
84 }
86 void
87 LPESpiro::setup_nodepath(Inkscape::NodePath::Path *np)
88 {
89
91 void
92 LPESpiro::doEffect(SPCurve * curve)
93 {
94     SPCurve *csrc = sp_curve_copy(curve);
95     sp_curve_reset(curve);
96     bezctx *bc = new_bezctx_ink(curve);
97     int len = SP_CURVE_LENGTH(csrc);
98     spiro_cp *path = g_new (spiro_cp, len + 1);
99     NArtBpath *bpath = csrc->_bpath;
100     int ib = 0;
101     int ip = 0;
102     bool closed = false;
103     NR::Point pt(0, 0);
104     NArtBpath *first_in_subpath = NULL;
105     while(ib <= len) {
106         path [ip].x = bpath[ib].x3;
107         path [ip].y = bpath[ib].y3;
108         // std::cout << "==" << bpath[ib].code << "   ip" << ip << "  ib" << ib << "\n";
109         if (bpath[ib].code == NR_END || bpath[ib].code == NR_MOVETO_OPEN || bpath[ib].code == NR_MOVETO) {
110             if (ip != 0) { // run prev subpath
111                 int sp_len = 0;
112                 if (!closed) {
113                      path[ip - 1].ty = '}';
114                     sp_len = ip;
115                 } else {
116                     sp_len = ip - 1;
117                 }
118                 spiro_seg *s = NULL;
119                 //for (int j = 0; j <= sp_len; j ++) printf ("%c\n", path[j].ty);
120                 s = run_spiro(path, sp_len);
121                 spiro_to_bpath(s, sp_len, bc);
122                 free(s);
123                 path[0].x = path[ip].x;
124                 path[0].y = path[ip].y;
125                 ip = 0;
126             }
127             if (bpath[ib].code == NR_MOVETO_OPEN) {
128                 closed = false;
129                 path[ip].ty = '{';
130             } else {
131                 closed = true;
132                 if (ib  < len)
133                     first_in_subpath = &(bpath[ib + 1]);
134                 path[ip].ty = 'c';
135             }
136         } else {
137                 // this point is not last, so makes sense to find a proper type for it
138                 NArtBpath *next = NULL;
139                 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
140                     if (closed) 
141                         next = first_in_subpath;
142                 } else {
143                     if (ib < len)
144                         next = &(bpath[ib+1]);
145                     else if (closed)
146                         next = first_in_subpath;
147                 }
148                 if (next) {
149                     bool this_is_line = bpath[ib].code == NR_LINETO || 
150                         (NR::L2(NR::Point(bpath[ib].x3, bpath[ib].y3) - NR::Point(bpath[ib].x2, bpath[ib].y2)) < 0.001);
151                     bool next_is_line = next->code == NR_LINETO || 
152                         (NR::L2(NR::Point(bpath[ib].x3, bpath[ib].y3) - NR::Point(next->x1, next->y1)) < 0.001);
153                     double this_angle = NR_HUGE;
154                     if (this_is_line) {
155                         this_angle = atan2 (bpath[ib].x3 - pt[NR::X], bpath[ib].y3 - pt[NR::Y]);
156                     } else if (bpath[ib].code == NR_CURVETO) {
157                         this_angle = atan2 (bpath[ib].x3 - bpath[ib].x2, bpath[ib].y3 - bpath[ib].y2);
158                     } 
159                     double next_angle = NR_HUGE;
160                     if (next_is_line) {
161                         next_angle = atan2 (next->x3 - bpath[ib].x3, next->y3 - bpath[ib].y3);
162                     } else if (next->code == NR_CURVETO) {
163                         next_angle = atan2 (next->x1 - bpath[ib].x3, next->y1 - bpath[ib].y3);
164                     } 
165                     if (this_angle != NR_HUGE && next_angle != NR_HUGE && fabs(this_angle - next_angle) < 0.001) {
166                         if (this_is_line && !next_is_line) {
167                             path[ip].ty = ']';
168                         } else if (next_is_line && !this_is_line) {
169                             path[ip].ty = '[';
170                         } else {
171                             path[ip].ty = 'c';
172                         }
173                     } else {
174                         path[ip].ty = 'v';
176                     }
177                     if (closed && next == first_in_subpath) {
178                         path[0].ty = path[ip].ty;
179                     }
180                 }
181         }
182         pt  = NR::Point(bpath[ib].x3, bpath[ib].y3);
183         ip++;
184         ib++;
185     }
186     g_free (path);
189 }; //namespace LivePathEffect
190 }; /* namespace Inkscape */
192 /*
193   Local Variables:
194   mode:c++
195   c-file-style:"stroustrup"
196   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
197   indent-tabs-mode:nil
198   fill-column:99
199   End:
200 */
201 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :