diff options
Diffstat (limited to 'src/path/path-object-set.cpp')
-rw-r--r-- | src/path/path-object-set.cpp | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/src/path/path-object-set.cpp b/src/path/path-object-set.cpp new file mode 100644 index 0000000..f5d0770 --- /dev/null +++ b/src/path/path-object-set.cpp @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/** @file + * + * Path related functions for ObjectSet. + * + * Copyright (C) 2020 Tavmjong Bah + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + * + * TODO: Move related code from path-chemistry.cpp + * + */ + +#include <glibmm/i18n.h> + +#include "document-undo.h" +#include "message-stack.h" + +#include "attribute-rel-util.h" + +#include "object/object-set.h" +#include "path/path-outline.h" +#include "path/path-simplify.h" +#include "ui/icon-names.h" + +using Inkscape::ObjectSet; + +bool +ObjectSet::strokesToPaths(bool legacy, bool skip_undo) +{ + if (desktop() && isEmpty()) { + desktop()->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>stroked path(s)</b> to convert stroke to path.")); + return false; + } + + bool did = false; + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (prefs->getBool("/options/pathoperationsunlink/value", true)) { + did = unlinkRecursive(true); + } + + // Need to turn on stroke scaling to ensure stroke is scaled when transformed! + bool scale_stroke = prefs->getBool("/options/transform/stroke", true); + prefs->setBool("/options/transform/stroke", true); + + + std::vector<SPItem *> my_items(items().begin(), items().end()); + + for (auto item : my_items) { + // Do not remove the object from the selection here + // as we want to keep it selected if the whole operation fails + Inkscape::XML::Node *new_node = item_to_paths(item, legacy); + if (new_node) { + SPObject* new_item = document()->getObjectByRepr(new_node); + + // Markers don't inherit properties from outside the + // marker. When converted to paths objects they need to be + // protected from inheritance. This is why (probably) the stroke + // to path code uses SP_STYLE_FLAG_ALWAYS when defining the + // style of the fill and stroke during the conversion. This + // means the style contains every possible property. Once we've + // finished the stroke to path conversion, we can eliminate + // unneeded properties from the style element. + sp_attribute_clean_recursive(new_node, SP_ATTRCLEAN_STYLE_REMOVE | SP_ATTRCLEAN_DEFAULT_REMOVE); + + add(new_item); // Add to selection. + did = true; + } + } + + // Reset + prefs->setBool("/options/transform/stroke", scale_stroke); + + if (desktop() && !did) { + desktop()->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No stroked paths</b> in the selection.")); + } + + if (did && !skip_undo) { + Inkscape::DocumentUndo::done(document(), _("Convert stroke to path"), ""); + } else if (!did && !skip_undo) { + Inkscape::DocumentUndo::cancel(document()); + } + + return did; +} + +bool +ObjectSet::simplifyPaths(bool skip_undo) +{ + if (desktop() && isEmpty()) { + desktop()->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>path(s)</b> to simplify.")); + return false; + } + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + double threshold = prefs->getDouble("/options/simplifythreshold/value", 0.003); + bool justCoalesce = prefs->getBool( "/options/simplifyjustcoalesce/value", false); + + // Keep track of accelerated simplify + static gint64 previous_time = 0; + static gdouble multiply = 1.0; + + // Get the current time + gint64 current_time = g_get_monotonic_time(); + + // Was the previous call to this function recent? (<0.5 sec) + if (previous_time > 0 && current_time - previous_time < 500000) { + + // add to the threshold 1/2 of its original value + multiply += 0.5; + threshold *= multiply; + + } else { + // reset to the default + multiply = 1; + } + + // Remember time for next call + previous_time = current_time; + + // set "busy" cursor + if (desktop()) { + desktop()->setWaitingCursor(); + } + + Geom::OptRect selectionBbox = visualBounds(); + if (!selectionBbox) { + std::cerr << "ObjectSet::: selection has no visual bounding box!" << std::endl; + return false; + } + double size = L2(selectionBbox->dimensions()); + + int pathsSimplified = 0; + std::vector<SPItem *> my_items(items().begin(), items().end()); + for (auto item : my_items) { + pathsSimplified += path_simplify(item, threshold, justCoalesce, size); + } + + if (pathsSimplified > 0 && !skip_undo) { + DocumentUndo::done(document(), _("Simplify"), INKSCAPE_ICON("path-simplify")); + } + + if (desktop()) { + desktop()->clearWaitingCursor(); + if (pathsSimplified > 0) { + desktop()->messageStack()->flashF(Inkscape::NORMAL_MESSAGE, _("<b>%d</b> paths simplified."), pathsSimplified); + } else { + desktop()->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No paths</b> to simplify in the selection.")); + } + } + + return (pathsSimplified > 0); +} + +/* + 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:textwidth=99 : |