diff --git a/share/icons/Dash/scalable/actions/trim.svg b/share/icons/Dash/scalable/actions/trim.svg new file mode 100644 index 0000000000000000000000000000000000000000..85065dba6307b223d50d3d74156e0970968e81e3 --- /dev/null +++ b/share/icons/Dash/scalable/actions/trim.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/share/icons/Dash/symbolic/actions/trim-symbolic.svg b/share/icons/Dash/symbolic/actions/trim-symbolic.svg new file mode 100644 index 0000000000000000000000000000000000000000..85065dba6307b223d50d3d74156e0970968e81e3 --- /dev/null +++ b/share/icons/Dash/symbolic/actions/trim-symbolic.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/share/icons/hicolor/scalable/actions/trim.svg b/share/icons/hicolor/scalable/actions/trim.svg new file mode 100644 index 0000000000000000000000000000000000000000..85065dba6307b223d50d3d74156e0970968e81e3 --- /dev/null +++ b/share/icons/hicolor/scalable/actions/trim.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/share/icons/hicolor/symbolic/actions/trim-symbolic.svg b/share/icons/hicolor/symbolic/actions/trim-symbolic.svg new file mode 100644 index 0000000000000000000000000000000000000000..85065dba6307b223d50d3d74156e0970968e81e3 --- /dev/null +++ b/share/icons/hicolor/symbolic/actions/trim-symbolic.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/share/icons/multicolor/symbolic/actions/trim-symbolic.svg b/share/icons/multicolor/symbolic/actions/trim-symbolic.svg new file mode 100644 index 0000000000000000000000000000000000000000..85065dba6307b223d50d3d74156e0970968e81e3 --- /dev/null +++ b/share/icons/multicolor/symbolic/actions/trim-symbolic.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index 89703479cc443022f0bbbdf437f1fb8eb5e0d4f5..04780b5ba20e54233d335be0ad8d3e2ac0838dcb 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -60,6 +60,7 @@ set(live_effects_SRC lpe-text_label.cpp lpe-tiling.cpp lpe-transform_2pts.cpp + lpe-trim-shape.cpp lpegroupbbox.cpp lpeobject-reference.cpp lpe-vonkoch.cpp @@ -158,6 +159,7 @@ set(live_effects_SRC lpe-text_label.h lpe-tiling.h lpe-transform_2pts.h + lpe-trim-shape.h lpe-vonkoch.h lpegroupbbox.h lpeobject-reference.h diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h index 0ae38eb4142168b7b26b59952f130734d3f96e39..0aaf3b85bde9da04da766ffe3399d5e911f5563d 100644 --- a/src/live_effects/effect-enum.h +++ b/src/live_effects/effect-enum.h @@ -59,6 +59,7 @@ enum EffectType { BOOL_OP, SLICE, TILING, + TRIM_SHAPE, // PUT NEW LPE BEFORE EXPERIMENTAL IN THE SAME ORDER AS IN effect.cpp // Visible Experimental LPE's ANGLE_BISECTOR, diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 7685b05918ff0b906516bf8bbddac16a357e15fb..f41d9187cfe7eba4aa2ea996367df2d545170f3b 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -77,6 +77,7 @@ #include "live_effects/lpe-test-doEffect-stack.h" #include "live_effects/lpe-text_label.h" #include "live_effects/lpe-tiling.h" +#include "live_effects/lpe-trim-shape.h" #include "live_effects/lpe-transform_2pts.h" #include "live_effects/lpe-vonkoch.h" #include "message-stack.h" @@ -691,6 +692,21 @@ const EnumEffectData LPETypeData[] = { false ,//on_text false ,//experimental }, + /* 1.5 */ + { + TRIM_SHAPE, + NC_("path effect", "Trim shapes") ,//label + "trim_shape" ,//key + "trim" ,//icon + N_("Trim shape") ,//description + LPECategory::EditTools ,//category + true ,//on_path + true ,//on_shape + false ,//on_group + false ,//on_image + false ,//on_text + false ,//experimental + }, // VISIBLE experimental LPEs { ANGLE_BISECTOR, @@ -1113,6 +1129,9 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case TILING: neweffect = static_cast ( new LPETiling(lpeobj) ); break; + case TRIM_SHAPE: + neweffect = static_cast ( new LPETrimShape(lpeobj) ); + break; default: g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr); neweffect = nullptr; diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index 25b19194fea1df071638da8f42970a5d716b55df..6baa215a33f4b6a253deb474e1bee64fd05e35cb 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -38,7 +38,7 @@ inline bool withinRange(T value, T low, T high) { namespace Inkscape { namespace LivePathEffect { -namespace TpS { +namespace TapperStrokeNS { class KnotHolderEntityAttachBegin : public LPEKnotHolderEntity { public: KnotHolderEntityAttachBegin(LPETaperStroke * effect, size_t index) @@ -51,7 +51,7 @@ namespace TpS { bool valid_index(unsigned int index) const { return (_effect->attach_start._vector.size() > index); }; - private: + protected: size_t _index; LPETaperStroke * _effect; }; @@ -66,13 +66,13 @@ namespace TpS { void knot_click(guint state) override; Geom::Point knot_get() const override; bool valid_index(unsigned int index) const { - return (_effect->attach_end._vector.size() > index); + return (_effect->attach_start._vector.size() > index); }; - private: + protected: size_t _index; LPETaperStroke * _effect; }; -} // TpS +} // TapperStrokeNS static const Util::EnumData JoinType[] = { // clang-format off @@ -611,19 +611,19 @@ LPETaperStroke::doBeforeEffect (SPLPEItem const* lpeitem) void LPETaperStroke::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item) { for (size_t i = 0 ; i < attach_start._vector.size(); i++) { - KnotHolderEntity *e = new TpS::KnotHolderEntityAttachBegin(this, i); + KnotHolderEntity *e = new TapperStrokeNS::KnotHolderEntityAttachBegin(this, i); e->create(nullptr, item, knotholder, Inkscape::CANVAS_ITEM_CTRL_TYPE_LPE, "LPE:TaperStrokeBegin", _("Start point of the taper: drag to alter the taper, Shift+click changes the taper direction")); knotholder->add(e); - KnotHolderEntity *f = new TpS::KnotHolderEntityAttachEnd(this, i); + KnotHolderEntity *f = new TapperStrokeNS::KnotHolderEntityAttachEnd(this, i); f->create(nullptr, item, knotholder, Inkscape::CANVAS_ITEM_CTRL_TYPE_LPE, "LPE:TaperStrokeEnd", _("End point of the taper: drag to alter the taper, Shift+click changes the taper direction")); knotholder->add(f); } } -namespace TpS { +namespace TapperStrokeNS { void KnotHolderEntityAttachBegin::knot_set(Geom::Point const &p, Geom::Point const&/*origin*/, guint state) { @@ -737,7 +737,7 @@ Geom::Point KnotHolderEntityAttachEnd::knot_get() const return Geom::Point(); } -} // namespace TpS +} // namespace TapperStrokeNS } // namespace LivePathEffect } // namespace Inkscape diff --git a/src/live_effects/lpe-taperstroke.h b/src/live_effects/lpe-taperstroke.h index 42b8ca84774e4a8a3b50a2a7e36c4c7f91af4b40..a4e2cf03da0d206e32d37b8ba0514966b46c149d 100644 --- a/src/live_effects/lpe-taperstroke.h +++ b/src/live_effects/lpe-taperstroke.h @@ -21,7 +21,7 @@ namespace Inkscape { namespace LivePathEffect { -namespace TpS { +namespace TapperStrokeNS { // we need a separate namespace to avoid clashes with other LPEs class KnotHolderEntityAttachBegin; class KnotHolderEntityAttachEnd; @@ -41,8 +41,8 @@ public: void addKnotHolderEntities(KnotHolder * knotholder, SPItem * item) override; protected: - friend class TpS::KnotHolderEntityAttachBegin; - friend class TpS::KnotHolderEntityAttachEnd; + friend class TapperStrokeNS::KnotHolderEntityAttachBegin; + friend class TapperStrokeNS::KnotHolderEntityAttachEnd; ScalarArrayParam attach_start; ScalarArrayParam attach_end; ScalarArrayParam start_smoothing; diff --git a/src/live_effects/lpe-trim-shape.cpp b/src/live_effects/lpe-trim-shape.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0120f811d698168d9eaed1469a704a25ff699f69 --- /dev/null +++ b/src/live_effects/lpe-trim-shape.cpp @@ -0,0 +1,436 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Author(s): + * Jabiertxo Arraiza Cenoz + * + * Copyright (C) 2014 Author(s) + * + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include "lpe-trim-shape.h" +#include +#include "helper/geom.h" +#include "helper/geom-nodetype.h" +#include "object/sp-shape.h" +#include "object/sp-lpe-item.h" +#include "svg/svg.h" +#include "ui/knot/knot-holder.h" +#include "ui/knot/knot-holder-entity.h" + + +template +inline bool withinRange(T value, T low, T high) { + return (value > low && value < high); +} + +namespace Inkscape { +namespace LivePathEffect { + +namespace TrimShapeNS { + class KnotHolderEntityAttach : public LPEKnotHolderEntity { + public: + KnotHolderEntityAttach(LPETrimShape * effect, size_t index, bool begin) + : LPEKnotHolderEntity(effect) + , _effect(effect) + , _index(index) + , _begin(begin) {}; + void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state) override; + void knot_ungrabbed(Geom::Point const &p, Geom::Point const &origin, unsigned state) override; + Geom::Point knot_get() const override; + bool valid_index(unsigned int index) const { + return (_effect->attach_start._vector.size() > index); + }; + protected: + size_t _index; + bool _begin; + LPETrimShape * _effect; + }; +} // TrimShapeNS + +LPETrimShape::LPETrimShape(LivePathEffectObject *lpeobject) + : Effect(lpeobject), + subpath(_("Select subpath"), _("Select the subpath you want to modify"), "subpath", &wr, this, 1.), + attach_start(_("Start offset"), _("Trim distance from path start"), "attach_start", &wr, this, 10), + attach_end(_("End offset"), _("The ending position of the trim"), "end_offset", &wr, this, 10), + flexible(_("Flexible position"), _("Flexible or absolute document units"), "flexible", &wr, this, true), + linkall(_("Link all subpaths"), _("Link all subpaths"), "linkall", &wr, this, false) +{ + show_orig_path = true; + _provides_knotholder_entities = true; + attach_start.param_set_digits(2); + attach_start.param_set_increments(1, 1); + attach_end.param_set_digits(2); + attach_end.param_set_increments(1, 1); + subpath.param_set_range(1, 1); + subpath.param_set_increments(1, 1); + subpath.param_set_digits(0); + registerParameter(&subpath); + registerParameter(&attach_start); + registerParameter(&attach_end); + registerParameter(&flexible); + registerParameter(&linkall); +} + +LPETrimShape::~LPETrimShape() = default; + +void LPETrimShape::doOnApply(SPLPEItem const *lpeItem) +{ + SPLPEItem *splpeitem = const_cast(lpeItem); + auto shape = cast(splpeitem); + if (!shape) { + g_warning("LPE Slice Nodes can only be applied to shapes (not groups)."); + SPLPEItem *item = const_cast(lpeItem); + item->removeCurrentPathEffect(false); + } +} + +// breaks time value into integral and fractional part +// must be better add PathVectorTimeAt and PathTimeAt to 2Geom adding this dupled function +Geom::PathTime LPETrimShape::_factorTime(Geom::Path const path, Geom::Coord t) const +{ + Geom::Path::size_type sz = path.size_default(); + if (t < 0 || t > sz) { + g_warning("parameter t out of bounds"); + t = sz; + } + + Geom::PathTime ret; + Geom::Coord k; + ret.t = modf(t, &k); + ret.curve_index = k; + if (ret.curve_index == sz) { + --ret.curve_index; + ret.t = 1; + } + return ret; +} + +/** + * @return Always returns a PathVector with three elements. + * + * The positions of the effect knots are accessed to determine + * where exactly the input path should be split. + */ +Geom::Path LPETrimShape::doEffect_simplePath(Geom::Path const & path, double start, double end) +{ + bool cross_start = false; + if (path.size() - start < end) { // this allow coninuing on closed paths like circles + cross_start = path.closed(); + } + if (path.size() - start == 0 && end == 0) { // this hide the path if start and end collapse at 0 + return Geom::Path(); + } + return path.portion(_factorTime(path, start), _factorTime(path, path.size() - end), cross_start); +} + +///Calculate the time in curve with a length +//TODO: find a better place to it dupled code better in 2GEOM +double LPETrimShape::timeAtLength(double const A, Geom::Piecewise> pwd2) +{ + if ( A == 0 || pwd2.size() == 0) { + return 0; + } + + double t = pwd2.size(); + std::vector t_roots = roots(Geom::arcLengthSb(pwd2) - A); + if (!t_roots.empty()) { + t = t_roots[0]; + } + return t; +} + +void LPETrimShape::doBeforeEffect(SPLPEItem const *lpeItem) +{ + using namespace Geom; + // this allow multi stack LPE + auto first = dynamic_cast(lpeItem->getFirstPathEffectOfType(TRIM_SHAPE)); + _pathvector_before_effect = pathvector_before_effect; + if (this != first) { + _pathvector_before_effect = first->_pathvector_before_effect; + } + // define ranges based on flexible value + if (prevflex != flexible) { + if (flexible) { + attach_start.param_set_range(0, 100); + attach_end.param_set_range(0, 100); + } else { + attach_start.param_set_range(0, std::numeric_limits::max()); + attach_end.param_set_range(0, std::numeric_limits::max()); + } + } + prevflex = flexible; + Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers(_pathvector_before_effect); + size_t sicepv = pathv.size(); + bool write = false; + // if number of subpaths change + if (previous_size != sicepv) { + subpath.param_set_range(1, sicepv); + // move to first one + subpath.param_readSVGValue("1"); + if (!is_load) { + attach_start._vector.clear(); + attach_end._vector.clear(); + } + previous_size = sicepv; + linkall.param_widget_is_enabled(sicepv > 1); + refresh_widgets = true; + } + + // if no begin data + if (!attach_start._vector.size()) { + // add 0 to all paths + for (auto path : _pathvector_before_effect) { + attach_start._vector.push_back(0); + attach_end._vector.push_back(0); + } + attach_start.param_set_default(); + attach_end.param_set_default(); + write = true; + } + // if active subpath change + if (prev_subpath != subpath) { + attach_start.param_setActive(subpath - 1); + attach_end.param_setActive(subpath - 1); + prev_subpath = subpath; + refresh_widgets = true; + write = true; + } + std::vector attach_startv; + Geom::Path::size_type index = 0; + // for each data in begin + for (auto & doub : attach_start.data()) { + if (linkall) { + // we need to sinc, add all the same to all + attach_startv.push_back(attach_start._vector[subpath - 1]); + } else { + // if active subpath change and path is not current set value to negative to further ignore + if (prev_subpath != subpath && index != (int)subpath) { + attach_startv.push_back(-1); + } else { + attach_startv.push_back(doub); + } + } + index += 1; + } + std::vector attach_endv; + index = 0; + for (auto & doub : attach_end.data()) { + if (linkall) { + attach_endv.push_back(attach_end._vector[subpath - 1]); + } else { + // if active subpath change and path is not current set value to negative to further ignore + if (prev_subpath != subpath && index != (int)subpath) { + attach_endv.push_back(-1); + } else { + attach_endv.push_back(doub); + } + } + index += 1; + } + // if write or start or end are moved + if (write || (linkall && ( + prev_attach_start != attach_start._vector[subpath - 1] || + prev_attach_end != attach_end._vector[subpath - 1] + ))) + { + attach_start.param_set_and_write_new_value(attach_startv); + attach_end.param_set_and_write_new_value(attach_endv); + } + prev_attach_start = attach_start._vector[subpath - 1]; + prev_attach_end = attach_end._vector[subpath - 1]; + pathv_out.clear(); + if (_pathvector_before_effect.empty()) { + return; + } + + index = 0; + // clear points + start_attach_point.clear(); + end_attach_point.clear(); + for (auto path : pathv) { + Geom::Path first_cusp = path; + Geom::Path last_cusp = path.reversed(); + Geom::Coord path_length = path.length(); + Geom::Piecewise< Geom::D2< Geom::SBasis > > first_cusp_pwd2 = first_cusp.toPwSb(); + Geom::Piecewise< Geom::D2< Geom::SBasis > > last_cusp_pwd2 = last_cusp.toPwSb(); + + // there is a pretty good chance that people will try to drag the knots + // on top of each other, so block it + + if (flexible) { + if (double(unsigned(attach_startv[index])) > 100.0) { + attach_startv[index] = 100.0; + } + if (double(unsigned(attach_endv[index])) > 100.0) { + attach_endv[index] = 100.0; + } + unsigned allowed_start = 100.0; + unsigned allowed_end = 100.0; + + // don't let the knots be farther than they are allowed to be + { + if ((unsigned)attach_startv[index] >= allowed_start) { + attach_startv[index] = ((double)allowed_start); + } + if ((unsigned)attach_endv[index] >= allowed_end) { + attach_endv[index] = ((double)allowed_end); + } + } + } + + + Geom::Path path_tmp; + // Calculate length + double start_path_length; + double end_path_length; + if (flexible) { + start_path_length = (attach_startv[index] * path_length) / 100.0; + end_path_length = (attach_endv[index] * path_length) / 100.0; + } else { + start_path_length = std::min(path_length,attach_startv[index]); + end_path_length = std::min(path_length,attach_endv[index]); + } + // get positions + Geom::Coord new_pos_start = timeAtLength(start_path_length,first_cusp_pwd2); + Geom::Coord new_pos_end = timeAtLength(end_path_length,last_cusp_pwd2); + start_attach_point.push_back(first_cusp(new_pos_start)); + end_attach_point.push_back(last_cusp(new_pos_end)); + // do portioned + path_tmp = doEffect_simplePath(path, new_pos_start, new_pos_end); + pathv_out.push_back(path_tmp); + index++; + } + if (this != first) { // if LPE is not the first one add it to allow staking + for (auto path : pathvector_before_effect) { + pathv_out.push_back(path); + } + } + attach_startv.clear(); + attach_endv.clear(); +} + +Geom::PathVector +LPETrimShape::doEffect_path(Geom::PathVector const &path_in) +{ + return pathv_out; +} + +void LPETrimShape::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item) +{ + for (size_t i = 0 ; i < attach_start._vector.size(); i++) { + KnotHolderEntity *e = new TrimShapeNS::KnotHolderEntityAttach(this, i, true); + e->create(nullptr, item, knotholder, Inkscape::CANVAS_ITEM_CTRL_TYPE_LPE, "LPE:TrimShapeBegin", + _("Start point of the trim: drag to alter the trim")); + knotholder->add(e); + + KnotHolderEntity *f = new TrimShapeNS::KnotHolderEntityAttach(this, i, false); + f->create(nullptr, item, knotholder, Inkscape::CANVAS_ITEM_CTRL_TYPE_LPE, "LPE:TrimShapeEnd", + _("End point of the trim: drag to alter the trim")); + knotholder->add(f); + } +} + +namespace TrimShapeNS { + +void KnotHolderEntityAttach::knot_set(Geom::Point const &p, Geom::Point const&/*origin*/, guint state) +{ + using namespace Geom; + // check is valid index + if (_begin && (!valid_index(_index) || _effect->start_attach_point.size() <= _index)) { + return; + } + + if (!_begin && (!valid_index(_index) || _effect->end_attach_point.size() <= _index)) { + return; + } + + Geom::Point const s = snap_knot_position(p, state); + + if (!is(_effect->sp_lpe_item)) { + g_warning("LPEItem is not a path!"); + return; + } + + if (!cast_unsafe(_effect->sp_lpe_item)->curve()) { + // oops + return; + } + // in case you are wondering, the above are simply sanity checks. we never want to actually + // use that object. + + Geom::PathVector pathv = _effect->_pathvector_before_effect; + Piecewise > pwd2; + Geom::Path p_in; + if (_begin) { + p_in = pathv[_index]; + } else { + p_in = pathv[_index].reversed(); + } + // calculate lenght + Geom::Coord path_length = p_in.length(); + pwd2.concat(p_in.toPwSb()); + double t0 = nearest_time(s, pwd2); + // if the position is not very near to start or end + if (!Geom::are_near(0,t0,0.01)) { + // get the removed portion to measure + Geom::Path p_in_port = p_in.portion(0,t0); + Geom::Coord length = p_in_port.length(); + if (_effect->flexible) { + t0 = (length * 100.0) / path_length; + } else { + t0 = length; + } + } else { + t0 = 0; + } + // if link all we use current subpath to + size_t pos = _index; + if (_effect->linkall) { + pos = _effect->subpath - 1; + } + if (_begin) { + _effect->attach_start._vector[pos] = t0; + _effect->attach_start.write_to_SVG(); + } else { + _effect->attach_end._vector[pos] = t0; + _effect->attach_end.write_to_SVG(); + } +} + +void KnotHolderEntityAttach::knot_ungrabbed(Geom::Point const &p, Geom::Point const &origin, unsigned state) +{ + LPETrimShape *lpe = dynamic_cast(_effect); + lpe->makeUndoDone(_("Move handle")); + sp_lpe_item_update_patheffect(cast(item), false, false); +} + +Geom::Point KnotHolderEntityAttach::knot_get() const +{ + if (!valid_index(_index)) { + return Geom::Point(); + } + if (_begin && _effect && _effect->start_attach_point.size() > _index) { + return _effect->start_attach_point[_index]; + } + if (!_begin && _effect && _effect->end_attach_point.size() > _index) { + return _effect->end_attach_point[_index]; + } + return Geom::Point(); +} + +} // namespace TrimShapeNS +} // namespace LivePathEffect +} // namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offset:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/live_effects/lpe-trim-shape.h b/src/live_effects/lpe-trim-shape.h new file mode 100644 index 0000000000000000000000000000000000000000..13d5228851a68842a9409269de607994a95c0f04 --- /dev/null +++ b/src/live_effects/lpe-trim-shape.h @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Author(s): + * Jabiertxo Arraiza Cenoz + * + * Copyright (C) 2014 Author(s) + * + * Jabiertxof:Thanks to all people help me + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#ifndef INKSCAPE_LPE_TRIM_SHAPE_H +#define INKSCAPE_LPE_TRIM_SHAPE_H + +#include "live_effects/effect.h" +#include "live_effects/parameter/enum.h" +#include "live_effects/parameter/enumarray.h" +#include "live_effects/parameter/scalararray.h" +#include "live_effects/parameter/parameter.h" + +namespace Inkscape { +namespace LivePathEffect { + +namespace TrimShapeNS { +// we need a separate namespace to avoid clashes with other LPEs +// we use TrimShapeNS to follow similar usage in tapper stroke +class KnotHolderEntityAttach; +} + +class LPETrimShape : public Effect { +public: + LPETrimShape(LivePathEffectObject *lpeobject); + ~LPETrimShape() override; + + void doOnApply(SPLPEItem const* lpeitem) override; + void doBeforeEffect (SPLPEItem const* lpeitem) override; + Geom::PathVector doEffect_path (Geom::PathVector const& path_in) override; + Geom::Path doEffect_simplePath(Geom::Path const& path, double start, double end); + + void addKnotHolderEntities(KnotHolder * knotholder, SPItem * item) override; +protected: + friend class TrimShapeNS::KnotHolderEntityAttach; + ScalarArrayParam attach_start; + ScalarArrayParam attach_end; +private: + ScalarParam subpath; + BoolParam linkall; + BoolParam flexible; + size_t previous_size = 0; + bool prevflex = false; + double prev_attach_start = -1; + double prev_attach_end = -1; + std::vector start_attach_point; + std::vector end_attach_point; + Geom::PathTime _factorTime(Geom::Path const path,Geom::Coord t) const; + double timeAtLength(double const A, Geom::Piecewise> pwd2); + size_t prev_subpath = Glib::ustring::npos; + Geom::PathVector _pathvector_before_effect; + Geom::PathVector pathv_out; + LPETrimShape(const LPETrimShape&) = delete; + LPETrimShape& operator=(const LPETrimShape&) = delete; +}; + +} //namespace LivePathEffect +} //namespace Inkscape + +#endif + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8 : + diff --git a/src/live_effects/parameter/array.h b/src/live_effects/parameter/array.h index dc262fedbede2b7529814068206d76a5e1dc99b1..59d2cfaa3c272c29ce6803ea086654593b7cc2be 100644 --- a/src/live_effects/parameter/array.h +++ b/src/live_effects/parameter/array.h @@ -23,11 +23,16 @@ namespace Inkscape::LivePathEffect { -namespace TpS { +namespace TapperStrokeNS { // we need a separate namespace to avoid clashes with other LPEs class KnotHolderEntityAttachBegin; class KnotHolderEntityAttachEnd; -} // namespace TpS +} // namespace TapperStrokeNS + +namespace TrimShapeNS { +// we need a separate namespace to avoid clashes with other LPEs +class KnotHolderEntityAttach; +} // namespace TrimShapeNS template class ArrayParam : public Parameter { @@ -99,8 +104,9 @@ public: bool valid_index(int index) const { return _vector.size() > index; } protected: - friend class TpS::KnotHolderEntityAttachBegin; - friend class TpS::KnotHolderEntityAttachEnd; + friend class TapperStrokeNS::KnotHolderEntityAttachBegin; + friend class TapperStrokeNS::KnotHolderEntityAttachEnd; + friend class TrimShapeNS::KnotHolderEntityAttach; std::vector _vector; std::size_t _default_size; diff --git a/src/live_effects/parameter/enumarray.h b/src/live_effects/parameter/enumarray.h index 7a1069bb1201c52efd4bd4e2da7113f56ea740c3..84795a46534e318d1be5bbc6297ba5bbaabe61f4 100644 --- a/src/live_effects/parameter/enumarray.h +++ b/src/live_effects/parameter/enumarray.h @@ -94,6 +94,7 @@ public: protected: friend class LPETaperStroke; + friend class LPETrimShape; private: size_t _active_index = 0; diff --git a/src/live_effects/parameter/scalararray.h b/src/live_effects/parameter/scalararray.h index 33a3265600a90633e6e3d8e956950dd2e6530483..413aef001319c18bb4b4641fbd0e95d840154038 100644 --- a/src/live_effects/parameter/scalararray.h +++ b/src/live_effects/parameter/scalararray.h @@ -58,6 +58,7 @@ public: private: friend class LPETaperStroke; + friend class LPETrimShape; size_t _active_index = 0; double min;