1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /** \file
3  * LPE <lattice> implementation
4 
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 v2+, read the file 'COPYING' for more information.
16  */
17 
18 #include "live_effects/lpe-lattice.h"
19 
20 #include "display/curve.h"
21 
22 #include <2geom/sbasis-2d.h>
23 #include <2geom/bezier-to-sbasis.h>
24 // TODO due to internal breakage in glibmm headers, this must be last:
25 #include <glibmm/i18n.h>
26 using namespace Geom;
27 
28 namespace Inkscape {
29 namespace LivePathEffect {
30 
LPELattice(LivePathEffectObject * lpeobject)31 LPELattice::LPELattice(LivePathEffectObject *lpeobject) :
32     Effect(lpeobject),
33 
34     // initialise your parameters here:
35     grid_point0(_("Control handle 0:"), _("Control handle 0"), "gridpoint0", &wr, this),
36     grid_point1(_("Control handle 1:"), _("Control handle 1"), "gridpoint1", &wr, this),
37     grid_point2(_("Control handle 2:"), _("Control handle 2"), "gridpoint2", &wr, this),
38     grid_point3(_("Control handle 3:"), _("Control handle 3"), "gridpoint3", &wr, this),
39     grid_point4(_("Control handle 4:"), _("Control handle 4"), "gridpoint4", &wr, this),
40     grid_point5(_("Control handle 5:"), _("Control handle 5"), "gridpoint5", &wr, this),
41     grid_point6(_("Control handle 6:"), _("Control handle 6"), "gridpoint6", &wr, this),
42     grid_point7(_("Control handle 7:"), _("Control handle 7"), "gridpoint7", &wr, this),
43     grid_point8(_("Control handle 8:"), _("Control handle 8"), "gridpoint8", &wr, this),
44     grid_point9(_("Control handle 9:"), _("Control handle 9"), "gridpoint9", &wr, this),
45     grid_point10(_("Control handle 10:"), _("Control handle 10"), "gridpoint10", &wr, this),
46     grid_point11(_("Control handle 11:"), _("Control handle 11"), "gridpoint11", &wr, this),
47     grid_point12(_("Control handle 12:"), _("Control handle 12"), "gridpoint12", &wr, this),
48     grid_point13(_("Control handle 13:"), _("Control handle 13"), "gridpoint13", &wr, this),
49     grid_point14(_("Control handle 14:"), _("Control handle 14"), "gridpoint14", &wr, this),
50     grid_point15(_("Control handle 15:"), _("Control handle 15"), "gridpoint15", &wr, this)
51 
52 {
53     // register all your parameters here, so Inkscape knows which parameters this effect has:
54     registerParameter(&grid_point0);
55     registerParameter(&grid_point1);
56     registerParameter(&grid_point2);
57     registerParameter(&grid_point3);
58     registerParameter(&grid_point4);
59     registerParameter(&grid_point5);
60     registerParameter(&grid_point6);
61     registerParameter(&grid_point7);
62     registerParameter(&grid_point8);
63     registerParameter(&grid_point9);
64     registerParameter(&grid_point10);
65     registerParameter(&grid_point11);
66     registerParameter(&grid_point12);
67     registerParameter(&grid_point13);
68     registerParameter(&grid_point14);
69     registerParameter(&grid_point15);
70 
71     apply_to_clippath_and_mask = true;
72 }
73 
74 LPELattice::~LPELattice()
75 = default;
76 
77 
78 Geom::Piecewise<Geom::D2<Geom::SBasis> >
doEffect_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis>> const & pwd2_in)79 LPELattice::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
80 {
81     D2<SBasis2d> sb2;
82 
83     //Initialisation of the sb2
84     for(unsigned dim = 0; dim < 2; dim++) {
85         sb2[dim].us = 2;
86         sb2[dim].vs = 2;
87         const int depth = sb2[dim].us*sb2[dim].vs;
88         sb2[dim].resize(depth, Linear2d(0));
89     }
90 
91     //Grouping the point params in a convenient vector
92     std::vector<Geom::Point *> handles(16);
93 
94     handles[0] = &grid_point0;
95     handles[1] = &grid_point1;
96     handles[2] = &grid_point2;
97     handles[3] = &grid_point3;
98     handles[4] = &grid_point4;
99     handles[5] = &grid_point5;
100     handles[6] = &grid_point6;
101     handles[7] = &grid_point7;
102     handles[8] = &grid_point8;
103     handles[9] = &grid_point9;
104     handles[10] = &grid_point10;
105     handles[11] = &grid_point11;
106     handles[12] = &grid_point12;
107     handles[13] = &grid_point13;
108     handles[14] = &grid_point14;
109     handles[15] = &grid_point15;
110 
111     Geom::Point origin = Geom::Point(boundingbox_X.min(),boundingbox_Y.min());
112 
113     double width = boundingbox_X.extent();
114     double height = boundingbox_Y.extent();
115 
116     //numbering is based on 4 rectangles.
117     for(unsigned dim = 0; dim < 2; dim++) {
118         Geom::Point dir(0,0);
119         dir[dim] = 1;
120         for(unsigned vi = 0; vi < sb2[dim].vs; vi++) {
121             for(unsigned ui = 0; ui < sb2[dim].us; ui++) {
122                 for(unsigned iv = 0; iv < 2; iv++) {
123                     for(unsigned iu = 0; iu < 2; iu++) {
124                         unsigned corner = iu + 2*iv;
125                         unsigned i = ui + vi*sb2[dim].us;
126 
127                         //This is the offset from the Upperleft point
128                         Geom::Point base(   (ui + iu*(3-2*ui))*width/3.,
129                                             (vi + iv*(3-2*vi))*height/3.);
130 
131                         //Special action for corners
132                         if(vi == 0 && ui == 0) {
133                             base = Geom::Point(0,0);
134                         }
135 
136                         // i = Upperleft corner of the considerated rectangle
137                         // corner = actual corner of the rectangle
138                         // origin = Upperleft point
139                         double dl = dot((*handles[corner+4*i] - (base + origin)), dir)/dot(dir,dir);
140                         sb2[dim][i][corner] = dl/( dim ? height : width )*pow(4.0,ui+vi);
141                     }
142                 }
143             }
144         }
145     }
146 
147     Piecewise<D2<SBasis> >  output;
148     output.push_cut(0.);
149     for(unsigned i = 0; i < pwd2_in.size(); i++) {
150         D2<SBasis> B = pwd2_in[i];
151         B -= origin;
152         B*= 1/width;
153         //Here comes the magic
154         D2<SBasis> tB = compose_each(sb2,B);
155         tB = tB * width + origin;
156 
157         output.push(tB,i+1);
158     }
159 
160     return output;
161 }
162 
163 void
doBeforeEffect(SPLPEItem const * lpeitem)164 LPELattice::doBeforeEffect (SPLPEItem const* lpeitem)
165 {
166     original_bbox(lpeitem, false, true);
167 }
168 
169 void
resetDefaults(SPItem const * item)170 LPELattice::resetDefaults(SPItem const* item)
171 {
172     Effect::resetDefaults(item);
173 
174     original_bbox(SP_LPE_ITEM(item), false, true);
175 
176     // place the 16 control points
177     grid_point0[Geom::X] = boundingbox_X.min();
178     grid_point0[Geom::Y] = boundingbox_Y.min();
179 
180     grid_point1[Geom::X] = boundingbox_X.max();
181     grid_point1[Geom::Y] = boundingbox_Y.min();
182 
183     grid_point2[Geom::X] = boundingbox_X.min();
184     grid_point2[Geom::Y] = boundingbox_Y.max();
185 
186     grid_point3[Geom::X] = boundingbox_X.max();
187     grid_point3[Geom::Y] = boundingbox_Y.max();
188 
189     grid_point4[Geom::X] = 1.0/3*boundingbox_X.max()+2.0/3*boundingbox_X.min();
190     grid_point4[Geom::Y] = boundingbox_Y.min();
191 
192     grid_point5[Geom::X] = 2.0/3*boundingbox_X.max()+1.0/3*boundingbox_X.min();
193     grid_point5[Geom::Y] = boundingbox_Y.min();
194 
195     grid_point6[Geom::X] = 1.0/3*boundingbox_X.max()+2.0/3*boundingbox_X.min();
196     grid_point6[Geom::Y] = boundingbox_Y.max();
197 
198     grid_point7[Geom::X] = 2.0/3*boundingbox_X.max()+1.0/3*boundingbox_X.min();
199     grid_point7[Geom::Y] = boundingbox_Y.max();
200 
201     grid_point8[Geom::X] = boundingbox_X.min();
202     grid_point8[Geom::Y] = 1.0/3*boundingbox_Y.max()+2.0/3*boundingbox_Y.min();
203 
204     grid_point9[Geom::X] = boundingbox_X.max();
205     grid_point9[Geom::Y] = 1.0/3*boundingbox_Y.max()+2.0/3*boundingbox_Y.min();
206 
207     grid_point10[Geom::X] = boundingbox_X.min();
208     grid_point10[Geom::Y] = 2.0/3*boundingbox_Y.max()+1.0/3*boundingbox_Y.min();
209 
210     grid_point11[Geom::X] = boundingbox_X.max();
211     grid_point11[Geom::Y] = 2.0/3*boundingbox_Y.max()+1.0/3*boundingbox_Y.min();
212 
213     grid_point12[Geom::X] = 1.0/3*boundingbox_X.max()+2.0/3*boundingbox_X.min();
214     grid_point12[Geom::Y] = 1.0/3*boundingbox_Y.max()+2.0/3*boundingbox_Y.min();
215 
216     grid_point13[Geom::X] = 2.0/3*boundingbox_X.max()+1.0/3*boundingbox_X.min();
217     grid_point13[Geom::Y] = 1.0/3*boundingbox_Y.max()+2.0/3*boundingbox_Y.min();
218 
219     grid_point14[Geom::X] = 1.0/3*boundingbox_X.max()+2.0/3*boundingbox_X.min();
220     grid_point14[Geom::Y] = 2.0/3*boundingbox_Y.max()+1.0/3*boundingbox_Y.min();
221 
222     grid_point15[Geom::X] = 2.0/3*boundingbox_X.max()+1.0/3*boundingbox_X.min();
223     grid_point15[Geom::Y] = 2.0/3*boundingbox_Y.max()+1.0/3*boundingbox_Y.min();
224     grid_point1.param_update_default(grid_point1);
225     grid_point2.param_update_default(grid_point2);
226     grid_point3.param_update_default(grid_point3);
227     grid_point4.param_update_default(grid_point4);
228     grid_point5.param_update_default(grid_point5);
229     grid_point6.param_update_default(grid_point6);
230     grid_point7.param_update_default(grid_point7);
231     grid_point8.param_update_default(grid_point8);
232     grid_point9.param_update_default(grid_point9);
233     grid_point10.param_update_default(grid_point10);
234     grid_point11.param_update_default(grid_point11);
235     grid_point12.param_update_default(grid_point12);
236     grid_point13.param_update_default(grid_point13);
237     grid_point14.param_update_default(grid_point14);
238     grid_point15.param_update_default(grid_point15);
239 }
240 
241 /**
242 void
243 LPELattice::addHelperPathsImpl(SPLPEItem *lpeitem, SPDesktop *desktop)
244 {
245     SPCurve *c = new SPCurve ();
246     c->moveto(grid_point0);
247     c->lineto(grid_point4);
248     c->lineto(grid_point5);
249     c->lineto(grid_point1);
250 
251     c->moveto(grid_point8);
252     c->lineto(grid_point12);
253     c->lineto(grid_point13);
254     c->lineto(grid_point9);
255 
256     c->moveto(grid_point10);
257     c->lineto(grid_point14);
258     c->lineto(grid_point15);
259     c->lineto(grid_point11);
260 
261     c->moveto(grid_point2);
262     c->lineto(grid_point6);
263     c->lineto(grid_point7);
264     c->lineto(grid_point3);
265 
266 
267     c->moveto(grid_point0);
268     c->lineto(grid_point8);
269     c->lineto(grid_point10);
270     c->lineto(grid_point2);
271 
272     c->moveto(grid_point4);
273     c->lineto(grid_point12);
274     c->lineto(grid_point14);
275     c->lineto(grid_point6);
276 
277     c->moveto(grid_point5);
278     c->lineto(grid_point13);
279     c->lineto(grid_point15);
280     c->lineto(grid_point7);
281 
282     c->moveto(grid_point1);
283     c->lineto(grid_point9);
284     c->lineto(grid_point11);
285     c->lineto(grid_point3);
286 
287     // TODO: factor this out (and remove the #include of desktop.h above)
288     SPCanvasItem *canvasitem = sp_nodepath_generate_helperpath(desktop, c, lpeitem, 0x009000ff);
289     Inkscape::Display::TemporaryItem* tmpitem = desktop->add_temporary_canvasitem (canvasitem, 0);
290     lpeitem->lpe_helperpaths.push_back(tmpitem);
291 
292     c->unref();
293 }
294 **/
295 
296 /* ######################## */
297 
298 } //namespace LivePathEffect
299 } /* namespace Inkscape */
300 
301 /*
302   Local Variables:
303   mode:c++
304   c-file-style:"stroustrup"
305   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
306   indent-tabs-mode:nil
307   fill-column:99
308   End:
309 */
310 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
311