summaryrefslogtreecommitdiffstats
path: root/src/live_effects/lpe-mirror_symmetry.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:29:01 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:29:01 +0000
commit35a96bde514a8897f6f0fcc41c5833bf63df2e2a (patch)
tree657d15a03cc46bd099fc2c6546a7a4ad43815d9f /src/live_effects/lpe-mirror_symmetry.cpp
parentInitial commit. (diff)
downloadinkscape-35a96bde514a8897f6f0fcc41c5833bf63df2e2a.tar.xz
inkscape-35a96bde514a8897f6f0fcc41c5833bf63df2e2a.zip
Adding upstream version 1.0.2.upstream/1.0.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/live_effects/lpe-mirror_symmetry.cpp')
-rw-r--r--src/live_effects/lpe-mirror_symmetry.cpp606
1 files changed, 606 insertions, 0 deletions
diff --git a/src/live_effects/lpe-mirror_symmetry.cpp b/src/live_effects/lpe-mirror_symmetry.cpp
new file mode 100644
index 0000000..d72eaf9
--- /dev/null
+++ b/src/live_effects/lpe-mirror_symmetry.cpp
@@ -0,0 +1,606 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * LPE <mirror_symmetry> implementation: mirrors a path with respect to a given line.
+ */
+/*
+ * Authors:
+ * Maximilian Albert
+ * Johan Engelen
+ * Abhishek Sharma
+ * Jabiertxof
+ *
+ * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
+ * Copyright (C) Maximilin Albert 2008 <maximilian.albert@gmail.com>
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "live_effects/lpe-mirror_symmetry.h"
+#include "2geom/affine.h"
+#include "2geom/path-intersection.h"
+#include "display/curve.h"
+#include "helper/geom.h"
+#include "path-chemistry.h"
+#include "style.h"
+#include "svg/path-string.h"
+#include "svg/svg.h"
+#include <gtkmm.h>
+
+#include "object/sp-defs.h"
+#include "object/sp-lpe-item.h"
+#include "object/sp-path.h"
+#include "object/sp-text.h"
+
+#include "xml/sp-css-attr.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<ModeType> ModeTypeData[] = {
+ { MT_V, N_("Vertical page center"), "vertical" },
+ { MT_H, N_("Horizontal page center"), "horizontal" },
+ { MT_FREE, N_("Freely defined mirror line"), "free" },
+ { MT_X, N_("X coordinate of mirror line midpoint"), "X" },
+ { MT_Y, N_("Y coordinate of mirror line midpoint"), "Y" }
+};
+static const Util::EnumDataConverter<ModeType>
+MTConverter(ModeTypeData, MT_END);
+
+
+LPEMirrorSymmetry::LPEMirrorSymmetry(LivePathEffectObject *lpeobject) :
+ Effect(lpeobject),
+ mode(_("Mode"), _("Set mode of transformation. Either freely defined by mirror line or constrained to certain symmetry points."), "mode", MTConverter, &wr, this, MT_FREE),
+ discard_orig_path(_("Discard original path"), _("Only keep mirrored part of the path, remove the original."), "discard_orig_path", &wr, this, false),
+ fuse_paths(_("Fuse paths"), _("Fuse original path and mirror image into a single path"), "fuse_paths", &wr, this, false),
+ oposite_fuse(_("Fuse opposite sides"), _("Picks the part on the other side of the mirror line as the original."), "oposite_fuse", &wr, this, false),
+ split_items(_("Split elements"), _("Split original and mirror image into separate paths, so each can have its own style."), "split_items", &wr, this, false),
+ start_point(_("Mirror line start"), _("Start point of mirror line"), "start_point", &wr, this, _("Adjust start point of of mirror line")),
+ end_point(_("Mirror line end"), _("End point of mirror line"), "end_point", &wr, this, _("Adjust end point of mirror line")),
+ center_point(_("Mirror line mid"), _("Center point of mirror line"), "center_point", &wr, this, _("Adjust center point of mirror line"))
+{
+ show_orig_path = true;
+ registerParameter(&mode);
+ registerParameter(&discard_orig_path);
+ registerParameter(&fuse_paths);
+ registerParameter(&oposite_fuse);
+ registerParameter(&split_items);
+ registerParameter(&start_point);
+ registerParameter(&end_point);
+ registerParameter(&center_point);
+ apply_to_clippath_and_mask = true;
+ previous_center = Geom::Point(0,0);
+ center_point.param_widget_is_visible(false);
+ reset = false;
+ center_horiz = false;
+ center_vert = false;
+}
+
+LPEMirrorSymmetry::~LPEMirrorSymmetry()
+= default;
+
+void
+LPEMirrorSymmetry::doAfterEffect (SPLPEItem const* lpeitem)
+{
+ SPDocument *document = getSPDoc();
+ if (!document) {
+ return;
+ }
+ container = dynamic_cast<SPObject *>(sp_lpe_item->parent);
+ Inkscape::XML::Node *root = document->getReprRoot();
+
+ if (split_items && !discard_orig_path) {
+ Geom::Line ls((Geom::Point)start_point, (Geom::Point)end_point);
+ Geom::Affine m = Geom::reflection (ls.vector(), (Geom::Point)start_point);
+ m *= sp_lpe_item->transform;
+ toMirror(m, reset);
+ reset = false;
+ } else {
+ processObjects(LPE_ERASE);
+ items.clear();
+ }
+}
+
+Gtk::Widget *
+LPEMirrorSymmetry::newWidget()
+{
+ // use manage here, because after deletion of Effect object, others might
+ // still be pointing to this widget.
+ Gtk::VBox *vbox = Gtk::manage(new Gtk::VBox(Effect::newWidget()));
+
+ vbox->set_border_width(5);
+ vbox->set_homogeneous(false);
+ vbox->set_spacing(2);
+ std::vector<Parameter *>::iterator it = param_vector.begin();
+ while (it != param_vector.end()) {
+ if ((*it)->widget_is_visible) {
+ Parameter *param = *it;
+ Gtk::Widget *widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget());
+ Glib::ustring *tip = param->param_getTooltip();
+ if (widg) {
+ vbox->pack_start(*widg, true, true, 2);
+ if (tip) {
+ widg->set_tooltip_text(*tip);
+ } else {
+ widg->set_tooltip_text("");
+ widg->set_has_tooltip(false);
+ }
+ }
+ }
+
+ ++it;
+ }
+ Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false,0));
+ Gtk::HBox * hbox2 = Gtk::manage(new Gtk::HBox(false,0));
+ Gtk::Button * center_vert_button = Gtk::manage(new Gtk::Button(Glib::ustring(_("Vertical center"))));
+ center_vert_button->signal_clicked().connect(sigc::mem_fun (*this,&LPEMirrorSymmetry::centerVert));
+ center_vert_button->set_size_request(110,20);
+ Gtk::Button * center_horiz_button = Gtk::manage(new Gtk::Button(Glib::ustring(_("Horizontal center"))));
+ center_horiz_button->signal_clicked().connect(sigc::mem_fun (*this,&LPEMirrorSymmetry::centerHoriz));
+ center_horiz_button->set_size_request(110,20);
+ Gtk::Button * reset_button = Gtk::manage(new Gtk::Button(Glib::ustring(_("Reset styles"))));
+ reset_button->signal_clicked().connect(sigc::mem_fun (*this,&LPEMirrorSymmetry::resetStyles));
+ reset_button->set_size_request(110,20);
+ vbox->pack_start(*hbox, true,true,2);
+ vbox->pack_start(*hbox2, true,true,2);
+ hbox->pack_start(*reset_button, false, false,2);
+ hbox2->pack_start(*center_vert_button, false, false,2);
+ hbox2->pack_start(*center_horiz_button, false, false,2);
+ if(Gtk::Widget* widg = defaultParamSet()) {
+ vbox->pack_start(*widg, true, true, 2);
+ }
+ return dynamic_cast<Gtk::Widget *>(vbox);
+}
+
+void
+LPEMirrorSymmetry::centerVert(){
+ center_vert = true;
+ refresh_widgets = true;
+ writeParamsToSVG();
+}
+
+void
+LPEMirrorSymmetry::centerHoriz(){
+ center_horiz = true;
+ refresh_widgets = true;
+ writeParamsToSVG();
+}
+
+void
+LPEMirrorSymmetry::doBeforeEffect (SPLPEItem const* lpeitem)
+{
+ using namespace Geom;
+ original_bbox(lpeitem, false, true);
+ Point point_a(boundingbox_X.max(), boundingbox_Y.min());
+ Point point_b(boundingbox_X.max(), boundingbox_Y.max());
+ Point point_c(boundingbox_X.middle(), boundingbox_Y.middle());
+ if (center_vert) {
+ center_point.param_setValue(point_c);
+ end_point.param_setValue(Geom::Point(boundingbox_X.middle(), boundingbox_Y.min()));
+ //force update
+ start_point.param_setValue(Geom::Point(boundingbox_X.middle(), boundingbox_Y.max()),true);
+ center_vert = false;
+ } else if (center_horiz) {
+ center_point.param_setValue(point_c);
+ end_point.param_setValue(Geom::Point(boundingbox_X.max(), boundingbox_Y.middle()));
+ start_point.param_setValue(Geom::Point(boundingbox_X.min(), boundingbox_Y.middle()),true);
+ //force update
+ center_horiz = false;
+ } else {
+
+ if (mode == MT_Y) {
+ point_a = Geom::Point(boundingbox_X.min(),center_point[Y]);
+ point_b = Geom::Point(boundingbox_X.max(),center_point[Y]);
+ }
+ if (mode == MT_X) {
+ point_a = Geom::Point(center_point[X],boundingbox_Y.min());
+ point_b = Geom::Point(center_point[X],boundingbox_Y.max());
+ }
+ if ((Geom::Point)start_point == (Geom::Point)end_point) {
+ start_point.param_setValue(point_a);
+ end_point.param_setValue(point_b);
+ previous_center = Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point);
+ center_point.param_setValue(previous_center);
+ return;
+ }
+ if ( mode == MT_X || mode == MT_Y ) {
+ if (!are_near(previous_center, (Geom::Point)center_point, 0.01)) {
+ center_point.param_setValue(Geom::middle_point(point_a, point_b));
+ end_point.param_setValue(point_b);
+ start_point.param_setValue(point_a);
+ } else {
+ if ( mode == MT_X ) {
+ if (!are_near(start_point[X], point_a[X], 0.01)) {
+ start_point.param_setValue(point_a);
+ }
+ if (!are_near(end_point[X], point_b[X], 0.01)) {
+ end_point.param_setValue(point_b);
+ }
+ } else { //MT_Y
+ if (!are_near(start_point[Y], point_a[Y], 0.01)) {
+ start_point.param_setValue(point_a);
+ }
+ if (!are_near(end_point[Y], point_b[Y], 0.01)) {
+ end_point.param_setValue(point_b);
+ }
+ }
+ }
+ } else if ( mode == MT_FREE) {
+ if (are_near(previous_center, (Geom::Point)center_point, 0.01)) {
+ center_point.param_setValue(Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point));
+
+ } else {
+ Geom::Point trans = center_point - Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point);
+ start_point.param_setValue(start_point * trans);
+ end_point.param_setValue(end_point * trans);
+ }
+ } else if ( mode == MT_V){
+ SPDocument *document = getSPDoc();
+ if (document) {
+ Geom::Affine transform = i2anc_affine(SP_OBJECT(lpeitem), nullptr).inverse();
+ Geom::Point sp = Geom::Point(document->getWidth().value("px")/2.0, 0) * transform;
+ start_point.param_setValue(sp);
+ Geom::Point ep = Geom::Point(document->getWidth().value("px")/2.0, document->getHeight().value("px")) * transform;
+ end_point.param_setValue(ep);
+ center_point.param_setValue(Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point));
+ }
+ } else { //horizontal page
+ SPDocument *document = getSPDoc();
+ if (document) {
+ Geom::Affine transform = i2anc_affine(SP_OBJECT(lpeitem), nullptr).inverse();
+ Geom::Point sp = Geom::Point(0, document->getHeight().value("px")/2.0) * transform;
+ start_point.param_setValue(sp);
+ Geom::Point ep = Geom::Point(document->getWidth().value("px"), document->getHeight().value("px")/2.0) * transform;
+ end_point.param_setValue(ep);
+ center_point.param_setValue(Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point));
+ }
+ }
+ }
+ previous_center = center_point;
+}
+
+void LPEMirrorSymmetry::cloneStyle(SPObject *orig, SPObject *dest)
+{
+ dest->getRepr()->setAttribute("style", orig->getRepr()->attribute("style"));
+ for (auto iter : orig->style->properties()) {
+ if (iter->style_src != SP_STYLE_SRC_UNSET) {
+ auto key = iter->id();
+ if (key != SP_PROP_FONT && key != SP_ATTR_D && key != SP_PROP_MARKER) {
+ const gchar *attr = orig->getRepr()->attribute(iter->name().c_str());
+ if (attr) {
+ dest->getRepr()->setAttribute(iter->name(), attr);
+ }
+ }
+ }
+ }
+}
+
+void
+LPEMirrorSymmetry::cloneD(SPObject *orig, SPObject *dest, bool reset)
+{
+ SPDocument *document = getSPDoc();
+ if (!document) {
+ return;
+ }
+ Inkscape::XML::Document *xml_doc = document->getReprDoc();
+ if ( SP_IS_GROUP(orig) && SP_IS_GROUP(dest) && SP_GROUP(orig)->getItemCount() == SP_GROUP(dest)->getItemCount() ) {
+ if (reset) {
+ cloneStyle(orig, dest);
+ }
+ std::vector< SPObject * > childs = orig->childList(true);
+ size_t index = 0;
+ for (auto & child : childs) {
+ SPObject *dest_child = dest->nthChild(index);
+ cloneD(child, dest_child, reset);
+ index++;
+ }
+ return;
+ }
+
+ if (SP_IS_TEXT(orig) && SP_IS_TEXT(dest) && SP_TEXT(orig)->children.size() == SP_TEXT(dest)->children.size()) {
+ if (reset) {
+ cloneStyle(orig, dest);
+ }
+ size_t index = 0;
+ for (auto &child : SP_TEXT(orig)->children) {
+ SPObject *dest_child = dest->nthChild(index);
+ cloneD(&child, dest_child, reset);
+ index++;
+ }
+ }
+
+ SPShape * shape = SP_SHAPE(orig);
+ SPPath * path = SP_PATH(dest);
+ if (path && shape) {
+ SPCurve *c = shape->getCurve();
+ if (c) {
+ gchar *str = sp_svg_write_path(c->get_pathvector());
+ dest->getRepr()->setAttribute("d", str);
+ g_free(str);
+ c->unref();
+ } else {
+ dest->getRepr()->removeAttribute("d");
+ }
+ }
+ if (reset) {
+ cloneStyle(orig, dest);
+ }
+}
+
+Inkscape::XML::Node *
+LPEMirrorSymmetry::createPathBase(SPObject *elemref) {
+ SPDocument *document = getSPDoc();
+ if (!document) {
+ return nullptr;
+ }
+ Inkscape::XML::Document *xml_doc = document->getReprDoc();
+ Inkscape::XML::Node *prev = elemref->getRepr();
+ SPGroup *group = dynamic_cast<SPGroup *>(elemref);
+ if (group) {
+ Inkscape::XML::Node *container = xml_doc->createElement("svg:g");
+ container->setAttribute("transform", prev->attribute("transform"));
+ std::vector<SPItem*> const item_list = sp_item_group_item_list(group);
+ Inkscape::XML::Node *previous = nullptr;
+ for (auto sub_item : item_list) {
+ Inkscape::XML::Node *resultnode = createPathBase(sub_item);
+ container->addChild(resultnode, previous);
+ previous = resultnode;
+ }
+ return container;
+ }
+ Inkscape::XML::Node *resultnode = xml_doc->createElement("svg:path");
+ resultnode->setAttribute("transform", prev->attribute("transform"));
+ return resultnode;
+}
+
+void
+LPEMirrorSymmetry::toMirror(Geom::Affine transform, bool reset)
+{
+ SPDocument *document = getSPDoc();
+ if (!document) {
+ return;
+ }
+ Inkscape::XML::Document *xml_doc = document->getReprDoc();
+ Glib::ustring elemref_id = Glib::ustring("mirror-");
+ elemref_id += this->lpeobj->getId();
+ items.clear();
+ items.push_back(elemref_id);
+ SPObject *elemref = document->getObjectById(elemref_id.c_str());
+ Inkscape::XML::Node *phantom = nullptr;
+ if (elemref) {
+ phantom = elemref->getRepr();
+ } else {
+ phantom = createPathBase(sp_lpe_item);
+ phantom->setAttribute("id", elemref_id);
+ reset = true;
+ elemref = container->appendChildRepr(phantom);
+ Inkscape::GC::release(phantom);
+ }
+ cloneD(SP_OBJECT(sp_lpe_item), elemref, reset);
+ gchar *str = sp_svg_transform_write(transform);
+ elemref->getRepr()->setAttribute("transform" , str);
+ g_free(str);
+ if (elemref->parent != container) {
+ Inkscape::XML::Node *copy = phantom->duplicate(xml_doc);
+ copy->setAttribute("id", elemref_id);
+ container->appendChildRepr(copy);
+ Inkscape::GC::release(copy);
+ elemref->deleteObject();
+ }
+}
+
+
+void
+LPEMirrorSymmetry::resetStyles(){
+ reset = true;
+ doAfterEffect_impl(sp_lpe_item);
+}
+
+
+//TODO: Migrate the tree next function to effect.cpp/h to avoid duplication
+void
+LPEMirrorSymmetry::doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/)
+{
+ processObjects(LPE_VISIBILITY);
+}
+
+void
+LPEMirrorSymmetry::doOnRemove (SPLPEItem const* /*lpeitem*/)
+{
+ //set "keep paths" hook on sp-lpe-item.cpp
+ if (keep_paths) {
+ processObjects(LPE_TO_OBJECTS);
+ items.clear();
+ return;
+ }
+ processObjects(LPE_ERASE);
+}
+
+void
+LPEMirrorSymmetry::doOnApply (SPLPEItem const* lpeitem)
+{
+ using namespace Geom;
+
+ original_bbox(lpeitem, false, true);
+
+ Point point_a(boundingbox_X.max(), boundingbox_Y.min());
+ Point point_b(boundingbox_X.max(), boundingbox_Y.max());
+ Point point_c(boundingbox_X.max(), boundingbox_Y.middle());
+ start_point.param_setValue(point_a, true);
+ start_point.param_update_default(point_a);
+ end_point.param_setValue(point_b, true);
+ end_point.param_update_default(point_b);
+ center_point.param_setValue(point_c, true);
+ previous_center = center_point;
+ SPLPEItem * splpeitem = const_cast<SPLPEItem *>(lpeitem);
+}
+
+
+Geom::PathVector
+LPEMirrorSymmetry::doEffect_path (Geom::PathVector const & path_in)
+{
+ if (split_items && !fuse_paths) {
+ return path_in;
+ }
+ Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(path_in);
+ Geom::PathVector path_out;
+
+ if (!discard_orig_path && !fuse_paths) {
+ path_out = pathv_to_linear_and_cubic_beziers(path_in);
+ }
+
+ Geom::Line line_separation((Geom::Point)start_point, (Geom::Point)end_point);
+ Geom::Affine m = Geom::reflection (line_separation.vector(), (Geom::Point)start_point);
+ if (fuse_paths && !discard_orig_path) {
+ for (const auto & path_it : original_pathv)
+ {
+ if (path_it.empty()) {
+ continue;
+ }
+ Geom::PathVector tmp_pathvector;
+ double time_start = 0.0;
+ int position = 0;
+ bool end_open = false;
+ if (path_it.closed()) {
+ const Geom::Curve &closingline = path_it.back_closed();
+ if (!are_near(closingline.initialPoint(), closingline.finalPoint())) {
+ end_open = true;
+ }
+ }
+ Geom::Path original = path_it;
+ if (end_open && path_it.closed()) {
+ original.close(false);
+ original.appendNew<Geom::LineSegment>( original.initialPoint() );
+ original.close(true);
+ }
+ Geom::Point s = start_point;
+ Geom::Point e = end_point;
+ double dir = line_separation.angle();
+ double diagonal = Geom::distance(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max()));
+ Geom::Rect bbox(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max()));
+ double size_divider = Geom::distance(center_point, bbox) + diagonal;
+ s = Geom::Point::polar(dir,size_divider) + center_point;
+ e = Geom::Point::polar(dir + Geom::rad_from_deg(180),size_divider) + center_point;
+ Geom::Path divider = Geom::Path(s);
+ divider.appendNew<Geom::LineSegment>(e);
+ Geom::Crossings cs = crossings(original, divider);
+ std::vector<double> crossed;
+ for(auto & c : cs) {
+ crossed.push_back(c.ta);
+ }
+ std::sort(crossed.begin(), crossed.end());
+ bool swamped = false;
+ if (crossed.size()) {
+ swamped = crossed[0] > crossed[crossed.size() - 1];
+ }
+ for (unsigned int i = 0; i < crossed.size(); i++) {
+ double time_end = crossed[i];
+ if (time_start != time_end && time_end - time_start > Geom::EPSILON) {
+ Geom::Path portion = original.portion(time_start, time_end);
+ if (!portion.empty()) {
+ Geom::Point middle = portion.pointAt((double)portion.size()/2.0);
+ position = Geom::sgn(Geom::cross(e - s, middle - s));
+ if (!oposite_fuse) {
+ position *= -1;
+ }
+ if (position == 1) {
+ if (!split_items) {
+ Geom::Path mirror = portion.reversed() * m;
+ mirror.setInitial(portion.finalPoint());
+ portion.append(mirror);
+ if(i != 0) {
+ portion.setFinal(portion.initialPoint());
+ portion.close();
+ }
+ } else if (path_it.closed() && swamped) {
+ portion.close();
+ }
+ tmp_pathvector.push_back(portion);
+ }
+ portion.clear();
+ }
+ }
+ time_start = time_end;
+ }
+ position = Geom::sgn(Geom::cross(e - s, original.finalPoint() - s));
+ if (!oposite_fuse) {
+ position *= -1;
+ }
+ if (cs.size()!=0 && (position == 1)) {
+ if (time_start != original.size() && original.size() - time_start > Geom::EPSILON) {
+ Geom::Path portion = original.portion(time_start, original.size());
+ if (!portion.empty()) {
+ portion = portion.reversed();
+ if (!split_items) {
+ Geom::Path mirror = portion.reversed() * m;
+ mirror.setInitial(portion.finalPoint());
+ portion.append(mirror);
+ }
+ portion = portion.reversed();
+ if (!original.closed()) {
+ tmp_pathvector.push_back(portion);
+ } else {
+ if (cs.size() > 1 && tmp_pathvector.size() > 0 && tmp_pathvector[0].size() > 0 ) {
+ if (swamped || !split_items) {
+ portion.setFinal(tmp_pathvector[0].initialPoint());
+ portion.setInitial(tmp_pathvector[0].finalPoint());
+ } else {
+ tmp_pathvector[0] = tmp_pathvector[0].reversed();
+ portion = portion.reversed();
+ portion.setInitial(tmp_pathvector[0].finalPoint());
+ }
+ tmp_pathvector[0].append(portion);
+ } else {
+ tmp_pathvector.push_back(portion);
+ }
+ tmp_pathvector[0].close();
+ }
+ portion.clear();
+ }
+ }
+ }
+ if (cs.size() == 0 && position == 1) {
+ tmp_pathvector.push_back(original);
+ tmp_pathvector.push_back(original * m);
+ }
+ path_out.insert(path_out.end(), tmp_pathvector.begin(), tmp_pathvector.end());
+ tmp_pathvector.clear();
+ }
+ } else if (!fuse_paths || discard_orig_path) {
+ for (const auto & i : original_pathv) {
+ path_out.push_back(i * m);
+ }
+ }
+ return path_out;
+}
+
+void
+LPEMirrorSymmetry::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
+{
+ using namespace Geom;
+ hp_vec.clear();
+ Geom::Path path;
+ Geom::Point s = start_point;
+ Geom::Point e = end_point;
+ path.start( s );
+ path.appendNew<Geom::LineSegment>( e );
+ Geom::PathVector helper;
+ helper.push_back(path);
+ hp_vec.push_back(helper);
+}
+
+} //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 :