Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
lpe-curvestitch.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
7/*
8 * Authors:
9 * Johan Engelen
10 *
11 * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
12 *
13 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
14 */
15
16#include "lpe-curvestitch.h"
17
18#include <glibmm/i18n.h>
19
20#include <2geom/sbasis-to-bezier.h> // for path_from_piecewise
21#include "object/sp-path.h"
22#include "svg/svg.h"
23#include "xml/node.h"
24
25namespace Inkscape {
26namespace LivePathEffect {
27
28using namespace Geom;
29
31 Effect(lpeobject),
32 strokepath(_("Stitch path:"), _("The path that will be used as stitch."), "strokepath", &wr, this, "M0,0 L1,0"),
33 nrofpaths(_("N_umber of paths:"), _("The number of paths that will be generated."), "count", &wr, this, 5),
34 startpoint_edge_variation(_("Sta_rt edge variance:"), _("The amount of random jitter to move the start points of the stitches inside & outside the guide path"), "startpoint_edge_variation", &wr, this, 0),
35 startpoint_spacing_variation(_("Sta_rt spacing variance:"), _("The amount of random shifting to move the start points of the stitches back & forth along the guide path"), "startpoint_spacing_variation", &wr, this, 0),
36 endpoint_edge_variation(_("End ed_ge variance:"), _("The amount of randomness that moves the end points of the stitches inside & outside the guide path"), "endpoint_edge_variation", &wr, this, 0),
37 endpoint_spacing_variation(_("End spa_cing variance:"), _("The amount of random shifting to move the end points of the stitches back & forth along the guide path"), "endpoint_spacing_variation", &wr, this, 0),
38 prop_scale(_("Scale _width:"), _("Scale the width of the stitch path"), "prop_scale", &wr, this, 1),
39 scale_y_rel(_("Scale _width relative to length"), _("Scale the width of the stitch path relative to its length"), "scale_y_rel", &wr, this, false)
40{
49
52
55 transformed = false;
56}
57
59
60bool
62{
63 if (!is_load || is_applied) {
64 return false;
65 }
67 return false;
68}
69
70
73{
74
75 if (is_load) {
77 }
78
79 if (path_in.size() >= 2) {
85
87 OptInterval bndsStroke = bounds_exact(stroke[0]);
88 OptInterval bndsStrokeY = bounds_exact(stroke[1]);
89 if (!bndsStroke && !bndsStrokeY) {
90 return path_in;
91 }
92 gdouble scaling = bndsStroke->max() - bndsStroke->min();
93 Point stroke_origin(bndsStroke->min(), (bndsStrokeY->max()+bndsStrokeY->min())/2);
94
95 Geom::PathVector path_out;
96
97 // do this for all permutations (ii,jj) if there are more than 2 paths? realllly cool!
98 for (unsigned ii = 0 ; ii < path_in.size() - 1; ii++)
99 for (unsigned jj = ii+1; jj < path_in.size(); jj++)
100 {
101 Piecewise<D2<SBasis> > A = arc_length_parametrization(Piecewise<D2<SBasis> >(path_in[ii].toPwSb()),2,.1);
102 Piecewise<D2<SBasis> > B = arc_length_parametrization(Piecewise<D2<SBasis> >(path_in[jj].toPwSb()),2,.1);
103 Interval bndsA = A.domain();
104 Interval bndsB = B.domain();
105 gdouble incrementA = (bndsA.max()-bndsA.min()) / (nrofpaths-1);
106 gdouble incrementB = (bndsB.max()-bndsB.min()) / (nrofpaths-1);
107 gdouble tA = bndsA.min();
108 gdouble tB = bndsB.min();
109 gdouble tAclean = tA; // the tA without spacing_variation
110 gdouble tBclean = tB; // the tB without spacing_variation
111
112 for (int i = 0; i < nrofpaths; i++) {
113 Point start = A(tA);
114 Point end = B(tB);
119
120 if (!Geom::are_near(start,end)) {
121 gdouble scaling_y = 1.0;
123 scaling_y = (L2(end-start)/scaling)*prop_scale;
124 transformed = false;
125 } else {
126 scaling_y = prop_scale;
127 }
128
129 Affine transform;
130 transform.setXAxis( (end-start) / scaling );
131 transform.setYAxis( rot90(unit_vector(end-start)) * scaling_y);
132 transform.setTranslation( start );
133 Piecewise<D2<SBasis> > pwd2_out = (strokepath.get_pwd2()-stroke_origin) * transform;
134
135 // add stuff to one big pw<d2<sbasis> > and then outside the loop convert to path?
136 // No: this way, the separate result paths are kept separate which might come in handy some time!
137 Geom::PathVector result = Geom::path_from_piecewise(pwd2_out, LPE_CONVERSION_TOLERANCE);
138 path_out.push_back(result[0]);
139 }
142 tAclean += incrementA;
143 tBclean += incrementB;
144 tA = tAclean + incrementA * svA;
145 tB = tBclean + incrementB * svB;
146 if (tA > bndsA.max())
147 tA = bndsA.max();
148 if (tB > bndsB.max())
149 tB = bndsB.max();
150 }
151 }
152
153 return path_out;
154 } else {
155 return path_in;
156 }
157}
158
159void
161{
163
164 if (!is<SPPath>(item)) return;
165
166 using namespace Geom;
167
168 // set the stroke path to run horizontally in the middle of the bounding box of the original path
169
170 // calculate bounding box: (isn't there a simpler way?)
172 Geom::PathVector temppath = sp_svg_read_pathv( item->getRepr()->attribute("inkscape:original-d"));
173 for (const auto & i : temppath) {
174 pwd2.concat( i.toPwSb() );
175 }
177 OptInterval bndsX = bounds_exact(d2pw[0]);
178 OptInterval bndsY = bounds_exact(d2pw[1]);
179 if (bndsX && bndsY) {
180 Point start(bndsX->min(), (bndsY->max()+bndsY->min())/2);
181 Point end(bndsX->max(), (bndsY->max()+bndsY->min())/2);
182 if ( !Geom::are_near(start,end) ) {
183 Geom::Path path;
184 path.start( start );
186 strokepath.set_new_value( path.toPwSb(), true );
187 } else {
188 // bounding box is too small to make decent path. set to default default. :-)
190 }
191 } else {
192 // bounding box is non-existent. set to default default. :-)
194 }
195}
196
197} //namespace LivePathEffect
198} /* namespace Inkscape */
199
200/*
201 Local Variables:
202 mode:c++
203 c-file-style:"stroustrup"
204 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
205 indent-tabs-mode:nil
206 fill-column:99
207 End:
208*/
209// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
3x3 matrix representing an affine transformation.
Definition affine.h:70
void setYAxis(Point const &vec)
Definition affine.cpp:50
void setTranslation(Point const &loc)
Sets the translation imparted by the Affine.
Definition affine.cpp:56
void setXAxis(Point const &vec)
Definition affine.cpp:45
Affine withoutTranslation() const
Definition affine.h:169
Adaptor that creates 2D functions from 1D ones.
Definition d2.h:55
constexpr C min() const
constexpr C max() const
Range of real numbers that is never empty.
Definition interval.h:59
Range of real numbers that can be empty.
Definition interval.h:199
Sequence of subpaths.
Definition pathvector.h:122
size_type size() const
Get the number of paths in the vector.
Definition pathvector.h:147
void push_back(Path const &path)
Append a path at the end.
Definition pathvector.h:172
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
Interval domain() const
Definition piecewise.h:215
void concat(const Piecewise< T > &other)
Definition piecewise.h:235
Two-dimensional point that doubles as a vector.
Definition point.h:66
void registerParameter(Parameter *param)
Definition effect.cpp:1710
virtual void resetDefaults(SPItem const *item)
Sets all parameters to their default values and writes them to SVG.
Definition effect.cpp:2014
void resetDefaults(SPItem const *item) override
Sets all parameters to their default values and writes them to SVG.
Geom::PathVector doEffect_path(Geom::PathVector const &path_in) override
bool doOnOpen(SPLPEItem const *lpeitem) override
Is performed on load document or revert If the item is fixed legacy return true.
LPECurveStitch(LivePathEffectObject *lpeobject)
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
Geom::Affine get_relative_affine()
Definition path.cpp:86
void param_set_digits(unsigned digits)
void param_set_range(double min, double max)
void param_set_increments(double step, double page)
virtual char const * attribute(char const *key) const =0
Get the string representation of a node's attribute.
Base class for visual SVG elements.
Definition sp-item.h:109
Inkscape::XML::Node * getRepr()
Returns the XML representation of tree.
Css & result
constexpr Coord infinity()
Get a value representing infinity.
Definition coord.h:88
SPItem * item
Implementation of the curve stitch effect, see lpe-curvestitch.cpp.
Geom::Point start
Geom::Point end
Various utility functions.
Definition affine.h:22
D2< Piecewise< SBasis > > make_cuts_independent(Piecewise< D2< SBasis > > const &a)
Definition d2-sbasis.cpp:75
OptInterval bounds_exact(Bezier const &b)
Definition bezier.cpp:310
PathVector path_from_piecewise(Piecewise< D2< SBasis > > const &B, double tol, bool only_cubicbeziers=false)
Make a path from a d2 sbasis.
SBasis L2(D2< SBasis > const &a, unsigned k)
Definition d2-sbasis.cpp:42
Piecewise< D2< SBasis > > arc_length_parametrization(D2< SBasis > const &M, unsigned order=3, double tol=.01)
Point unit_vector(Point const &a)
bool are_near(Affine const &a1, Affine const &a2, Coord eps=EPSILON)
D2< T > rot90(D2< T > const &a)
Definition d2.h:397
Helper class to stream background task notifications as a series of messages.
Conversion between SBasis and Bezier basis polynomials.
Geom::PathVector sp_svg_read_pathv(char const *str)
Definition svg-path.cpp:37
Interface for XML nodes.