17#include <glibmm/i18n.h>
35 return (value > low && value < high);
39namespace LivePathEffect {
49 void knot_click(guint state)
override;
51 bool valid_index(
unsigned int index)
const {
52 return (_effect->attach_start._vector.size() >
index);
66 void knot_click(guint state)
override;
68 bool valid_index(
unsigned int index)
const {
69 return (_effect->attach_end._vector.size() >
index);
106 subpath(_(
"Select subpath:"), _(
"Select the subpath you want to modify"),
"subpath", &wr, this, 1.),
107 line_width(_(
"Stroke width:"), _(
"The (non-tapered) width of the path"),
"stroke_width", &wr, this, 1.),
108 attach_start(_(
"Start offset:"), _(
"Taper distance from path start"),
"attach_start", &wr, this, 0.2),
109 attach_end(_(
"End offset:"), _(
"The ending position of the taper"),
"end_offset", &wr, this, 0.2),
110 start_smoothing(_(
"Start smoothing:"), _(
"Amount of smoothing to apply to the start taper"),
"start_smoothing", &wr, this, 0.5),
111 end_smoothing(_(
"End smoothing:"), _(
"Amount of smoothing to apply to the end taper"),
"end_smoothing", &wr, this, 0.5),
115 miter_limit(_(
"Miter limit:"), _(
"Limit for miter joins"),
"miter_limit", &wr, this, 100.)
122 if (!ss || !g_strcmp0(ss,
"")){
125 g_warning(
"Your taper stroke is not set correctly in LPE id: %s, defaulting to center mode", this->
getRepr()->attribute(
"id"));
128 if (!se || !g_strcmp0(se,
"")){
131 g_warning(
"Your taper stroke is not set correctly in LPE id: %s, defaulting to center mode", this->
getRepr()->attribute(
"id"));
160 bool transform_stroke = prefs ? prefs->
getBool(
"/options/transform/stroke",
true) :
true;
168 auto lpeitem_mutable =
const_cast<SPLPEItem *
>(lpeitem);
169 auto item = cast<SPShape>(lpeitem_mutable);
172 g_warning(
"It only makes sense to apply Taper stroke to paths (not groups).");
182 Glib::ustring pref_path = (Glib::ustring)
"/live_effects/" +
185 (Glib::ustring)
"stroke_width";
198 auto lpeitem_mutable =
const_cast<SPLPEItem *
>(lpeitem);
199 auto shape = cast<SPShape>(lpeitem_mutable);
214 for (
unsigned i = 0; i < path_in.
size(); i++) {
216 if (path_in.
size() > i+1) {
243 auto const endTime = std::max(path.
size() -
end,
start);
265 using namespace Geom;
268 if ( pattern.
empty() ) {
274 std::vector<Piecewise<D2<SBasis> > > pre_output;
281 if (pattBndsX && pattBndsY) {
282 x0 -= pattBndsX->min();
283 y0 -= pattBndsY->middle();
291 std::vector<Piecewise<D2<SBasis> > > paths_in;
294 for (
auto path_i : paths_in) {
298 uskeleton = remove_short_cuts(uskeleton,.01);
303 double scaling = (uskeleton.
domain().
extent() - toffset)/pattBndsX->extent();
306 double pattWidth = pattBndsX->extent() * scaling;
308 if (scaling != 1.0) {
312 y*=(scaling*prop_scale);
314 if (prop_scale != 1.0) y *= prop_scale;
319 for (
int i=0; i<nbCopies; i++) {
323 pre_output.insert(pre_output.end(), splited_output_piece.begin(), splited_output_piece.end() );
339 using namespace Geom;
341 size_t sicepv = pathv.
size();
393 std::vector<double> attach_startv;
395 attach_startv.push_back(doub);
397 std::vector<double> attach_endv;
399 attach_endv.push_back(doub);
401 std::vector<double> start_smoothingv;
403 start_smoothingv.push_back(doub);
405 std::vector<double> end_smoothingv;
407 end_smoothingv.push_back(doub);
425 for (
auto path : pathv) {
429 bool zeroStart =
false;
430 bool zeroEnd =
false;
431 bool metInMiddle =
false;
436 unsigned size = path.size();
455 if (
double(
unsigned(attach_startv[
index])) == attach_startv[
index]) {
456 attach_startv[
index] = (attach_startv[
index] - 0.00001);
458 if (
double(
unsigned(attach_endv[
index])) == attach_endv[
index]) {
459 attach_endv[
index] = (attach_endv[
index] - 0.00001);
463 unsigned allowed_start = first_cusp.
size();
464 unsigned allowed_end = last_cusp.
size();
468 if ((
unsigned)attach_startv[
index] >= allowed_start) {
469 attach_startv[
index] = ((double)allowed_start - 0.00001);
471 if ((
unsigned)attach_endv[
index] >= allowed_end) {
472 attach_endv[
index] = ((double)allowed_end - 0.00001);
477 if (attach_startv[
index] < 0.0000001 ||
withinRange(
double(attach_startv[
index]), 0.00000001, 0.000001)) {
478 attach_startv[
index] = ( 0.0000001 );
481 if (attach_endv[
index] < 0.0000001 ||
withinRange(
double(attach_endv[
index]), 0.00000001, 0.000001)) {
482 attach_endv[
index] = ( 0.0000001 );
503 std::stringstream pat_str;
504 pat_str.imbue(std::locale::classic());
511 pat_str <<
"M 1,0 Q " << 1 - (double)start_smoothingv[
index] <<
",0 0,1 L 1,1";
514 pat_str <<
"M 1,0 L 0,0 Q " << 1 - (double)start_smoothingv[
index] <<
",1 1,1";
517 pat_str <<
"M 1,0 C " << 1 - (double)start_smoothingv[
index] <<
",0 0,0.5 0,0.5 0,0.5 " << 1 - (
double)start_smoothingv[
index] <<
",1 1,1";
525 real_path.
append(throwaway_path);
534 if (!zeroStart && real_path.
size() >= 1 && throwaway_path.
size() >= 1) {
541 real_path.
append(throwaway_path);
546 std::stringstream pat_str_1;
547 pat_str_1.imbue(std::locale::classic());
554 pat_str_1 <<
"M 0,1 L 1,1 Q " << (double)end_smoothingv[
index] <<
",0 0,0";
557 pat_str_1 <<
"M 0,1 Q " << (double)end_smoothingv[
index] <<
",1 1,0 L 0,0";
560 pat_str_1 <<
"M 0,1 C " << (double)end_smoothingv[
index] <<
",1 1,0.5 1,0.5 1,0.5 " << (
double)end_smoothingv[
index] <<
",0 0,0";
575 real_path.
append(throwaway_path);
588 real_path.
append(throwaway_path);
605 start_smoothingv.clear();
606 end_smoothingv.clear();
607 attach_startv.clear();
616 _(
"<b>Start point of the taper</b>: drag to alter the taper, <b>Shift+click</b> changes the taper direction"));
621 _(
"<b>End point of the taper</b>: drag to alter the taper, <b>Shift+click</b> changes the taper direction"));
630 using namespace Geom;
632 if (!valid_index(_index) || _effect->start_attach_point.size() <= _index) {
636 Geom::Point const s = snap_knot_position(p, state);
638 if (!is<SPShape>(_effect->sp_lpe_item)) {
639 g_warning(
"LPEItem is not a path!");
643 if (!cast_unsafe<SPShape>(_effect->sp_lpe_item)->curve()) {
656 _effect->attach_start._vector[_index] = t0;
657 _effect->attach_start.write_to_SVG();
662 using namespace Geom;
664 if (!valid_index(_index) || _effect->end_attach_point.size() <= _index) {
668 Geom::Point const s = snap_knot_position(p, state);
670 if (!is<SPShape>(_effect->sp_lpe_item)) {
671 g_warning(
"LPEItem is not a path!");
675 if (!cast_unsafe<SPShape>(_effect->sp_lpe_item)->curve()) {
684 _effect->attach_end._vector[_index] = t0;
685 _effect->attach_end.write_to_SVG();
688void KnotHolderEntityAttachBegin::knot_click(guint state)
690 using namespace Geom;
691 if (!(state & GDK_SHIFT_MASK)) {
695 if (!valid_index(_index) || _effect->start_attach_point.size() <= _index) {
700 _effect->start_shape.write_to_SVG();
703void KnotHolderEntityAttachEnd::knot_click(guint state)
705 using namespace Geom;
706 if (!(state & GDK_SHIFT_MASK)) {
710 if (!valid_index(_index) || _effect->end_attach_point.size() <= _index) {
715 _effect->end_shape.write_to_SVG();
718Geom::Point KnotHolderEntityAttachBegin::knot_get()
const
720 if (!valid_index(_index)) {
723 if (_effect && _effect->start_attach_point.size() > _index) {
724 return _effect->start_attach_point[_index];
729Geom::Point KnotHolderEntityAttachEnd::knot_get()
const
731 if (!valid_index(_index)) {
734 if (_effect && _effect->end_attach_point.size() > _index) {
735 return _effect->end_attach_point[_index];
3x3 matrix representing an affine transformation.
Adaptor that creates 2D functions from 1D ones.
constexpr C extent() const
Range of real numbers that can be empty.
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.
bool empty() const
Check whether path is empty.
Piecewise< D2< SBasis > > toPwSb() const
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.
void setFinal(Point const &p)
size_type size() const
Natural size of the path.
void appendNew(Args &&... args)
Append a new curve to the path.
Function defined as discrete pieces.
void concat(const Piecewise< T > &other)
Two-dimensional point that doubles as a vector.
Polynomial in symmetric power basis.
void param_set_and_write_new_value(std::vector< StorageType > const &new_vector)
std::vector< StorageType > _vector
bool valid_index(int index) const
std::vector< StorageType > const & data() const
void registerParameter(Parameter *param)
Inkscape::XML::Node * getRepr()
Geom::PathVector pathvector_before_effect
EffectType effectType() const
bool _provides_knotholder_entities
void param_setActive(size_t index)
void param_set_default() override
friend class TpS::KnotHolderEntityAttachBegin
void doBeforeEffect(SPLPEItem const *lpeitem) override
Is performed each time before the effect is updated.
EnumParam< unsigned > join_type
LPETaperStroke(LivePathEffectObject *lpeobject)
Geom::PathVector doEffect_simplePath(Geom::Path const &path, size_t index, double start, double end)
friend class TpS::KnotHolderEntityAttachEnd
void transform_multiply(Geom::Affine const &postmul, bool set) override
Overridden function to apply transforms for example to powerstroke, jointtype or tapperstroke.
void doOnApply(SPLPEItem const *lpeitem) override
Is performed a single time when the effect is freshly applied to a path.
void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item) override
Geom::PathVector pathv_out
std::vector< Geom::Point > end_attach_point
~LPETaperStroke() override
EnumArrayParam start_shape
ScalarArrayParam attach_start
Geom::PathVector doEffect_path(Geom::PathVector const &path_in) override
std::vector< Geom::Point > start_attach_point
ScalarArrayParam end_smoothing
ScalarArrayParam attach_end
void doOnRemove(SPLPEItem const *lpeitem) override
ScalarArrayParam start_smoothing
void param_set_digits(unsigned digits)
void param_setActive(size_t index)
void param_set_default() override
void param_set_digits(unsigned digits)
void param_transform_multiply(Geom::Affine const &postmul, bool set) override
void param_set_range(double min, double max)
bool param_readSVGValue(char const *strvalue) override
void param_set_increments(double step, double page)
void param_set_value(double val)
bool isValidDouble() const
Check if the preference value can be interpreted as a floating point value.
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.
Entry const getEntry(Glib::ustring const &pref_path)
Retrieve a preference entry without specifying its type.
Simplified management of enumerations of svg items with UI labels.
E get_id_from_key(const Glib::ustring &key) const
const Glib::ustring & get_key(const E id) const
void setAttribute(Util::const_char_ptr key, Util::const_char_ptr value)
Change an attribute of this node.
virtual char const * attribute(char const *key) const =0
Get the string representation of a node's attribute.
KnotHolderEntity definition.
void create(SPDesktop *desktop, SPItem *item, KnotHolder *parent, Inkscape::CanvasItemCtrlType type=Inkscape::CANVAS_ITEM_CTRL_TYPE_DEFAULT, Glib::ustring const &name="unknown", char const *tip="", uint32_t color=0xffffff00)
void add(KnotHolderEntity *e)
Base class for visual SVG elements.
SPStyle * style
Represents the style properties, whether from presentation attributes, the style attribute,...
T< SPAttr::STROKE_WIDTH, SPILength > stroke_width
stroke-width
Fill/stroke conversion routines for LPEs which draw a stroke.
Specific nodetype geometry functions for Inkscape, not provided my lib2geom.
Geom::PathVector pathv_to_linear_and_cubic_beziers(Geom::PathVector const &pathv)
Specific geometry functions for Inkscape, not provided my lib2geom.
bool withinRange(T value, T low, T high)
Taper Stroke path effect (meant as a replacement for using Power Strokes for tapering)
Various utility functions.
D2< Piecewise< SBasis > > make_cuts_independent(Piecewise< D2< SBasis > > const &a)
OptInterval bounds_exact(Bezier const &b)
Coord nearest_time(Point const &p, Curve const &c)
std::vector< Geom::Piecewise< Geom::D2< Geom::SBasis > > > split_at_discontinuities(Geom::Piecewise< Geom::D2< Geom::SBasis > > const &pwsbin, double tol=.0001)
@ NODE_SMOOTH
This node continuously joins two segments, with continuous unit tangent.
NodeType get_nodetype(Curve const &c_incoming, Curve const &c_outgoing)
PathVector path_from_piecewise(Piecewise< D2< SBasis > > const &B, double tol, bool only_cubicbeziers=false)
Make a path from a d2 sbasis.
D2< T > compose(D2< T > const &a, T const &b)
Bezier derivative(Bezier const &a)
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)
bool are_near(Affine const &a1, Affine const &a2, Coord eps=EPSILON)
D2< T > rot90(D2< T > const &a)
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,...
Piecewise< D2< SBasis > > stretch_along(Piecewise< D2< SBasis > > pwd2_in, Geom::Path pattern, double width)
Most of the below function is verbatim from Pattern Along Path.
static const Util::EnumDataConverter< unsigned > JoinTypeConverter(JoinTypeData, sizeof(JoinTypeData)/sizeof(*JoinTypeData))
const EnumEffectDataConverter< EffectType > LPETypeConverter
defined in effect.cpp
static Geom::Path return_at_first_cusp(Geom::Path const &path_in, double=0.05)
static const Util::EnumDataConverter< unsigned > TaperShapeTypeConverter(TaperShapeType, sizeof(TaperShapeType)/sizeof(*TaperShapeType))
static const Util::EnumData< unsigned > TaperShapeType[]
Helper class to stream background task notifications as a series of messages.
@ CANVAS_ITEM_CTRL_TYPE_LPE
Geom::Path half_outline(Geom::Path const &input, double width, double miter, LineJoinType join, double tolerance)
Offset the input path by width.
Singleton class to access the preferences file in a convenient way.
Conversion between SBasis and Bezier basis polynomials.
Simplified management of enumerations of svg items with UI labels.
SPStyle - a style object for SPItem objects.
Geom::PathVector sp_svg_read_pathv(char const *str)