16#include <glibmm/i18n.h>
39 Point const & origin_b,
Point const & vector_b)
43 Coord t = (
cross(vector_b, origin_a) +
cross(origin_b, vector_b)) / denom;
44 return origin_a + t * vector_a;
51 std::vector<Geom::Point> temp;
66 Coord K = 4 *
dot(p,q) / (L2sq(p) + L2sq(q));
75 double f = (-O[
X]*p[
Y] + O[
Y]*p[
X])/
cross;
78 double A = (a*d*
K+d*d+a*a);
79 double B = (a*e*
K+b*d*
K+2*d*e+2*a*b);
80 double C = (b*e*
K+e*e+b*b);
81 double D = (a*f*
K+
c*d*
K+2*d*f-2*d+2*a*
c-2*a);
82 double E = (b*f*
K+
c*e*
K+2*e*f-2*e+2*b*
c-2*b);
83 double F =
c*f*
K+f*f-2*f+
c*
c-2*
c+1;
96 if (
are_near(L2sq(dM(t)),0.) && (dM[0].
size() > 1) && (dM[1].
size() > 1) ) {
99 if (
are_near(L2sq(dM(t)),0.) && (dM[0].
size() > 1) && (dM[1].
size() > 1) ) {
111 k =
divide(k,dMlength,tol,3);
115 double radius = 1/curv;
123namespace LivePathEffect {
155 offset_points(_(
"Offset points"), _(
"Offset points"),
"offset_points", &wr, this),
156 not_jump(_(
"No jumping handles"), _(
"Allow to move handles along the path without them automatically attaching to the nearest path segment"),
"not_jump", &wr, this, false),
157 sort_points(_(
"Sort points"), _(
"Sort offset points according to their time value along the curve"),
"sort_points", &wr, this, true),
158 interpolator_type(_(
"Smoothing type"), _(
"Determines which kind of interpolator will be used to interpolate between stroke width along the path"),
"interpolator_type",
InterpolatorTypeConverter, &wr, this,
Geom::Interpolate::INTERP_CENTRIPETAL_CATMULLROM),
159 interpolator_beta(_(
"Smoothness:"), _(
"Sets the smoothness for the CubicBezierJohan interpolator; 0 = linear interpolation, 1 = smooth"),
"interpolator_beta", &wr, this, 0.2),
160 scale_width(_(
"Width multiplier"), _(
"Scale the stroke's width uniformly along the whole path"),
"scale_width", &wr, this, 1.0),
163 miter_limit(_(
"Miter limit"), _(
"Maximum length of the miter (in units of stroke width)"),
"miter_limit", &wr, this, 4.),
165 message(_(
"Add new thickness control point"), _(
"Important messages"),
"message", &wr, this, _(
"<b>Ctrl + click</b> on existing node and move it"))
218 if (
auto shape = cast<SPShape>(lpeitem)) {
221 std::vector<Geom::Point> points;
225 Glib::ustring pref_path_pp =
"/live_effects/powerstroke/powerpencil";
226 bool powerpencil = prefs->
getBool(pref_path_pp,
false);
231 if (!clipboard && !powerpencil) {
234 points.emplace_back(0.2,
width );
235 points.emplace_back(0.5,
width);
236 points.emplace_back(0.8,
width);
238 size_t current_pos = 0;
239 for (
auto path : pathv) {
241 if (!path.closed()) {
242 points.emplace_back(0.2 + current_pos,
width);
244 points.emplace_back((0.5 * psize) + current_pos,
width);
245 if (!path.closed()) {
246 points.emplace_back((psize - 0.2) + current_pos,
width);
248 current_pos += psize;
255 if (!is<SPShape>(lpeitem)) {
256 g_warning(
"LPE Powerstroke can only be applied to shapes (not groups).");
263 auto lpeitem_mutable =
const_cast<SPLPEItem *
>(lpeitem);
264 auto shape = cast<SPShape>(lpeitem_mutable);
294 if (B.empty() || !bbox) {
304 for (
unsigned i=1; i < B.size(); i++) {
308 if (B[i].isConstant(4e-3)) {
311 if (!
are_near(B[prev_i].at1(), B[i].at0(), tol) )
313 double width = y( B.cuts[i] );
317 Geom::Point discontinuity_vec = B[i].at0() - B[prev_i].at1();
318 bool on_outside = (
dot(tang1, discontinuity_vec) >= 0. );
342 ellipse =
find_ellipse(B[prev_i].at1(), B[i].at0(), *O);
367 false,
width < 0, B[i].at0() );
386 if (
len > fabs(
width) * miter_limit) {
390 std::pair<Geom::CubicBezier, Geom::CubicBezier> sub1 = bzr1.
subdivide(
cross[0].ta);
391 std::pair<Geom::CubicBezier, Geom::CubicBezier> sub2 = bzr2.
subdivide(
cross[0].tb);
392 pb.
curveTo(sub1.first[1], sub1.first[2], sub1.first[3]);
393 pb.
curveTo(sub2.second[1], sub2.second[2], sub2.second[3]);
402 std::vector<Geom::ShapeIntersection>
solutions;
407 bool point0bad =
false;
408 bool point1bad =
false;
419 if (!point0bad && !point1bad ) {
423 }
else if (!point0bad) {
425 }
else if (!point1bad) {
430 (*bbox).expandBy (bbox->width()/4);
432 if (!(*bbox).contains(sol)) {
439 arc0 = circle1.
arc(B[prev_i].at1(), 0.5*(B[prev_i].at1()+sol), sol);
440 arc1 = circle2.
arc(sol, 0.5*(sol+B[i].at0()), B[i].at0());
452 if (
len <= fabs(
width) * miter_limit) {
465 if (!solok || !(arc0 && build)) {
473 if (
len <= fabs(
width) * miter_limit) {
496 if (
len <= fabs(
width) * miter_limit) {
520 if (
len <= fabs(
width) * miter_limit) {
529 Geom::Point direction = B[i].at0() - B[prev_i].at1();
530 double tang1_sign =
dot(direction,tang1);
531 double tang2_sign =
dot(direction,tang2);
534 controlpoints[0].
x = (B[prev_i].at1() - tang1_sign*tang1)[
Geom::X];
535 controlpoints[0].
y = (B[prev_i].at1() - tang1_sign*tang1)[
Geom::Y];
536 controlpoints[0].
ty =
'{';
537 controlpoints[1].
x = B[prev_i].at1()[
Geom::X];
538 controlpoints[1].
y = B[prev_i].at1()[
Geom::Y];
539 controlpoints[1].
ty =
']';
540 controlpoints[2].
x = B[i].at0()[
Geom::X];
541 controlpoints[2].
y = B[i].at0()[
Geom::Y];
542 controlpoints[2].
ty =
'[';
543 controlpoints[3].
x = (B[i].at0() + tang2_sign*tang2)[
Geom::X];
544 controlpoints[3].
y = (B[i].at0() + tang2_sign*tang2)[
Geom::Y];
545 controlpoints[3].
ty =
'}';
548 pb.
append(spiro.portion(1, spiro.size_open() - 1));
564 if (
cross.size() != 1) {
570 for (
unsigned i=0; i < bzr1.
size_open(); ++i) {
591 using namespace Geom;
594 if (path_in.
empty()) {
598 size_t path_init = 0;
603 if (version <
"1.3") {
611 if (pwd2_in.
empty()) {
627 size_t pathindex = 0;
628 for (
auto path : pathv) {
630 std::cerr <<
"LPEPowerStroke::doEffect_path: empty sub-path!" << std::endl;
637 path_out_prev_tmp.
size() > pathindex &&
641 path_out.
push_back(path_out_prev_tmp[pathindex]);
645 path_out.
push_back(path_out_prev_tmp[pathindex]);
651 pwd2_in = path.toPwSb();
652 if (pwd2_in.
empty()) {
670 if (ts_no_scale.empty()) {
673 std::vector<Geom::Point> ts;
674 for (
auto & tsp : ts_no_scale) {
675 if (path_init - psize <= tsp[
Geom::X] && path_init >= tsp[
Geom::X]) {
691 if (path.closed() && ts.size()) {
692 std::vector<Geom::Point> ts_close;
697 if (version <
"1.3") {
702 ts_close.push_back(ts.back());
704 ts_close.push_back(tmpstart);
716 for (gint i = 0; i < p.
size_open(); i++) {
723 for (gint i = 0; i < p2.
size_open(); i++) {
727 gint signfront = ts.front()[
Geom::Y] > 0 ? 1 : -1;
728 gint signback = ts.back() [
Geom::Y] > 0 ? 1 : -1;
730 bool inverted = std::abs(ts.front()[
Geom::Y]) > std::abs(ts.back()[
Geom::Y]);
731 double min = std::min(std::abs(ts.front()[
Geom::Y]), std::abs(ts.back()[
Geom::Y]));
732 double max = std::max(std::abs(ts.front()[
Geom::Y]), std::abs(ts.back()[
Geom::Y]));
733 if (signfront < 0 && signback < 0) {
737 }
else if (signfront < 0) {
738 max *=
max == std::abs(ts.front()[
Geom::Y]) ? signfront : signback;
739 min *=
min == std::abs(ts.front()[
Geom::Y]) ? signback : signfront;
740 }
else if (signback < 0) {
741 max *=
max == std::abs(ts.front()[
Geom::Y]) ? signfront : signback;
742 min *=
min == std::abs(ts.front()[
Geom::Y]) ? signback : signfront;
744 double gap = std::abs(
max-
min);
745 double factor1 = pl/(pl + pl2);
746 double factor2 = pl2/(pl + pl2);
747 bool toggled =
false;
756 ts.insert(ts.begin(),
start );
758 if (version <
"1.3") {
767 ts.emplace_back(pwd2_in.
domain().
max(), end_y);
772 double pwd2_in_arclength =
length(pwd2_in);
773 double xcoord_scaling = pwd2_in_arclength / ts.back()[
Geom::X];
774 for (
auto & t : ts) {
782 strokepath *=
Scale(1/xcoord_scaling, 1);
789 std::vector< double > rtsmin =
roots (x - pwd2_in.
domain().
min());
790 std::vector< double > rtsmax =
roots (x + pwd2_in.
domain().
max());
791 if ( !rtsmin.empty() && !rtsmax.empty() ) {
792 x =
portion(x, rtsmin.at(0), rtsmax.at(0));
793 y =
portion(y, rtsmin.at(0), rtsmax.at(0));
806 fixed_path.
close(
true);
809 fixed_mirrorpath.
close(
true);
816 switch (end_linecap) {
852 fixed_path.
append(fixed_mirrorpath);
853 switch (start_linecap) {
888 fixed_path.
close(
true);
893 if (version <
"1.3") {
897 path_out_prev_tmp.
clear();
898 if (path_out.
empty()) {
921 double threshold = simplify->
threshold * 1.2;
3x3 matrix representing an affine transformation.
Bezier curve with compile-time specified order.
std::pair< BezierCurveN, BezierCurveN > subdivide(Coord t) const
Divide a Bezier curve into two curves.
Point pointAt(Coord t) const override
Evaluate the curve at a specified time value.
Set of all points at a fixed distance from the center.
EllipticalArc * arc(Point const &initial, Point const &inner, Point const &final) const
std::vector< ShapeIntersection > intersect(Line const &other) const
virtual Coord length(Coord tolerance=0.01) const
Compute the arc length of this curve.
Adaptor that creates 2D functions from 1D ones.
bool isZero(double eps=EPSILON) const
Set of points with a constant sum of distances from two foci.
Angle rotationAngle() const
Get the angle the X ray makes with the +X axis.
Coord ray(Dim2 d) const
Get one ray of the ellipse.
D2< SBasis > toSBasis() const override
Convert the curve to a symmetric power basis polynomial.
virtual Geom::Path interpolateToPath(std::vector< Point > const &points) const =0
static Interpolator * create(InterpolatorType type)
Axis-aligned rectangle that can be empty.
Store paths to a PathVector.
PathVector const & peek() const
Retrieve the path.
void setStitching(bool s)
void moveTo(Point const &p) override
Move to a different point without creating a segment.
void append(Path const &other)
bool backspace() override
Undo the last segment.
void arcTo(Coord rx, Coord ry, Coord angle, bool large_arc, bool sweep, Point const &p) override
Output an elliptical arc segment.
void lineTo(Point const &p) override
Output a line segment.
void flush() override
Flush any internal state of the generator.
void curveTo(Point const &c0, Point const &c1, Point const &p) override
Output a quadratic Bezier segment.
size_type size() const
Get the number of paths in the vector.
void push_back(Path const &path)
Append a path at the end.
void clear()
Remove all paths from the vector.
bool empty() const
Check whether the vector contains any paths.
Sequence of contiguous curves, aka spline.
Point finalPoint() const
Get the last point in the path.
void close(bool closed=true)
Set whether the path is closed.
Piecewise< D2< SBasis > > toPwSb() const
Point pointAt(Coord t) const
Get the point at the specified time value.
size_type size_open() const
Size without the closing segment, even if the path is closed.
Path portion(Coord f, Coord t) const
void append(Curve *curve)
Add a new curve to the end of the path.
Point initialPoint() const
Get the first point in the path.
Curve const & curveAt(Coord t, Coord *rest=NULL) const
Get the curve at the specified time value.
void appendNew(Args &&... args)
Append a new curve to the path.
Function defined as discrete pieces.
output_type lastValue() const
output_type firstValue() const
Two-dimensional point that doubles as a vector.
constexpr Point cw() const
Return a point like this point but rotated +90 degrees.
void param_set_and_write_new_value(std::vector< StorageType > const &new_vector)
std::vector< StorageType > const & data() const
void registerParameter(Parameter *param)
bool _provides_path_adjustment
Geom::PathVector pathvector_before_effect
Geom::PathVector pathvector_after_effect
LivePathEffectObject * getLPEObj()
void param_setValue(Glib::ustring newvalue, bool write=false)
Glib::ustring param_getSVGValue() const override
void adjustForNewPath() override
EnumParam< unsigned > linejoin_type
void doBeforeEffect(SPLPEItem const *lpeItem) override
Is performed each time before the effect is updated.
EnumParam< unsigned > interpolator_type
ScalarParam interpolator_beta
EnumParam< unsigned > start_linecap_type
void doOnApply(SPLPEItem const *lpeitem) override
Is performed a single time when the effect is freshly applied to a path.
Geom::PathVector doEffect_path(Geom::PathVector const &path_in) override
PowerStrokePointArrayParam offset_points
void transform_multiply(Geom::Affine const &postmul, bool set) override
Overridden function to apply transforms for example to powerstroke, jointtype or tapperstroke.
void doOnRemove(SPLPEItem const *lpeitem) override
LPEPowerStroke(LivePathEffectObject *lpeobject)
~LPEPowerStroke() override
void applyStyle(SPLPEItem *lpeitem)
void doAfterEffect(SPLPEItem const *lpeitem, Geom::PathVector *curve) override
Is performed at the end of the LPE only one time per "lpeitem" in paths/shapes is called in middle of...
EnumParam< unsigned > end_linecap_type
Geom::PathVector path_out_prev
void recalculate_controlpoints(Geom::PathVector pv)
call this method to recalculate the controlpoints such that they stay at the same location relative t...
void set_pwd2(Geom::Piecewise< Geom::D2< Geom::SBasis > > const &pwd2_in, Geom::Piecewise< Geom::D2< Geom::SBasis > > const &pwd2_normal_in)
void set_scale_width(double scale_width)
void param_transform_multiply(Geom::Affine const &postmul, bool) override
void param_set_digits(unsigned digits)
void param_set_range(double min, double max)
void param_set_increments(double step, double page)
void addSlider(bool add_slider_widget)
void param_set_value(double val)
Preference storage class.
bool getBool(Glib::ustring const &pref_path, bool def=false)
Retrieve a Boolean value.
static Preferences * get()
Access the singleton Preferences object.
Simplified management of enumerations of svg items with UI labels.
Inkscape::LivePathEffect::Effect * get_lpe()
Inkscape::LivePathEffect::Effect * getFirstPathEffectOfType(int type)
SPStyle * style
Represents the style properties, whether from presentation attributes, the style attribute,...
Inkscape::XML::Node * updateRepr(unsigned int flags=SP_OBJECT_WRITE_EXT)
Updates the object's repr based on the object's state.
T< SPAttr::STROKE_WIDTH, SPILength > stroke_width
stroke-width
Fill/stroke conversion routines for LPEs which draw a stroke.
BezierCurveN< 3 > CubicBezier
Cubic (order 3) Bezier curve.
double Coord
Floating point type used to store coordinates.
constexpr Coord EPSILON
Default "acceptably small" value.
Geom::PathVector pathv_to_linear_and_cubic_beziers(Geom::PathVector const &pathv)
size_t count_pathvector_curves(Geom::PathVector const &pathv)
Specific geometry functions for Inkscape, not provided my lib2geom.
Interpolators for lists of points.
PowerStroke LPE effect, see lpe-powerstroke.cpp.
@ INTERP_CUBICBEZIER_JOHAN
@ INTERP_CUBICBEZIER_SMOOTH
@ INTERP_CENTRIPETAL_CATMULLROM
Various utility functions.
Path path_from_sbasis(D2< SBasis > const &B, double tol, bool only_cubicbeziers=false)
Make a path from a d2 sbasis.
Coord length(LineSegment const &seg)
D2< Piecewise< SBasis > > make_cuts_independent(Piecewise< D2< SBasis > > const &a)
Bezier reverse(const Bezier &a)
SBasisN< n > divide(SBasisN< n > const &a, SBasisN< n > const &b, int k)
Piecewise< D2< SBasis > > paths_to_pw(PathVector const &paths)
MultiDegree< n > max(MultiDegree< n > const &p, MultiDegree< n > const &q)
Returns the maximal degree appearing in the two arguments for each variables.
Coord nearest_time(Point const &p, Curve const &c)
Coord distanceSq(Point const &p, Rect const &rect)
void build_from_sbasis(PathBuilder &pb, D2< SBasis > const &B, double tol, bool only_cubicbeziers)
Make a path from a d2 sbasis.
Angle distance(Angle const &a, Angle const &b)
static float sign(double number)
Returns +1 for positive numbers, -1 for negative numbers, and 0 otherwise.
static Point intersection_point(Point origin_a, Point vector_a, Point origin_b, Point vector_b)
static Geom::CubicBezier sbasis_to_cubicbezier(Geom::D2< Geom::SBasis > const &sbasis_in)
D2< T > compose(D2< T > const &a, T const &b)
std::vector< double > roots(SBasis const &s)
std::vector< Crossing > Crossings
Crossings crossings(Curve const &a, Curve const &b)
static Circle touching_circle(D2< SBasis > const &curve, double t, double tol=0.01)
Find circle that touches inside of the curve, with radius matching the curvature, at time value t.
void sbasis_to_bezier(Bezier &bz, SBasis const &sb, size_t sz=0)
Changes the basis of p to be bernstein.
Bezier portion(const Bezier &a, double from, double to)
Bezier derivative(Bezier const &a)
Piecewise< SBasis > cross(Piecewise< D2< SBasis > > const &a, Piecewise< D2< SBasis > > const &b)
Point unitTangentAt(D2< SBasis > const &a, Coord t, unsigned n=3)
Piecewise< SBasis > min(SBasis const &f, SBasis const &g)
Return the more negative of the two functions pointwise.
T dot(D2< T > const &a, D2< T > const &b)
OptInterval bounds_fast(Bezier const &b)
bool are_near(Affine const &a1, Affine const &a2, Coord eps=EPSILON)
static Ellipse find_ellipse(Point P, Point Q, Point O)
document this! very quick: this finds the ellipse with minimum eccentricity passing through point P a...
D2< T > rot90(D2< T > const &a)
Point middle_point(LineSegment const &_segment)
Piecewise< D2< SBasis > > unitVector(D2< SBasis > const &vect, double tol=.01, unsigned order=3)
static Geom::Path path_from_piecewise_fix_cusps(Geom::Piecewise< Geom::D2< Geom::SBasis > > const &B, Geom::Piecewise< Geom::SBasis > const &y, LineJoinType jointype, double miter_limit, double tol=Geom::EPSILON)
void lpe_shape_convert_stroke_and_fill(SPShape *shape)
Prepares a SPShape's fill and stroke for use in a path effect by setting the existing stroke properti...
void lpe_shape_revert_stroke_and_fill(SPShape *shape, double width)
Applies the fill of the SPShape to its stroke, sets the stroke width to the provided parameter,...
static bool compare_offsets(Geom::Point first, Geom::Point second)
static const Util::EnumDataConverter< unsigned > LineCapTypeConverter(LineCapTypeData, sizeof(LineCapTypeData)/sizeof(*LineCapTypeData))
@ LINEJOIN_EXTRP_MITER_ARC
static const Util::EnumData< unsigned > LineJoinTypeData[]
static const Util::EnumDataConverter< unsigned > LineJoinTypeConverter(LineJoinTypeData, sizeof(LineJoinTypeData)/sizeof(*LineJoinTypeData))
static const Util::EnumData< unsigned > InterpolatorTypeData[]
static const Util::EnumDataConverter< unsigned > InterpolatorTypeConverter(InterpolatorTypeData, sizeof(InterpolatorTypeData)/sizeof(*InterpolatorTypeData))
Helper class to stream background task notifications as a series of messages.
Geom::Path spiro_run(const spiro_cp *src, int src_len)
callback interface for SVG path data
Singleton class to access the preferences file in a convenient way.
std::vector< double > & solutions
Simplified management of enumerations of svg items with UI labels.
SPStyle - a style object for SPItem objects.
Glib::RefPtr< Gtk::Adjustment > smooth