summaryrefslogtreecommitdiffstats
path: root/src/live_effects/lpe-fill-between-many.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/live_effects/lpe-fill-between-many.cpp303
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 :