diff options
Diffstat (limited to '')
-rw-r--r-- | src/live_effects/lpe-fill-between-many.cpp | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/src/live_effects/lpe-fill-between-many.cpp b/src/live_effects/lpe-fill-between-many.cpp new file mode 100644 index 0000000..cc44464 --- /dev/null +++ b/src/live_effects/lpe-fill-between-many.cpp @@ -0,0 +1,303 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) Theodore Janeczko 2012 <flutterguy317@gmail.com> + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + + +#include "live_effects/lpe-fill-between-many.h" +#include "live_effects/lpeobject.h" +#include "xml/node.h" +#include "display/curve.h" +#include "inkscape.h" +#include "selection.h" + +#include "object/sp-defs.h" +#include "object/sp-root.h" +#include "object/sp-shape.h" +#include "svg/svg.h" + +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> + +namespace Inkscape { +namespace LivePathEffect { + +static const Util::EnumData<Filllpemethod> FilllpemethodData[] = { + { FLM_ORIGINALD, N_("Without LPEs"), "originald" }, + { FLM_BSPLINESPIRO, N_("With Spiro or BSpline"), "bsplinespiro" }, + { FLM_D, N_("With all LPEs"), "d" } +}; +static const Util::EnumDataConverter<Filllpemethod> FLMConverter(FilllpemethodData, FLM_END); + +LPEFillBetweenMany::LPEFillBetweenMany(LivePathEffectObject *lpeobject) + : Effect(lpeobject) + , linked_paths(_("Linked path:"), _("Paths from which to take the original path data"), "linkedpaths", &wr, this) + , method(_("LPEs:"), _("Which LPEs of the linked paths should be considered"), "method", FLMConverter, &wr, this, FLM_BSPLINESPIRO) + , join(_("Join subpaths"), _("Join subpaths"), "join", &wr, this, true) + , close(_("Close"), _("Close path"), "close", &wr, this, true) + , autoreverse(_("Autoreverse"), _("Autoreverse"), "autoreverse", &wr, this, true) +{ + registerParameter(&linked_paths); + registerParameter(&method); + registerParameter(&join); + registerParameter(&close); + registerParameter(&autoreverse); + previous_method = FLM_END; + linked_paths.setUpdating(true); +} + +LPEFillBetweenMany::~LPEFillBetweenMany() += default; + +void +LPEFillBetweenMany::doOnApply(SPLPEItem const* lpeitem) +{ + lpeversion.param_setValue("1.2", true); +} + +bool +LPEFillBetweenMany::doOnOpen(SPLPEItem const *lpeitem) +{ + if (!is_load || is_applied) { + return false; + } + + linked_paths.setUpdating(false); + linked_paths.start_listening(); + linked_paths.connect_selection_changed(); + std::vector<SPLPEItem *> lpeitems = getCurrrentLPEItems(); + if (lpeitems.size() == 1) { + sp_lpe_item = lpeitems[0]; + prevaffine = i2anc_affine(sp_lpe_item, sp_lpe_item->document->getRoot()); + } + return false; +} + +void +LPEFillBetweenMany::doBeforeEffect (SPLPEItem const* lpeitem) +{ + legacytest = false; + std::vector<SPLPEItem *> lpeitems = getCurrrentLPEItems(); + if (lpeitems.size() == 1) { + sp_lpe_item = lpeitems[0]; + } + if (!is_load) { + transform_multiply_nested(i2anc_affine(sp_lpe_item, sp_lpe_item->document->getRoot()).inverse() * prevaffine); + prevaffine = i2anc_affine(sp_lpe_item, sp_lpe_item->document->getRoot()); + } else { + linked_paths.setUpdating(false); + linked_paths.start_listening(); + linked_paths.connect_selection_changed(); + } + Glib::ustring version = lpeversion.param_getSVGValue(); + if (version < "1.2") { + legacytest = true; + } +} + +void +LPEFillBetweenMany::transform_multiply_nested(Geom::Affine const &postmul) +{ + if (is_visible && sp_lpe_item->pathEffectsEnabled() && !isOnClipboard() && !postmul.isIdentity()) { + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + Inkscape::Selection *selection = nullptr; + if (desktop) { + selection = desktop->selection; + } + std::vector<SPLPEItem *> lpeitems = getCurrrentLPEItems(); + if (lpeitems.size() == 1) { + sp_lpe_item = lpeitems[0]; + } + for (auto & iter : linked_paths._vector) { + SPItem *item; + if (iter->ref.isAttached() && (( item = dynamic_cast<SPItem*>(iter->ref.getObject()) )) && + !iter->_pathvector.empty() && iter->visibled) { + if (iter->_pathvector.front().closed() && linked_paths._vector.size() > 1) { + continue; + } + if (selection && !selection->includes(item, true) && selection->includes(sp_lpe_item, true)) { + item->transform *= i2anc_affine(item->parent, item->document->getRoot()); + item->transform *= postmul.inverse(); + item->transform *= i2anc_affine(item->parent, item->document->getRoot()).inverse(); + item->doWriteTransform(item->transform, nullptr, false); + item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + } + } + } + } +} + +void +LPEFillBetweenMany::doEffect (SPCurve * curve) +{ + if (previous_method != method) { + if (method == FLM_BSPLINESPIRO) { + linked_paths.allowOnlyBsplineSpiro(true); + linked_paths.setFromOriginalD(false); + } else if(method == FLM_ORIGINALD) { + linked_paths.allowOnlyBsplineSpiro(false); + linked_paths.setFromOriginalD(true); + } else { + linked_paths.allowOnlyBsplineSpiro(false); + linked_paths.setFromOriginalD(false); + } + previous_method = method; + } + Geom::PathVector res_pathv; + if (!autoreverse) { + for (auto & iter : linked_paths._vector) { + SPItem *item; + if (iter->ref.isAttached() && (( item = dynamic_cast<SPItem*>(iter->ref.getObject()) )) && + !iter->_pathvector.empty() && iter->visibled) { + Geom::Path linked_path; + if (iter->_pathvector.front().closed() && linked_paths._vector.size() > 1) { + continue; + } + if (iter->reversed) { + linked_path = iter->_pathvector.front().reversed(); + } else { + linked_path = iter->_pathvector.front(); + } + linked_path *= item->getRelativeTransform(sp_lpe_item); + if (!res_pathv.empty() && join) { + if (!are_near(res_pathv.front().finalPoint(), linked_path.initialPoint(), 0.1)) { + res_pathv.front().appendNew<Geom::LineSegment>(linked_path.initialPoint()); + } else { + linked_path.setInitial(res_pathv.front().finalPoint()); + } + res_pathv.front().append(linked_path); + } else { + if (close && !join) { + linked_path.close(); + } + res_pathv.push_back(linked_path); + } + } + } + } else { + unsigned int counter = 0; + Geom::Point current = Geom::Point(); + counter = 0; + std::vector<unsigned int> done; + for (auto & iter : linked_paths._vector) { + SPItem *item; + if (iter->ref.isAttached() && (( item = dynamic_cast<SPItem*>(iter->ref.getObject()) )) && + !iter->_pathvector.empty() && iter->visibled) { + Geom::Path linked_path; + if (iter->_pathvector.front().closed() && linked_paths._vector.size() > 1) { + counter++; + continue; + } + if (counter == 0) { + Geom::Path initial_path = iter->_pathvector.front(); + if (!legacytest && iter->reversed) { + initial_path = initial_path.reversed(); + } + done.push_back(0); + if (close && !join) { + initial_path.close(); + } + initial_path *= item->getRelativeTransform(sp_lpe_item); + res_pathv.push_back(initial_path); + current = res_pathv.front().finalPoint(); + } + Geom::Coord distance = Geom::infinity(); + unsigned int counter2 = 0; + unsigned int added = 0; + PathAndDirectionAndVisible *nearest = nullptr; + for (auto & iter2 : linked_paths._vector) { + SPItem *item2; + if (iter2->ref.isAttached() && (( item2 = dynamic_cast<SPItem*>(iter2->ref.getObject()) )) && + !iter2->_pathvector.empty() && iter2->visibled) { + if (item == item2 || std::find(done.begin(), done.end(), counter2) != done.end()) { + counter2++; + continue; + } + if (iter2->_pathvector.front().closed() && linked_paths._vector.size() > 1) { + counter2++; + continue; + } + Geom::Point start = iter2->_pathvector.front().initialPoint(); + Geom::Point end = iter2->_pathvector.front().finalPoint(); + if (!legacytest && iter2->reversed) { + std::swap(start,end); + } + if (!legacytest) { + current = res_pathv.finalPoint(); + } + Geom::Coord distance_iter = + std::min(Geom::distance(current, end), Geom::distance(current, start)); + if (distance > distance_iter) { + distance = distance_iter; + nearest = iter2; + added = counter2; + } + counter2++; + } + } + if (nearest != nullptr) { + done.push_back(added); + Geom::Point start = nearest->_pathvector.front().initialPoint(); + Geom::Point end = nearest->_pathvector.front().finalPoint(); + if (!legacytest && nearest->reversed) { + linked_path = iter->_pathvector.front().reversed(); + std::swap(start,end); + } else { + linked_path = iter->_pathvector.front(); + } + if (Geom::distance(current, end) > Geom::distance(current, start)) { + linked_path = nearest->_pathvector.front(); + } else { + linked_path = nearest->_pathvector.front().reversed(); + } + + if (legacytest) { + current = end; + } + SPItem *itemnear; + if (nearest->ref.isAttached() && (( itemnear = dynamic_cast<SPItem*>(nearest->ref.getObject()) ))) { + linked_path *= itemnear->getRelativeTransform(sp_lpe_item); + } + if (!res_pathv.empty() && join) { + if (!are_near(res_pathv.front().finalPoint(), linked_path.initialPoint(), 0.1)) { + res_pathv.front().appendNew<Geom::LineSegment>(linked_path.initialPoint()); + } else { + linked_path.setInitial(res_pathv.front().finalPoint()); + } + res_pathv.front().append(linked_path); + } else { + if (close && !join) { + linked_path.close(); + } + res_pathv.push_back(linked_path); + } + } + counter++; + } + } + } + if (!res_pathv.empty() && close) { + res_pathv.front().close(); + res_pathv.front().snapEnds(0.1); + } + if (res_pathv.empty()) { + res_pathv = curve->get_pathvector(); + } + curve->set_pathvector(res_pathv); +} + +} // namespace LivePathEffect +} /* namespace Inkscape */ + +/* + 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 : |