Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
lpe-envelope.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) Steren Giannini 2008 <steren.giannini@gmail.com>
4 *
5 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
6 */
7
8#include "lpe-envelope.h"
9
10#include <glibmm/i18n.h>
11
12#include "display/curve.h"
13#include "object/sp-lpe-item.h"
14
15
16namespace Inkscape {
17namespace LivePathEffect {
18
20 Effect(lpeobject),
21 bend_path1(_("Top bend path:"), _("Top path along which to bend the original path"), "bendpath1", &wr, this, "M0,0 L1,0"),
22 bend_path2(_("Right bend path:"), _("Right path along which to bend the original path"), "bendpath2", &wr, this, "M0,0 L1,0"),
23 bend_path3(_("Bottom bend path:"), _("Bottom path along which to bend the original path"), "bendpath3", &wr, this, "M0,0 L1,0"),
24 bend_path4(_("Left bend path:"), _("Left path along which to bend the original path"), "bendpath4", &wr, this, "M0,0 L1,0"),
25 xx(_("_Enable left &amp; right paths"), _("Enable the left and right deformation paths"), "xx", &wr, this, true),
26 yy(_("_Enable top &amp; bottom paths"), _("Enable the top and bottom deformation paths"), "yy", &wr, this, true)
27{
36}
37
39
40bool
42{
43 if (!is_load || is_applied) {
44 return false;
45 }
50 return false;
51}
52
62
63void
65{
66 // get the item bounding box
67 original_bbox(lpeitem, false, true);
68 if (is_load) {
73 }
74
75
76}
77
80{
81
82 if(!xx.get_value() && !yy.get_value())
83 {
84 return pwd2_in;
85 }
86
87 using namespace Geom;
88
89 // Don't allow empty path parameters:
94 {
95 return pwd2_in;
96 }
97
98 /*
99 The code below is inspired from the Bend Path code developed by jfb and mgsloan
100 Please, read it before trying to understand this one
101 */
102
105 uskeleton1 = remove_short_cuts(uskeleton1,.01);
106 Piecewise<D2<SBasis> > n1 = rot90(derivative(uskeleton1));
107 n1 = force_continuity(remove_short_cuts(n1,.1));
108
110
112 uskeleton2 = remove_short_cuts(uskeleton2,.01);
113 Piecewise<D2<SBasis> > n2 = rot90(derivative(uskeleton2));
114 n2 = force_continuity(remove_short_cuts(n2,.1));
115
118 uskeleton3 = remove_short_cuts(uskeleton3,.01);
119 Piecewise<D2<SBasis> > n3 = rot90(derivative(uskeleton3));
120 n3 = force_continuity(remove_short_cuts(n3,.1));
121
124 uskeleton4 = remove_short_cuts(uskeleton4,.01);
125 Piecewise<D2<SBasis> > n4 = rot90(derivative(uskeleton4));
126 n4 = force_continuity(remove_short_cuts(n4,.1));
127
128
129 D2<Piecewise<SBasis> > patternd2 = make_cuts_independent(pwd2_in);
130 Piecewise<SBasis> x = Piecewise<SBasis>(patternd2[0]);
131 Piecewise<SBasis> y = Piecewise<SBasis>(patternd2[1]);
132
133 /*The *1.001 is a hack to avoid a small bug : path at x=0 and y=0 don't work well. */
134 x-= boundingbox_X.min()*1.001;
135 y-= boundingbox_Y.min()*1.001;
136
137 Piecewise<SBasis> x1 = x ;
138 Piecewise<SBasis> y1 = y ;
139
140 Piecewise<SBasis> x2 = x ;
141 Piecewise<SBasis> y2 = y ;
142 x2 -= boundingbox_X.extent();
143
144 Piecewise<SBasis> x3 = x ;
145 Piecewise<SBasis> y3 = y ;
146 y3 -= boundingbox_Y.extent();
147
148 Piecewise<SBasis> x4 = x ;
149 Piecewise<SBasis> y4 = y ;
150
151
152 /*Scaling to the Bend Path length*/
153 double scaling1 = uskeleton1.cuts.back()/boundingbox_X.extent();
154 if (scaling1 != 1.0) {
155 x1*=scaling1;
156 }
157
158 double scaling2 = uskeleton2.cuts.back()/boundingbox_Y.extent();
159 if (scaling2 != 1.0) {
160 y2*=scaling2;
161 }
162
163 double scaling3 = uskeleton3.cuts.back()/boundingbox_X.extent();
164 if (scaling3 != 1.0) {
165 x3*=scaling3;
166 }
167
168 double scaling4 = uskeleton4.cuts.back()/boundingbox_Y.extent();
169 if (scaling4 != 1.0) {
170 y4*=scaling4;
171 }
172
173
174
175 Piecewise<SBasis> xbis = x;
176 Piecewise<SBasis> ybis = y;
177 xbis *= -1.0;
178 xbis += boundingbox_X.extent();
179 ybis *= -1.0;
180 ybis += boundingbox_Y.extent();
181 /* This is important : y + ybis = constant and x +xbis = constant */
182
183 Piecewise<D2<SBasis> > output;
184 Piecewise<D2<SBasis> > output1;
185 Piecewise<D2<SBasis> > output2;
186 Piecewise<D2<SBasis> > output_x;
187 Piecewise<D2<SBasis> > output_y;
188
189 /*
190 output_y : Deformation by Up and Down Bend Paths
191 We use weighting : The closer a point is to a Band Path, the more it will be affected by this Bend Path.
192 This is done by the line "ybis*Derformation1 + y*Deformation2"
193 The result is a mix between the 2 deformed paths
194 */
195 output_y = ybis*(compose((uskeleton1),x1) + y1*compose(n1,x1) )
196 + y*(compose((uskeleton3),x3) + y3*compose(n3,x3) );
197 output_y /= (boundingbox_Y.extent());
198 if(!xx.get_value() && yy.get_value())
199 {
200 return output_y;
201 }
202
203 /*output_x : Deformation by Left and Right Bend Paths*/
204 output_x = x*(compose((uskeleton2),y2) + -x2*compose(n2,y2) )
205 + xbis*(compose((uskeleton4),y4) + -x4*compose(n4,y4) );
206 output_x /= (boundingbox_X.extent());
207 if(xx.get_value() && !yy.get_value())
208 {
209 return output_x;
210 }
211
212 /*output : Deformation by Up, Left, Right and Down Bend Paths*/
213 if(xx.get_value() && yy.get_value())
214 {
215 Piecewise<SBasis> xsqr = x*xbis; /* xsqr = x * (BBox_X - x) */
216 Piecewise<SBasis> ysqr = y*ybis; /* xsqr = y * (BBox_Y - y) */
217 Piecewise<SBasis> xsqrbis = xsqr;
218 Piecewise<SBasis> ysqrbis = ysqr;
219 xsqrbis *= -1;
220 xsqrbis += boundingbox_X.extent()*boundingbox_X.extent()/4.;
221 ysqrbis *= -1;
222 ysqrbis += boundingbox_Y.extent()*boundingbox_Y.extent()/4.;
223 /*This is important : xsqr + xsqrbis = constant*/
224
225
226 /*
227 Here we mix the last two results : output_x and output_y
228 output1 : The more a point is close to Up and Down, the less it will be affected by output_x.
229 (This is done with the polynomial function)
230 output2 : The more a point is close to Left and Right, the less it will be affected by output_y.
231 output : we do the mean between output1 and output2 for all points.
232 */
233 output1 = (ysqrbis*output_y) + (ysqr*output_x);
234 output1 /= (boundingbox_Y.extent()*boundingbox_Y.extent()/4.);
235
236 output2 = (xsqrbis*output_x) + (xsqr*output_y);
237 output2 /= (boundingbox_X.extent()*boundingbox_X.extent()/4.);
238
239 output = output1 + output2;
240 output /= 2.;
241
242 return output;
243 /*Of course, the result is not perfect, but on a graphical point of view, this is sufficient.*/
244
245 }
246
247 // do nothing when xx and yy are both false
248 return pwd2_in;
249}
250
251void
253{
255
256 original_bbox(cast<SPLPEItem>(item), false, true);
257
262
263 Geom::Path path1;
264 path1.start( Up_Left );
265 path1.appendNew<Geom::LineSegment>( Up_Right );
266 bend_path1.set_new_value( path1.toPwSb(), true );
267
268 Geom::Path path2;
269 path2.start( Up_Right );
270 path2.appendNew<Geom::LineSegment>( Down_Right );
271 bend_path2.set_new_value( path2.toPwSb(), true );
272
273 Geom::Path path3;
274 path3.start( Down_Left );
275 path3.appendNew<Geom::LineSegment>( Down_Right );
276 bend_path3.set_new_value( path3.toPwSb(), true );
277
278 Geom::Path path4;
279 path4.start( Up_Left );
280 path4.appendNew<Geom::LineSegment>( Down_Left );
281 bend_path4.set_new_value( path4.toPwSb(), true );
282}
283
284
285} // namespace LivePathEffect
286} /* namespace Inkscape */
3x3 matrix representing an affine transformation.
Definition affine.h:70
Adaptor that creates 2D functions from 1D ones.
Definition d2.h:55
constexpr C extent() const
constexpr C min() const
constexpr C max() const
bool empty() const
Check whether the vector contains any paths.
Definition pathvector.h:145
Sequence of contiguous curves, aka spline.
Definition path.h:353
Piecewise< D2< SBasis > > toPwSb() const
Definition path.cpp:388
void appendNew(Args &&... args)
Append a new curve to the path.
Definition path.h:804
void start(Point const &p)
Definition path.cpp:426
Function defined as discrete pieces.
Definition piecewise.h:71
std::vector< double > cuts
Definition piecewise.h:75
Two-dimensional point that doubles as a vector.
Definition point.h:66
void registerParameter(Parameter *param)
Definition effect.cpp:1704
virtual void resetDefaults(SPItem const *item)
Sets all parameters to their default values and writes them to SVG.
Definition effect.cpp:2008
void original_bbox(SPLPEItem const *lpeitem, bool absolute=false, bool clip_mask=false, Geom::Affine base_transform=Geom::identity())
LPEEnvelope(LivePathEffectObject *lpeobject)
void doBeforeEffect(SPLPEItem const *lpeitem) override
Is performed each time before the effect is updated.
Geom::Piecewise< Geom::D2< Geom::SBasis > > doEffect_pwd2(Geom::Piecewise< Geom::D2< Geom::SBasis > > const &pwd2_in) override
void resetDefaults(SPItem const *item) override
Sets all parameters to their default values and writes them to SVG.
void transform_multiply(Geom::Affine const &postmul, bool set) override
Overridden function to apply transforms for example to powerstroke, jointtype or tapperstroke.
bool doOnOpen(SPLPEItem const *lpeitem) override
Is performed on load document or revert If the item is fixed legacy return true.
Geom::PathVector const & get_pathvector() const
Definition path.cpp:99
Geom::Piecewise< Geom::D2< Geom::SBasis > > const & get_pwd2()
Definition path.cpp:105
void set_new_value(Geom::PathVector const &newpath, bool write_to_svg)
Definition path.cpp:370
void param_transform_multiply(Geom::Affine const &postmul, bool set) override
Definition path.cpp:323
Geom::Affine get_relative_affine()
Definition path.cpp:86
Base class for visual SVG elements.
Definition sp-item.h:109
bool pathEffectsEnabled() const
bool optimizeTransforms()
returns false when LPE write unoptimiced
SPItem * item
Various utility functions.
Definition affine.h:22
D2< Piecewise< SBasis > > make_cuts_independent(Piecewise< D2< SBasis > > const &a)
Definition d2-sbasis.cpp:75
D2< T > compose(D2< T > const &a, T const &b)
Definition d2.h:405
Bezier derivative(Bezier const &a)
Definition bezier.cpp:282
Piecewise< D2< SBasis > > arc_length_parametrization(D2< SBasis > const &M, unsigned order=3, double tol=.01)
Piecewise< D2< SBasis > > force_continuity(Piecewise< D2< SBasis > > const &f, double tol=0, bool closed=false)
D2< T > rot90(D2< T > const &a)
Definition d2.h:397
Helper class to stream background task notifications as a series of messages.
unsigned n3
unsigned n4
unsigned n1
unsigned n2
Base class for live path effect items.