Code

struct SPCurve => class SPCurve
[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>
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 *bpath = csrc->_bpath;
103     int ib = 0;
104     int ip = 0;
105     bool closed = false;
106     NR::Point pt(0, 0);
107     NArtBpath *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 *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)) < 0.001);
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)) < 0.001);
156                     double this_angle = NR_HUGE;
157                     if (this_is_line) {
158                         this_angle = atan2 (bpath[ib].x3 - pt[NR::X], bpath[ib].y3 - pt[NR::Y]);
159                     } else if (bpath[ib].code == NR_CURVETO) {
160                         this_angle = atan2 (bpath[ib].x3 - bpath[ib].x2, bpath[ib].y3 - bpath[ib].y2);
161                     }
162                     double next_angle = NR_HUGE;
163                     if (next_is_line) {
164                         next_angle = atan2 (next->x3 - bpath[ib].x3, next->y3 - bpath[ib].y3);
165                     } else if (next->code == NR_CURVETO) {
166                         next_angle = atan2 (next->x1 - bpath[ib].x3, next->y1 - bpath[ib].y3);
167                     }
168                     if (this_angle != NR_HUGE && next_angle != NR_HUGE && fabs(this_angle - next_angle) < 0.001) {
169                         if (this_is_line && !next_is_line) {
170                             path[ip].ty = ']';
171                         } else if (next_is_line && !this_is_line) {
172                             path[ip].ty = '[';
173                         } else {
174                             path[ip].ty = 'c';
175                         }
176                     } else {
177                         path[ip].ty = 'v';
179                     }
180                     if (closed && next == first_in_subpath) {
181                         path[0].ty = path[ip].ty;
182                     }
183                 }
184         }
185         pt  = NR::Point(bpath[ib].x3, bpath[ib].y3);
186         ip++;
187         ib++;
188     }
189     g_free (path);
192 }; //namespace LivePathEffect
193 }; /* namespace Inkscape */
195 /*
196   Local Variables:
197   mode:c++
198   c-file-style:"stroustrup"
199   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
200   indent-tabs-mode:nil
201   fill-column:99
202   End:
203 */
204 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :