1 #define INKSCAPE_LPE_LATTICE_CPP
2 /** \file
3 * LPE <lattice> implementation
5 */
6 /*
7 * Authors:
8 * Johan Engelen <j.b.c.engelen@utwente.nl>
9 * Steren Giannini
10 * NoƩ Falzon
11 * Victor Navez
12 *
13 * Copyright (C) 2007-2008 Authors
14 *
15 * Released under GNU GPL, read the file 'COPYING' for more information
16 */
18 #include "live_effects/lpe-lattice.h"
20 #include "sp-shape.h"
21 #include "sp-item.h"
22 #include "sp-path.h"
23 #include "display/curve.h"
24 #include "libnr/n-art-bpath-2geom.h"
25 #include "svg/svg.h"
26 #include "nodepath.h"
28 #include <2geom/sbasis.h>
29 #include <2geom/sbasis-2d.h>
30 #include <2geom/sbasis-geometric.h>
31 #include <2geom/bezier-to-sbasis.h>
32 #include <2geom/sbasis-to-bezier.h>
33 #include <2geom/d2.h>
34 #include <2geom/piecewise.h>
35 #include <2geom/transforms.h>
37 #include "desktop.h" // TODO: should be factored out (see below)
39 using namespace Geom;
41 namespace Inkscape {
42 namespace LivePathEffect {
44 LPELattice::LPELattice(LivePathEffectObject *lpeobject) :
45 Effect(lpeobject),
47 // initialise your parameters here:
48 grid_point0(_("Control handle 0"), _("Control handle 0"), "gridpoint0", &wr, this),
49 grid_point1(_("Control handle 1"), _("Control handle 1"), "gridpoint1", &wr, this),
50 grid_point2(_("Control handle 2"), _("Control handle 2"), "gridpoint2", &wr, this),
51 grid_point3(_("Control handle 3"), _("Control handle 3"), "gridpoint3", &wr, this),
52 grid_point4(_("Control handle 4"), _("Control handle 4"), "gridpoint4", &wr, this),
53 grid_point5(_("Control handle 5"), _("Control handle 5"), "gridpoint5", &wr, this),
54 grid_point6(_("Control handle 6"), _("Control handle 6"), "gridpoint6", &wr, this),
55 grid_point7(_("Control handle 7"), _("Control handle 7"), "gridpoint7", &wr, this),
56 grid_point8(_("Control handle 8"), _("Control handle 8"), "gridpoint8", &wr, this),
57 grid_point9(_("Control handle 9"), _("Control handle 9"), "gridpoint9", &wr, this),
58 grid_point10(_("Control handle 10"), _("Control handle 10"), "gridpoint10", &wr, this),
59 grid_point11(_("Control handle 11"), _("Control handle 11"), "gridpoint11", &wr, this),
60 grid_point12(_("Control handle 12"), _("Control handle 12"), "gridpoint12", &wr, this),
61 grid_point13(_("Control handle 13"), _("Control handle 13"), "gridpoint13", &wr, this),
62 grid_point14(_("Control handle 14"), _("Control handle 14"), "gridpoint14", &wr, this),
63 grid_point15(_("Control handle 15"), _("Control handle 15"), "gridpoint15", &wr, this)
65 {
66 // register all your parameters here, so Inkscape knows which parameters this effect has:
67 registerParameter( dynamic_cast<Parameter *>(&grid_point0) );
68 registerParameter( dynamic_cast<Parameter *>(&grid_point1) );
69 registerParameter( dynamic_cast<Parameter *>(&grid_point2) );
70 registerParameter( dynamic_cast<Parameter *>(&grid_point3) );
71 registerParameter( dynamic_cast<Parameter *>(&grid_point4) );
72 registerParameter( dynamic_cast<Parameter *>(&grid_point5) );
73 registerParameter( dynamic_cast<Parameter *>(&grid_point6) );
74 registerParameter( dynamic_cast<Parameter *>(&grid_point7) );
75 registerParameter( dynamic_cast<Parameter *>(&grid_point8) );
76 registerParameter( dynamic_cast<Parameter *>(&grid_point9) );
77 registerParameter( dynamic_cast<Parameter *>(&grid_point10) );
78 registerParameter( dynamic_cast<Parameter *>(&grid_point11) );
79 registerParameter( dynamic_cast<Parameter *>(&grid_point12) );
80 registerParameter( dynamic_cast<Parameter *>(&grid_point13) );
81 registerParameter( dynamic_cast<Parameter *>(&grid_point14) );
82 registerParameter( dynamic_cast<Parameter *>(&grid_point15) );
85 }
87 LPELattice::~LPELattice()
88 {
90 }
93 Geom::Piecewise<Geom::D2<Geom::SBasis> >
94 LPELattice::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
95 {
96 D2<SBasis2d> sb2;
98 //Initialisation of the sb2
99 for(unsigned dim = 0; dim < 2; dim++) {
100 sb2[dim].us = 2;
101 sb2[dim].vs = 2;
102 const int depth = sb2[dim].us*sb2[dim].vs;
103 sb2[dim].resize(depth, Linear2d(0));
104 }
106 //Grouping the point params in a convenient vector
107 std::vector<Geom::Point *> handles(16);
109 handles[0] = &grid_point0;
110 handles[1] = &grid_point1;
111 handles[2] = &grid_point2;
112 handles[3] = &grid_point3;
113 handles[4] = &grid_point4;
114 handles[5] = &grid_point5;
115 handles[6] = &grid_point6;
116 handles[7] = &grid_point7;
117 handles[8] = &grid_point8;
118 handles[9] = &grid_point9;
119 handles[10] = &grid_point10;
120 handles[11] = &grid_point11;
121 handles[12] = &grid_point12;
122 handles[13] = &grid_point13;
123 handles[14] = &grid_point14;
124 handles[15] = &grid_point15;
126 Geom::Point origin = Geom::Point(boundingbox_X.min(),boundingbox_Y.min());
128 double width = boundingbox_X.extent();
129 double height = boundingbox_Y.extent();
131 //numbering is based on 4 rectangles.
132 for(unsigned dim = 0; dim < 2; dim++) {
133 Geom::Point dir(0,0);
134 dir[dim] = 1;
135 for(unsigned vi = 0; vi < sb2[dim].vs; vi++) {
136 for(unsigned ui = 0; ui < sb2[dim].us; ui++) {
137 for(unsigned iv = 0; iv < 2; iv++) {
138 for(unsigned iu = 0; iu < 2; iu++) {
139 unsigned corner = iu + 2*iv;
140 unsigned i = ui + vi*sb2[dim].us;
142 //This is the offset from the Upperleft point
143 Geom::Point base( (ui + iu*(3-2*ui))*width/3.,
144 (vi + iv*(3-2*vi))*height/3.);
146 //Special action for corners
147 if(vi == 0 && ui == 0) {
148 base = Geom::Point(0,0);
149 }
151 // i = Upperleft corner of the considerated rectangle
152 // corner = actual corner of the rectangle
153 // origin = Upperleft point
154 double dl = dot((*handles[corner+4*i] - (base + origin)), dir)/dot(dir,dir);
155 sb2[dim][i][corner] = dl/( dim ? height : width )*pow(4.0,ui+vi);
156 }
157 }
158 }
159 }
160 }
162 Piecewise<D2<SBasis> > output;
163 output.push_cut(0.);
164 for(unsigned i = 0; i < pwd2_in.size(); i++) {
165 D2<SBasis> B = pwd2_in[i];
166 B -= origin;
167 B*= 1/width;
168 //Here comes the magic
169 D2<SBasis> tB = compose_each(sb2,B);
170 tB = tB * width + origin;
172 output.push(tB,i+1);
173 }
175 return output;
176 }
178 void
179 LPELattice::doBeforeEffect (SPLPEItem *lpeitem)
180 {
181 original_bbox(lpeitem);
182 }
184 void
185 LPELattice::resetDefaults(SPItem * item)
186 {
187 original_bbox(SP_LPE_ITEM(item), false);
189 // place the 16 control points
190 grid_point0[Geom::X] = boundingbox_X.min();
191 grid_point0[Geom::Y] = boundingbox_Y.min();
193 grid_point1[Geom::X] = boundingbox_X.max();
194 grid_point1[Geom::Y] = boundingbox_Y.min();
196 grid_point2[Geom::X] = boundingbox_X.min();
197 grid_point2[Geom::Y] = boundingbox_Y.max();
199 grid_point3[Geom::X] = boundingbox_X.max();
200 grid_point3[Geom::Y] = boundingbox_Y.max();
202 grid_point4[Geom::X] = 1.0/3*boundingbox_X.max()+2.0/3*boundingbox_X.min();
203 grid_point4[Geom::Y] = boundingbox_Y.min();
205 grid_point5[Geom::X] = 2.0/3*boundingbox_X.max()+1.0/3*boundingbox_X.min();
206 grid_point5[Geom::Y] = boundingbox_Y.min();
208 grid_point6[Geom::X] = 1.0/3*boundingbox_X.max()+2.0/3*boundingbox_X.min();
209 grid_point6[Geom::Y] = boundingbox_Y.max();
211 grid_point7[Geom::X] = 2.0/3*boundingbox_X.max()+1.0/3*boundingbox_X.min();
212 grid_point7[Geom::Y] = boundingbox_Y.max();
214 grid_point8[Geom::X] = boundingbox_X.min();
215 grid_point8[Geom::Y] = 1.0/3*boundingbox_Y.max()+2.0/3*boundingbox_Y.min();
217 grid_point9[Geom::X] = boundingbox_X.max();
218 grid_point9[Geom::Y] = 1.0/3*boundingbox_Y.max()+2.0/3*boundingbox_Y.min();
220 grid_point10[Geom::X] = boundingbox_X.min();
221 grid_point10[Geom::Y] = 2.0/3*boundingbox_Y.max()+1.0/3*boundingbox_Y.min();
223 grid_point11[Geom::X] = boundingbox_X.max();
224 grid_point11[Geom::Y] = 2.0/3*boundingbox_Y.max()+1.0/3*boundingbox_Y.min();
226 grid_point12[Geom::X] = 1.0/3*boundingbox_X.max()+2.0/3*boundingbox_X.min();
227 grid_point12[Geom::Y] = 1.0/3*boundingbox_Y.max()+2.0/3*boundingbox_Y.min();
229 grid_point13[Geom::X] = 2.0/3*boundingbox_X.max()+1.0/3*boundingbox_X.min();
230 grid_point13[Geom::Y] = 1.0/3*boundingbox_Y.max()+2.0/3*boundingbox_Y.min();
232 grid_point14[Geom::X] = 1.0/3*boundingbox_X.max()+2.0/3*boundingbox_X.min();
233 grid_point14[Geom::Y] = 2.0/3*boundingbox_Y.max()+1.0/3*boundingbox_Y.min();
235 grid_point15[Geom::X] = 2.0/3*boundingbox_X.max()+1.0/3*boundingbox_X.min();
236 grid_point15[Geom::Y] = 2.0/3*boundingbox_Y.max()+1.0/3*boundingbox_Y.min();
237 }
239 /**
240 void
241 LPELattice::addHelperPathsImpl(SPLPEItem *lpeitem, SPDesktop *desktop)
242 {
243 SPCurve *c = new SPCurve ();
244 c->moveto(grid_point0);
245 c->lineto(grid_point4);
246 c->lineto(grid_point5);
247 c->lineto(grid_point1);
249 c->moveto(grid_point8);
250 c->lineto(grid_point12);
251 c->lineto(grid_point13);
252 c->lineto(grid_point9);
254 c->moveto(grid_point10);
255 c->lineto(grid_point14);
256 c->lineto(grid_point15);
257 c->lineto(grid_point11);
259 c->moveto(grid_point2);
260 c->lineto(grid_point6);
261 c->lineto(grid_point7);
262 c->lineto(grid_point3);
265 c->moveto(grid_point0);
266 c->lineto(grid_point8);
267 c->lineto(grid_point10);
268 c->lineto(grid_point2);
270 c->moveto(grid_point4);
271 c->lineto(grid_point12);
272 c->lineto(grid_point14);
273 c->lineto(grid_point6);
275 c->moveto(grid_point5);
276 c->lineto(grid_point13);
277 c->lineto(grid_point15);
278 c->lineto(grid_point7);
280 c->moveto(grid_point1);
281 c->lineto(grid_point9);
282 c->lineto(grid_point11);
283 c->lineto(grid_point3);
285 // TODO: factor this out (and remove the #include of desktop.h above)
286 SPCanvasItem *canvasitem = sp_nodepath_generate_helperpath(desktop, c, SP_ITEM(lpeitem), 0x009000ff);
287 Inkscape::Display::TemporaryItem* tmpitem = desktop->add_temporary_canvasitem (canvasitem, 0);
288 lpeitem->lpe_helperpaths.push_back(tmpitem);
290 c->unref();
291 }
292 **/
294 /* ######################## */
296 } //namespace LivePathEffect
297 } /* namespace Inkscape */
299 /*
300 Local Variables:
301 mode:c++
302 c-file-style:"stroustrup"
303 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
304 indent-tabs-mode:nil
305 fill-column:99
306 End:
307 */
308 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :