From c30d8e71636f2c1e03c515d39fbe30bbac8a3917 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Mon, 24 May 2021 13:47:11 +0530 Subject: [PATCH 01/66] Added alignment snap preferences new SPAttr ALIGNMENTTOLERANCE --- src/attributes.cpp | 1 + src/attributes.h | 1 + src/object/sp-namedview.cpp | 5 +++++ src/snap-preferences.h | 3 +++ src/ui/dialog/document-properties.cpp | 13 ++++++++++++- src/ui/dialog/document-properties.h | 1 + 6 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/attributes.cpp b/src/attributes.cpp index 021205c232..2165e7c008 100644 --- a/src/attributes.cpp +++ b/src/attributes.cpp @@ -71,6 +71,7 @@ static SPStyleProp const props[] = { {SPAttr::GRIDTOLERANCE, "gridtolerance"}, {SPAttr::GUIDETOLERANCE, "guidetolerance"}, {SPAttr::OBJECTTOLERANCE, "objecttolerance"}, + {SPAttr::ALIGNMENTTOLERANCE, "alignmenttolerance"}, {SPAttr::GUIDECOLOR, "guidecolor"}, {SPAttr::GUIDEOPACITY, "guideopacity"}, {SPAttr::GUIDEHICOLOR, "guidehicolor"}, diff --git a/src/attributes.h b/src/attributes.h index 2dc50d4c30..4d961aa9e3 100644 --- a/src/attributes.h +++ b/src/attributes.h @@ -70,6 +70,7 @@ enum class SPAttr { GRIDTOLERANCE, GUIDETOLERANCE, OBJECTTOLERANCE, + ALIGNMENTTOLERANCE, GUIDECOLOR, GUIDEOPACITY, GUIDEHICOLOR, diff --git a/src/object/sp-namedview.cpp b/src/object/sp-namedview.cpp index 8d902e8fe9..8a943151c7 100644 --- a/src/object/sp-namedview.cpp +++ b/src/object/sp-namedview.cpp @@ -200,6 +200,7 @@ void SPNamedView::build(SPDocument *document, Inkscape::XML::Node *repr) { this->readAttr(SPAttr::GRIDTOLERANCE); this->readAttr(SPAttr::GUIDETOLERANCE); this->readAttr(SPAttr::OBJECTTOLERANCE); + this->readAttr(SPAttr::ALIGNMENTTOLERANCE); this->readAttr(SPAttr::GUIDECOLOR); this->readAttr(SPAttr::GUIDEOPACITY); this->readAttr(SPAttr::GUIDEHICOLOR); @@ -313,6 +314,10 @@ void SPNamedView::set(SPAttr key, const gchar* value) { this->snap_manager.snapprefs.setObjectTolerance(value ? g_ascii_strtod(value, nullptr) : 20); this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; + case SPAttr::ALIGNMENTTOLERANCE: + this->snap_manager.snapprefs.setAlignementTolerance(value ? g_ascii_strtod(value, nullptr) : 20); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; case SPAttr::GUIDECOLOR: this->guidecolor = (this->guidecolor & 0xff) | (DEFAULTGUIDECOLOR & 0xffffff00); diff --git a/src/snap-preferences.h b/src/snap-preferences.h index 4c0bc02ae0..bcf3b81a44 100644 --- a/src/snap-preferences.h +++ b/src/snap-preferences.h @@ -53,10 +53,12 @@ public: double getGridTolerance() const {return _grid_tolerance;} double getGuideTolerance() const {return _guide_tolerance;} double getObjectTolerance() const {return _object_tolerance;} + double getAlignmentTolerance() const {return _alignment_tolerance;} void setGridTolerance(double val) {_grid_tolerance = val;} void setGuideTolerance(double val) {_guide_tolerance = val;} void setObjectTolerance(double val) {_object_tolerance = val;} + void setAlignementTolerance(double val) {_alignment_tolerance = val;} private: @@ -95,6 +97,7 @@ private: double _grid_tolerance; double _guide_tolerance; double _object_tolerance; + double _alignment_tolerance; }; } diff --git a/src/ui/dialog/document-properties.cpp b/src/ui/dialog/document-properties.cpp index 8ddc09e234..d9ac14779f 100644 --- a/src/ui/dialog/document-properties.cpp +++ b/src/ui/dialog/document-properties.cpp @@ -108,7 +108,7 @@ DocumentProperties::DocumentProperties() , _rum_deflt(_("Display _units:"), "inkscape:document-units", _wr) , _page_sizer(_wr) //--------------------------------------------------------------- - //General snap options + //General guide options , _rcb_sgui(_("Show _guides"), _("Show or hide guides"), "showguides", _wr) , _rcb_lgui(_("Lock all guides"), _("Toggle lock of all guides in the document"), "inkscape:lockguides", _wr) , _rcp_gui(_("Guide co_lor:"), _("Guideline color"), _("Color of guidelines"), "guidecolor", "guideopacity", _wr) @@ -130,6 +130,11 @@ DocumentProperties::DocumentProperties() _("Snapping distance, in screen pixels, for snapping to guides"), _("Always snap to guides, regardless of the distance"), _("If set, objects only snap to a guide when it's within the range specified below"), "guidetolerance", _wr) + //Options for alignement snapping + , _rsu_assn(_("Snap dista_nce"), _("Snap only when cl_oser than:"), _("Always snap"), + _("Snapping distance, in screen pixels, for alignment snapping"), _("Always snap to alignment guides, regardless of the distance"), + _("If set, objects only snap to as alignment guide when it's within the range specified below"), + "alignmenttolerance", _wr) //--------------------------------------------------------------- , _rcb_snclp(_("Snap to clip paths"), _("When snapping to paths, then also try snapping to clip paths"), "inkscape:snap-path-clip", _wr) , _rcb_snmsk(_("Snap to mask paths"), _("When snapping to paths, then also try snapping to mask paths"), "inkscape:snap-path-mask", _wr) @@ -361,6 +366,8 @@ void DocumentProperties::build_snap() label_gr->set_markup (_("Snap to grids")); Gtk::Label *label_gu = Gtk::manage (new Gtk::Label); label_gu->set_markup (_("Snap to guides")); + Gtk::Label *label_as = Gtk::manage (new Gtk::Label); + label_as->set_markup (_("Alignment Snapping")); Gtk::Label *label_m = Gtk::manage (new Gtk::Label); label_m->set_markup (_("Miscellaneous")); @@ -379,6 +386,9 @@ void DocumentProperties::build_snap() label_gu, nullptr, nullptr, _rsu_gusn._vbox, nullptr, nullptr, + label_as, nullptr, + nullptr, _rsu_assn._vbox, + nullptr, nullptr, label_m, nullptr, nullptr, &_rcb_perp, nullptr, &_rcb_tang @@ -1404,6 +1414,7 @@ void DocumentProperties::update_widgets() _rsu_sno.setValue (nv->snap_manager.snapprefs.getObjectTolerance()); _rsu_sn.setValue (nv->snap_manager.snapprefs.getGridTolerance()); _rsu_gusn.setValue (nv->snap_manager.snapprefs.getGuideTolerance()); + _rsu_assn.setValue (nv->snap_manager.snapprefs.getAlignmentTolerance()); _rcb_snclp.setActive (nv->snap_manager.snapprefs.isSnapButtonEnabled(Inkscape::SNAPTARGET_PATH_CLIP)); _rcb_snmsk.setActive (nv->snap_manager.snapprefs.isSnapButtonEnabled(Inkscape::SNAPTARGET_PATH_MASK)); _rcb_perp.setActive (nv->snap_manager.snapprefs.getSnapPerp()); diff --git a/src/ui/dialog/document-properties.h b/src/ui/dialog/document-properties.h index 9a8a6bbd96..fee6c38552 100644 --- a/src/ui/dialog/document-properties.h +++ b/src/ui/dialog/document-properties.h @@ -141,6 +141,7 @@ protected: UI::Widget::ToleranceSlider _rsu_sno; UI::Widget::ToleranceSlider _rsu_sn; UI::Widget::ToleranceSlider _rsu_gusn; + UI::Widget::ToleranceSlider _rsu_assn; UI::Widget::RegisteredCheckButton _rcb_snclp; UI::Widget::RegisteredCheckButton _rcb_snmsk; UI::Widget::RegisteredCheckButton _rcb_perp; -- GitLab From f64c2efa73b05982d45b2e81dca1bc8f8a44efcc Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Mon, 24 May 2021 19:07:44 +0530 Subject: [PATCH 02/66] Added skeleton AlignmentSnapper class and linked it to SnapManager alignment-snapper.cpp and alignment.h added in CMakeLists --- src/CMakeLists.txt | 2 ++ src/alignment-snapper.cpp | 64 +++++++++++++++++++++++++++++++++++ src/alignment-snapper.h | 70 +++++++++++++++++++++++++++++++++++++++ src/snap.cpp | 2 ++ src/snap.h | 2 ++ 5 files changed, 140 insertions(+) create mode 100644 src/alignment-snapper.cpp create mode 100644 src/alignment-snapper.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cbb16235b7..e975d6fe27 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,6 +4,7 @@ # ----------------------------------------------------------------------------- set(inkscape_SRC + alignment-snapper.cpp attribute-rel-css.cpp attribute-rel-svg.cpp attribute-rel-util.cpp @@ -88,6 +89,7 @@ set(inkscape_SRC # ------- # Headers + alignment-snapper.h attribute-rel-css.h attribute-rel-svg.h attribute-rel-util.h diff --git a/src/alignment-snapper.cpp b/src/alignment-snapper.cpp new file mode 100644 index 0000000000..9cc0d05ec2 --- /dev/null +++ b/src/alignment-snapper.cpp @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** \file + * Snapping things to on-canvas alignment guides. + * + * Authors: + * Parth Pant + * + * Copyright (C) 2021 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include <2geom/circle.h> +#include <2geom/line.h> +#include <2geom/path-intersection.h> +#include <2geom/path-sink.h> + +#include "inkscape.h" + +Inkscape::AlignmentSnapper::AlignmentSnapper(SnapManager *sm, Geom::Coord const d) + : Snapper(sm, d) +{ +} + +Inkscape::AlignmentSnapper::~AlignmentSnapper() +{ +} + +void Inkscape::AlignmentSnapper::freeSnap(IntermSnapResults &isr, + Inkscape::SnapCandidatePoint const &p, + Geom::OptRect const &bbox_to_snap, + std::vector const *it, + std::vector *unselected_nodes) const +{ +} + +void Inkscape::AlignmentSnapper::constrainedSnap(IntermSnapResults &isr, + Inkscape::SnapCandidatePoint const &p, + Geom::OptRect const &bbox_to_snap, + SnapConstraint const &c, + std::vector const *it, + std::vector *unselected_nodes) const +{ +} + +bool Inkscape::AlignmentSnapper::ThisSnapperMightSnap() const +{ + return true; +} + +bool Inkscape::AlignmentSnapper::getSnapperAlwaysSnap() const +{ + return _snapmanager->snapprefs.getAlignmentTolerance() == 10000; //TODO: Replace this threshold of 10000 by a constant; see also tolerance-slider.cpp +} + +Geom::Coord Inkscape::AlignmentSnapper::getSnapperTolerance() const +{ + SPDesktop const *dt = _snapmanager->getDesktop(); + double const zoom = dt ? dt->current_zoom() : 1; + return _snapmanager->snapprefs.getAlignmentTolerance() / zoom; +} + + + diff --git a/src/alignment-snapper.h b/src/alignment-snapper.h new file mode 100644 index 0000000000..418ee338f8 --- /dev/null +++ b/src/alignment-snapper.h @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** \file + * Authors: + * Parth Pant + * + * Copyright (C) 2021 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#ifndef SEEN_ALIGNMENT_SNAPPER_H +#define SEEN_ALIGNMENT_SNAPPER_H + +#include "snapper.h" +#include "snap-candidate.h" + +class SPDesktop; +class SPNamedView; +class SPItem; +class SPObject; +class SPPath; +class SPDesktop; + +namespace Inkscape +{ + +/** + * Snapping things to on-canvas alignment guides + */ +class AlignmentSnapper : public Snapper +{ + +public: + AlignmentSnapper(SnapManager *sm, Geom::Coord const d); + ~AlignmentSnapper() override; + + /** + * @return true if this Snapper will snap at least one kind of point. + */ + bool ThisSnapperMightSnap() const override; + + /** + * @return Snap tolerance (desktop coordinates); depends on current zoom so that it's always the same in screen pixels. + */ + Geom::Coord getSnapperTolerance() const override; //returns the tolerance of the snapper in screen pixels (i.e. independent of zoom) + + bool getSnapperAlwaysSnap() const override; //if true, then the snapper will always snap, regardless of its tolerance + + void freeSnap(IntermSnapResults &isr, + Inkscape::SnapCandidatePoint const &p, + Geom::OptRect const &bbox_to_snap, + std::vector const *it, + std::vector *unselected_nodes) const override; + + void constrainedSnap(IntermSnapResults &isr, + Inkscape::SnapCandidatePoint const &p, + Geom::OptRect const &bbox_to_snap, + SnapConstraint const &c, + std::vector const *it, + std::vector *unselected_nodes) const override; + +private: + +}; // end of AlignmentSnapper class + +void getBBoxPoints(Geom::OptRect const bbox, std::vector *points, bool const isTarget, bool const includeCorners, bool const includeLineMidpoints, bool const includeObjectMidpoints); + +} // end of namespace Inkscape + +#endif diff --git a/src/snap.cpp b/src/snap.cpp index c56358540b..c0afcd27fe 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -43,6 +43,7 @@ using Inkscape::Util::round_to_lower_multiple_plus; SnapManager::SnapManager(SPNamedView const *v) : guide(this, 0), object(this, 0), + alignment(this, 0), snapprefs(), _named_view(v), _rotation_center_source_items(std::vector()), @@ -58,6 +59,7 @@ SnapManager::SnapperList SnapManager::getSnappers() const SnapManager::SnapperList s; s.push_back(&guide); s.push_back(&object); + s.push_back(&alignment); SnapManager::SnapperList gs = getGridSnappers(); s.splice(s.begin(), gs); diff --git a/src/snap.h b/src/snap.h index ba0cb15cec..c5a44de023 100644 --- a/src/snap.h +++ b/src/snap.h @@ -22,6 +22,7 @@ #include "guide-snapper.h" #include "object-snapper.h" +#include "alignment-snapper.h" #include "snap-preferences.h" @@ -337,6 +338,7 @@ public: Inkscape::GuideSnapper guide; ///< guide snapper Inkscape::ObjectSnapper object; ///< snapper to other objects + Inkscape::AlignmentSnapper alignment; ///< snapper to align with other objects Inkscape::SnapPreferences snapprefs; /** -- GitLab From 792ea281158cb749f664d4ded99703f3c73d42ad Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Mon, 24 May 2021 19:40:58 +0530 Subject: [PATCH 03/66] Added AlignmentSnapper::_findCandidates --- src/alignment-snapper.cpp | 134 ++++++++++++++++++++++++++++++++++++++ src/alignment-snapper.h | 20 +++++- 2 files changed, 152 insertions(+), 2 deletions(-) diff --git a/src/alignment-snapper.cpp b/src/alignment-snapper.cpp index 9cc0d05ec2..028e2a5fd4 100644 --- a/src/alignment-snapper.cpp +++ b/src/alignment-snapper.cpp @@ -15,23 +15,157 @@ #include <2geom/path-intersection.h> #include <2geom/path-sink.h> +#include "desktop.h" +#include "display/curve.h" +#include "document.h" #include "inkscape.h" +#include "live_effects/effect-enum.h" +#include "object/sp-clippath.h" +#include "object/sp-flowtext.h" +#include "object/sp-image.h" +#include "object/sp-item-group.h" +#include "object/sp-mask.h" +#include "object/sp-namedview.h" +#include "object/sp-path.h" +#include "object/sp-root.h" +#include "object/sp-shape.h" +#include "object/sp-text.h" +#include "object/sp-use.h" +#include "path/path-util.h" // curve_for_item +#include "preferences.h" +#include "style.h" +#include "svg/svg.h" +#include "text-editing.h" Inkscape::AlignmentSnapper::AlignmentSnapper(SnapManager *sm, Geom::Coord const d) : Snapper(sm, d) { + _candidates = new std::vector; } Inkscape::AlignmentSnapper::~AlignmentSnapper() { } +void Inkscape::AlignmentSnapper::_findCandidates(SPObject* parent, + std::vector const *it, + bool const &first_point, + bool const clip_or_mask, + Geom::Affine const additional_affine) const +{ + SPDesktop const *dt = _snapmanager->getDesktop(); + if (dt == nullptr) { + g_warning("desktop == NULL, so we cannot snap; please inform the developers of this bug"); + // Apparently the setup() method from the SnapManager class hasn't been called before trying to snap. + } + + if (first_point) { + _candidates->clear(); + } + + for (auto& o: parent->children) { + g_assert(dt != nullptr); + SPItem *item = dynamic_cast(&o); + if (item && !(dt->itemIsHidden(item) && !clip_or_mask)) { + // Fix LPE boolops selfsnaping + bool stop = false; + if (item->style) { + SPFilter *filt = item->style->getFilter(); + if (filt && filt->getId() && strcmp(filt->getId(), "selectable_hidder_filter") == 0) { + stop = true; + } + SPLPEItem *lpeitem = dynamic_cast(item); + if (lpeitem && lpeitem->hasPathEffectOfType(Inkscape::LivePathEffect::EffectType::BOOL_OP)) { + stop = true; + } + } + if (stop) { + stop = false; + for (auto skipitem : *it) { + if (skipitem && skipitem->style) { + SPItem *toskip = const_cast(skipitem); + if (toskip) { + SPFilter *filt = toskip->style->getFilter(); + if (filt && filt->getId() && strcmp(filt->getId(), "selectable_hidder_filter") == 0) { + stop = true; + break; + } + + SPLPEItem *lpeitem = dynamic_cast(toskip); + if (!stop && lpeitem && + lpeitem->hasPathEffectOfType(Inkscape::LivePathEffect::EffectType::BOOL_OP)) { + stop = true; + break; + } + } + } + } + if (stop) { + continue; + } + } + // Snapping to items in a locked layer is allowed + // Don't snap to hidden objects, unless they're a clipped path or a mask + /* See if this item is on the ignore list */ + std::vector::const_iterator i; + if (it != nullptr) { + i = it->begin(); + while (i != it->end() && *i != &o) { + ++i; + } + } + + if (it == nullptr || i == it->end()) { + if (item) { + if (!clip_or_mask) { // cannot clip or mask more than once + // The current item is not a clipping path or a mask, but might + // still be the subject of clipping or masking itself ; if so, then + // we should also consider that path or mask for snapping to + SPObject *obj = item->getClipObject(); + if (obj && _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_PATH_CLIP)) { + _findCandidates(obj, it, false, true, item->i2doc_affine()); + } + obj = item->getMaskObject(); + if (obj && _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_PATH_MASK)) { + _findCandidates(obj, it, false, true, item->i2doc_affine()); + } + } + + if (dynamic_cast(item)) { + _findCandidates(&o, it, false, clip_or_mask, additional_affine); + } else { + // Finally add the object to _candidates. + _candidates->push_back(SnapCandidateItem(item, clip_or_mask, additional_affine)); + // For debugging: print the id of the candidate to the console + // SPObject *obj = (SPObject*)item; + // std::cout << "Snap candidate added: " << obj->getId() << std::endl; + if (_candidates->size() > 200) { // This makes Inkscape crawl already + static Glib::Timer timer; + if (timer.elapsed() > 1.0) { + timer.reset(); + std::cout << "Warning: limit of 200 snap target paths reached, some will be ignored" << std::endl; + } + break; + } + } + } + } + } + } +} + + void Inkscape::AlignmentSnapper::freeSnap(IntermSnapResults &isr, Inkscape::SnapCandidatePoint const &p, Geom::OptRect const &bbox_to_snap, std::vector const *it, std::vector *unselected_nodes) const { + // TODO: add toggle checks here + if (p.getSourceNum() <= 0){ + _candidates->clear(); + _findCandidates(_snapmanager->getDocument()->getRoot(), it, true, false); + } } void Inkscape::AlignmentSnapper::constrainedSnap(IntermSnapResults &isr, diff --git a/src/alignment-snapper.h b/src/alignment-snapper.h index 418ee338f8..c4f4053552 100644 --- a/src/alignment-snapper.h +++ b/src/alignment-snapper.h @@ -11,6 +11,8 @@ #ifndef SEEN_ALIGNMENT_SNAPPER_H #define SEEN_ALIGNMENT_SNAPPER_H +#include <2geom/affine.h> + #include "snapper.h" #include "snap-candidate.h" @@ -60,11 +62,25 @@ public: std::vector *unselected_nodes) const override; private: + // Store some snap candidate, these are cached for the first point and not recalculated for each point + std::vector *_candidates; + std::vector *_points_to_snap_to; + + /** Find candidates that lie withing a certain range (visible on viewport). + * @param parent Pointer to the document's root, or to a clipped path or mask object. + * @param it List of items to ignore. + * @param bbox_to_snap Bounding box hulling the whole bunch of points, all from the same selection and having the same transformation. + * @param clip_or_mask The parent object being passed is either a clip or mask. + * @param additional_affine Affine of the clipped path or mask object. + */ + void _findCandidates(SPObject* parent, + std::vector const *it, + bool const &first_point, + bool const clip_or_mask, + Geom::Affine const additional_affine = Geom::identity()) const; }; // end of AlignmentSnapper class -void getBBoxPoints(Geom::OptRect const bbox, std::vector *points, bool const isTarget, bool const includeCorners, bool const includeLineMidpoints, bool const includeObjectMidpoints); - } // end of namespace Inkscape #endif -- GitLab From a4f66351fc14fe1456f04eb68460c61930b3ca61 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Wed, 26 May 2021 18:38:26 +0530 Subject: [PATCH 04/66] Add _collectBBoxPoints, _snapBBoxPoints and ALIGNMENT_CATEGORY enums Bug: all nodes are snapped instead of only bbox points --- src/alignment-snapper.cpp | 143 ++++++++++++++++++++++++++++++++++++++ src/alignment-snapper.h | 13 ++++ src/object-snapper.cpp | 22 ++++-- src/object-snapper.h | 2 +- src/snap-enums.h | 20 ++++++ src/snap-preferences.cpp | 18 +++++ 6 files changed, 213 insertions(+), 5 deletions(-) diff --git a/src/alignment-snapper.cpp b/src/alignment-snapper.cpp index 028e2a5fd4..e33cd680f2 100644 --- a/src/alignment-snapper.cpp +++ b/src/alignment-snapper.cpp @@ -33,6 +33,7 @@ #include "object/sp-use.h" #include "path/path-util.h" // curve_for_item #include "preferences.h" +#include "snap-enums.h" #include "style.h" #include "svg/svg.h" #include "text-editing.h" @@ -41,10 +42,13 @@ Inkscape::AlignmentSnapper::AlignmentSnapper(SnapManager *sm, Geom::Coord const : Snapper(sm, d) { _candidates = new std::vector; + _points_to_snap_to = new std::vector; } Inkscape::AlignmentSnapper::~AlignmentSnapper() { + _candidates->clear(); + _points_to_snap_to->clear(); } void Inkscape::AlignmentSnapper::_findCandidates(SPObject* parent, @@ -155,17 +159,138 @@ void Inkscape::AlignmentSnapper::_findCandidates(SPObject* parent, } +void Inkscape::AlignmentSnapper::_collectBBoxPoints(bool const &first_point) const +{ + if (!first_point) + return; + + _points_to_snap_to->clear(); + SPItem::BBoxType bbox_type = SPItem::GEOMETRIC_BBOX; + + Preferences *prefs = Preferences::get(); + bool prefs_bbox = prefs->getBool("/tools/bounding_box"); + bbox_type = !prefs_bbox ? + SPItem::VISUAL_BBOX : SPItem::GEOMETRIC_BBOX; + + // collect page corners and center + // TODO: use the function in ObjectSnapper + if (_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_PAGE_CORNER)) { + Geom::Coord w = (_snapmanager->getDocument())->getWidth().value("px"); + Geom::Coord h = (_snapmanager->getDocument())->getHeight().value("px"); + _points_to_snap_to->push_back(SnapCandidatePoint(Geom::Point(0,0), SNAPSOURCE_UNDEFINED, SNAPTARGET_ALIGNMENT_PAGE_CORNER)); + _points_to_snap_to->push_back(SnapCandidatePoint(Geom::Point(0,h), SNAPSOURCE_UNDEFINED, SNAPTARGET_ALIGNMENT_PAGE_CORNER)); + _points_to_snap_to->push_back(SnapCandidatePoint(Geom::Point(w,h), SNAPSOURCE_UNDEFINED, SNAPTARGET_ALIGNMENT_PAGE_CORNER)); + _points_to_snap_to->push_back(SnapCandidatePoint(Geom::Point(w,0), SNAPSOURCE_UNDEFINED, SNAPTARGET_ALIGNMENT_PAGE_CORNER)); + _points_to_snap_to->push_back(SnapCandidatePoint(Geom::Point(w/2.0f,h/2.0f), SNAPSOURCE_UNDEFINED, SNAPTARGET_ALIGNMENT_PAGE_CENTER)); + } + + // collect bounding boxes of other objects + for (const auto & candidate : *_candidates) { + SPItem *root_item = candidate.item; + + // get the root item in case we have a duplicate at hand + SPUse *use = dynamic_cast(candidate.item); + if (use) { + root_item = use->root(); + } + g_return_if_fail(root_item); + + // if candidate is not a clip or a mask object then extract its BBox points + if (!candidate.clip_or_mask) { + Geom::OptRect b = root_item->desktopBounds(bbox_type); + getBBoxPoints(b, _points_to_snap_to, true, true, true, true, true); + } + } + + // Debug log + //std::cout<<"----------"< *unselected_nodes, + SnapConstraint const &c, + Geom::Point const &p_proj_on_constraint) const +{ + + _collectBBoxPoints(p.getSourceNum() <= 0); + + if (unselected_nodes != nullptr && unselected_nodes->size() > 0) { + g_assert(_points_to_snap_to != nullptr); + _points_to_snap_to->insert(_points_to_snap_to->end(), unselected_nodes->begin(), unselected_nodes->end()); + } + + SnappedPoint sx; + SnappedPoint sy; + bool success = false; + //bool strict_snapping = _snapmanager->snapprefs.getStrictSnapping(); + + for (const auto & k : *_points_to_snap_to) { + // TODO: add strict snpping checks from ObjectSnapper::_allowSourceToSnapToTarget(...) + if (true) { + Geom::Point target_pt = k.getPoint(); + // (unconstrained) distace from HORIZONTAL guide + Geom::Point point_on_x(p.getPoint().x(), target_pt.y()); + Geom::Coord distX = Geom::L2(point_on_x - p.getPoint()); + + // (unconstrained) distace from VERTICAL guide + Geom::Point point_on_y(target_pt.x(), p.getPoint().y()); + Geom::Coord distY = Geom::L2(point_on_y - p.getPoint()); + + // TODO: What about constraints? + if (!c.isUndefined()) { + } + + if (distX < getSnapperTolerance()) { + sx = SnappedPoint(point_on_x, source2alignment(p.getSourceType()), p.getSourceNum(), k.getTargetType(), distX, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true, k.getTargetBBox()); + success = true; + } + + if (distY < getSnapperTolerance()) { + sy = SnappedPoint(point_on_y, source2alignment(p.getSourceType()), p.getSourceNum(), k.getTargetType(), distY, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true, k.getTargetBBox()); + success = true; + } + } + } + + if (success) { + if (sx.getSnapDistance() < sy.getSnapDistance()) { + isr.points.push_back(sx); + // Debug log + //std::cout<<"----X----"< const *it, std::vector *unselected_nodes) const { + // only snap if the source point is a bounding box or a handel + bool p_is_bbox = p.getSourceType() | SNAPSOURCE_BBOX_CATEGORY; + bool p_is_handel = p.getSourceType() | SNAPSOURCE_OTHER_HANDLE; + + if (!(p_is_bbox || p_is_handel)) + return; + // TODO: add toggle checks here if (p.getSourceNum() <= 0){ _candidates->clear(); _findCandidates(_snapmanager->getDocument()->getRoot(), it, true, false); } + + _snapBBoxPoints(isr, p, unselected_nodes); } void Inkscape::AlignmentSnapper::constrainedSnap(IntermSnapResults &isr, @@ -194,5 +319,23 @@ Geom::Coord Inkscape::AlignmentSnapper::getSnapperTolerance() const return _snapmanager->snapprefs.getAlignmentTolerance() / zoom; } +Inkscape::SnapSourceType Inkscape::AlignmentSnapper::source2alignment(SnapSourceType s) const +{ + switch (s) { + case SNAPSOURCE_BBOX_CATEGORY: + return SNAPSOURCE_ALIGNMENT_CATEGORY; + case SNAPSOURCE_BBOX_CORNER: + return SNAPSOURCE_ALIGNMENT_BBOX_CORNER; + case SNAPSOURCE_BBOX_MIDPOINT: + return SNAPSOURCE_ALIGNMENT_BBOX_MIDPOINT; + case SNAPSOURCE_BBOX_EDGE_MIDPOINT: + return SNAPSOURCE_ALIGNMENT_BBOX_EDGE_MIDPOINT; + case SNAPSOURCE_OTHER_HANDLE: + return SNAPSOURCE_ALIGNMENT_HANDLE; + default: + return SNAPSOURCE_UNDEFINED; + } +} + diff --git a/src/alignment-snapper.h b/src/alignment-snapper.h index c4f4053552..3ecbead87d 100644 --- a/src/alignment-snapper.h +++ b/src/alignment-snapper.h @@ -13,6 +13,7 @@ #include <2geom/affine.h> +#include "snap-enums.h" #include "snapper.h" #include "snap-candidate.h" @@ -79,6 +80,18 @@ private: bool const clip_or_mask, Geom::Affine const additional_affine = Geom::identity()) const; + /** Collects and caches points on bounding boxes of the candidates + * @param is the point first point in the selection? + */ + void _collectBBoxPoints(bool const &first_point) const; + + void _snapBBoxPoints(IntermSnapResults &isr, + SnapCandidatePoint const &p, + std::vector *unselected_nodes, + SnapConstraint const &c = SnapConstraint(), + Geom::Point const &p_proj_on_constraint = Geom::Point()) const; + + SnapSourceType source2alignment(SnapSourceType s) const; }; // end of AlignmentSnapper class } // end of namespace Inkscape diff --git a/src/object-snapper.cpp b/src/object-snapper.cpp index ca9bd997de..b8435a5ba4 100644 --- a/src/object-snapper.cpp +++ b/src/object-snapper.cpp @@ -36,6 +36,7 @@ #include "object/sp-use.h" #include "path/path-util.h" // curve_for_item #include "preferences.h" +#include "snap-enums.h" #include "style.h" #include "svg/svg.h" #include "text-editing.h" @@ -814,21 +815,34 @@ void Inkscape::getBBoxPoints(Geom::OptRect const bbox, bool const /*isTarget*/, bool const includeCorners, bool const includeLineMidpoints, - bool const includeObjectMidpoints) + bool const includeObjectMidpoints, + bool const isAlignment) { if (bbox) { // collect the corners of the bounding box for ( unsigned k = 0 ; k < 4 ; k++ ) { if (includeCorners) { - points->push_back(SnapCandidatePoint(bbox->corner(k), SNAPSOURCE_BBOX_CORNER, -1, SNAPTARGET_BBOX_CORNER, *bbox)); + points->push_back(SnapCandidatePoint(bbox->corner(k), + isAlignment ? SNAPSOURCE_ALIGNMENT_BBOX_CORNER : SNAPSOURCE_BBOX_CORNER, + -1, + isAlignment ? SNAPTARGET_ALIGNMENT_BBOX_CORNER : SNAPTARGET_BBOX_CORNER, + *bbox)); } // optionally, collect the midpoints of the bounding box's edges too if (includeLineMidpoints) { - points->push_back(SnapCandidatePoint((bbox->corner(k) + bbox->corner((k+1) % 4))/2, SNAPSOURCE_BBOX_EDGE_MIDPOINT, -1, SNAPTARGET_BBOX_EDGE_MIDPOINT, *bbox)); + points->push_back(SnapCandidatePoint((bbox->corner(k) + bbox->corner((k+1) % 4))/2, + isAlignment ? SNAPSOURCE_ALIGNMENT_BBOX_EDGE_MIDPOINT : SNAPSOURCE_BBOX_EDGE_MIDPOINT, + -1, + isAlignment ? SNAPTARGET_ALIGNMENT_BBOX_EDGE_MIDPOINT : SNAPTARGET_BBOX_EDGE_MIDPOINT, + *bbox)); } } if (includeObjectMidpoints) { - points->push_back(SnapCandidatePoint(bbox->midpoint(), SNAPSOURCE_BBOX_MIDPOINT, -1, SNAPTARGET_BBOX_MIDPOINT, *bbox)); + points->push_back(SnapCandidatePoint(bbox->midpoint(), + isAlignment ? SNAPSOURCE_ALIGNMENT_BBOX_MIDPOINT : SNAPSOURCE_BBOX_MIDPOINT, + -1, + isAlignment ? SNAPTARGET_ALIGNMENT_BBOX_MIDPOINT : SNAPTARGET_BBOX_MIDPOINT, + *bbox)); } } } diff --git a/src/object-snapper.h b/src/object-snapper.h index 1709137db3..929b57a1c8 100644 --- a/src/object-snapper.h +++ b/src/object-snapper.h @@ -126,7 +126,7 @@ private: }; // end of ObjectSnapper class -void getBBoxPoints(Geom::OptRect const bbox, std::vector *points, bool const isTarget, bool const includeCorners, bool const includeLineMidpoints, bool const includeObjectMidpoints); +void getBBoxPoints(Geom::OptRect const bbox, std::vector *points, bool const isTarget, bool const includeCorners, bool const includeLineMidpoints, bool const includeObjectMidpoints, bool const isAlignment = false); } // end of namespace Inkscape diff --git a/src/snap-enums.h b/src/snap-enums.h index 321963b087..ae4e146e48 100644 --- a/src/snap-enums.h +++ b/src/snap-enums.h @@ -50,6 +50,16 @@ enum SnapSourceType { // When adding source types here, then also update Inkscap SNAPSOURCE_TEXT_ANCHOR, SNAPSOURCE_OTHER_HANDLE, // eg. the handle of a gradient or of a connector (ie not being tied to a stroke) SNAPSOURCE_GRID_PITCH, // eg. when pasting or alt-dragging in the selector tool; not really a snap source + + //------------------------------------------------------------------- + // Alignment snapping + SNAPSOURCE_ALIGNMENT_CATEGORY = 256, + SNAPSOURCE_ALIGNMENT_BBOX_CORNER, + SNAPSOURCE_ALIGNMENT_BBOX_MIDPOINT, + SNAPSOURCE_ALIGNMENT_BBOX_EDGE_MIDPOINT, + SNAPSOURCE_ALIGNMENT_PAGE_CENTER, + SNAPSOURCE_ALIGNMENT_PAGE_CORNER, + SNAPSOURCE_ALIGNMENT_HANDLE }; enum SnapTargetType { @@ -97,6 +107,16 @@ enum SnapTargetType { SNAPTARGET_TEXT_BASELINE, SNAPTARGET_CONSTRAINED_ANGLE, SNAPTARGET_CONSTRAINT, + + //------------------------------------------------------------------- + // Alignment snapping + SNAPTARGET_ALIGNMENT_CATEGORY = 256, // will be used as a flag and must therefore be a power of two + SNAPTARGET_ALIGNMENT_BBOX_CORNER, + SNAPTARGET_ALIGNMENT_BBOX_MIDPOINT, + SNAPTARGET_ALIGNMENT_BBOX_EDGE_MIDPOINT, + SNAPTARGET_ALIGNMENT_PAGE_CENTER, + SNAPTARGET_ALIGNMENT_PAGE_CORNER, + SNAPTARGET_ALIGNMENT_HANDLE, //------------------------------------------------------------------- SNAPTARGET_MAX_ENUM_VALUE }; diff --git a/src/snap-preferences.cpp b/src/snap-preferences.cpp index 876293aca5..69b5f921d9 100644 --- a/src/snap-preferences.cpp +++ b/src/snap-preferences.cpp @@ -11,6 +11,7 @@ */ #include "inkscape.h" +#include "snap-enums.h" Inkscape::SnapPreferences::SnapPreferences() : _snap_enabled_globally(true), @@ -295,6 +296,23 @@ Inkscape::SnapTargetType Inkscape::SnapPreferences::source2target(Inkscape::Snap return SNAPTARGET_NODE_CATEGORY; case SNAPSOURCE_GRID_PITCH: return SNAPTARGET_GRID; + + + case SNAPSOURCE_ALIGNMENT_CATEGORY: + return SNAPTARGET_ALIGNMENT_CATEGORY; + case SNAPSOURCE_ALIGNMENT_BBOX_CORNER: + return SNAPTARGET_ALIGNMENT_BBOX_CORNER; + case SNAPSOURCE_ALIGNMENT_BBOX_MIDPOINT: + return SNAPTARGET_ALIGNMENT_BBOX_EDGE_MIDPOINT; + case SNAPSOURCE_ALIGNMENT_BBOX_EDGE_MIDPOINT: + return SNAPTARGET_ALIGNMENT_BBOX_EDGE_MIDPOINT; + case SNAPSOURCE_ALIGNMENT_PAGE_CENTER: + return SNAPTARGET_ALIGNMENT_PAGE_CENTER; + case SNAPSOURCE_ALIGNMENT_PAGE_CORNER: + return SNAPTARGET_ALIGNMENT_PAGE_CORNER; + case Inkscape::SNAPSOURCE_ALIGNMENT_HANDLE: + return SNAPTARGET_ALIGNMENT_HANDLE; + default: g_warning("Mapping of snap source to snap target undefined"); return SNAPTARGET_UNDEFINED; -- GitLab From bc4b5493074e7aaa591cec0306861f9ea8b93a6a Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Thu, 27 May 2021 23:04:30 +0530 Subject: [PATCH 05/66] Added a toggle for alignment snapping --- share/ui/toolbar-snap.ui | 16 ++++++++++++++++ src/actions/actions-canvas-snapping.cpp | 13 +++++++++++++ src/alignment-snapper.cpp | 17 +++++++++++------ src/attributes.cpp | 1 + src/attributes.h | 1 + src/object/sp-namedview.cpp | 4 ++++ src/snap-preferences.cpp | 20 +++++++++++++++++++- 7 files changed, 65 insertions(+), 7 deletions(-) diff --git a/share/ui/toolbar-snap.ui b/share/ui/toolbar-snap.ui index b287c87033..5f0c8e9b4e 100644 --- a/share/ui/toolbar-snap.ui +++ b/share/ui/toolbar-snap.ui @@ -212,6 +212,22 @@ + + + + + True + + + + + + True + doc.snap-alignment + snap + Alignment + + diff --git a/src/actions/actions-canvas-snapping.cpp b/src/actions/actions-canvas-snapping.cpp index acef9532ed..1cbc2869cf 100644 --- a/src/actions/actions-canvas-snapping.cpp +++ b/src/actions/actions-canvas-snapping.cpp @@ -24,6 +24,7 @@ #include "document-undo.h" #include "object/sp-namedview.h" +#include "snap-enums.h" // There are four snapping lists that must be connected: // 1. The attribute name in NamedView: e.g. "inkscape:snap-bbox". @@ -63,6 +64,11 @@ canvas_snapping_toggle(SPDocument* document, const SPAttr option) repr->setAttributeBoolean("inkscape:snap-global", !v); break; + case SPAttr::INKSCAPE_SNAP_ALIGNMENT: + v = nv->snap_manager.snapprefs.isTargetSnappable(Inkscape::SNAPTARGET_ALIGNMENT_CATEGORY); + repr->setAttributeBoolean("inkscape:snap-alignment", !v); + break; + // BBox case SPAttr::INKSCAPE_SNAP_BBOX: v = nv->snap_manager.snapprefs.isTargetSnappable(Inkscape::SNAPTARGET_BBOX_CATEGORY); @@ -184,6 +190,8 @@ std::vector> raw_data_canvas_snapping = { {"doc.snap-global-toggle", N_("Snapping"), "Snap", N_("Toggle snapping on/off") }, + {"doc.snap-alignment", N_("Snap Objects that Align"), "Snap", N_("Toggle alignment snapping on/off") }, + {"doc.snap-bbox", N_("Snap Bounding Boxes"), "Snap", N_("Toggle snapping to bounding boxes (global)") }, {"doc.snap-bbox-edge", N_("Snap Bounding Box Edges"), "Snap", N_("Toggle snapping to bounding-box edges") }, {"doc.snap-bbox-corner", N_("Snap Bounding Box Corners"), "Snap", N_("Toggle snapping to bounding-box corners") }, @@ -217,6 +225,8 @@ add_actions_canvas_snapping(SPDocument* document) map->add_action_bool( "snap-global-toggle", sigc::bind(sigc::ptr_fun(&canvas_snapping_toggle), document, SPAttr::INKSCAPE_SNAP_GLOBAL)); + map->add_action_bool( "snap-alignment", sigc::bind(sigc::ptr_fun(&canvas_snapping_toggle), document, SPAttr::INKSCAPE_SNAP_ALIGNMENT)); + map->add_action_bool( "snap-bbox", sigc::bind(sigc::ptr_fun(&canvas_snapping_toggle), document, SPAttr::INKSCAPE_SNAP_BBOX)); map->add_action_bool( "snap-bbox-edge", sigc::bind(sigc::ptr_fun(&canvas_snapping_toggle), document, SPAttr::INKSCAPE_SNAP_BBOX_EDGE)); map->add_action_bool( "snap-bbox-corner", sigc::bind(sigc::ptr_fun(&canvas_snapping_toggle), document, SPAttr::INKSCAPE_SNAP_BBOX_CORNER)); @@ -304,6 +314,9 @@ set_actions_canvas_snapping(SPDocument* document) bool global = nv->snap_manager.snapprefs.getSnapEnabledGlobally(); set_actions_canvas_snapping_helper(map, "snap-global-toggle", global, true); // Always enabled + bool alignment = nv->snap_manager.snapprefs.isTargetSnappable(Inkscape::SNAPTARGET_ALIGNMENT_CATEGORY); + set_actions_canvas_snapping_helper(map, "snap-alignment", alignment, global); + bool bbox = nv->snap_manager.snapprefs.isTargetSnappable(Inkscape::SNAPTARGET_BBOX_CATEGORY); set_actions_canvas_snapping_helper(map, "snap-bbox", bbox, global); set_actions_canvas_snapping_helper(map, "snap-bbox-edge", nv->snap_manager.snapprefs.isSnapButtonEnabled(Inkscape::SNAPTARGET_BBOX_EDGE), global && bbox); diff --git a/src/alignment-snapper.cpp b/src/alignment-snapper.cpp index e33cd680f2..ff3deea640 100644 --- a/src/alignment-snapper.cpp +++ b/src/alignment-snapper.cpp @@ -198,7 +198,7 @@ void Inkscape::AlignmentSnapper::_collectBBoxPoints(bool const &first_point) con // if candidate is not a clip or a mask object then extract its BBox points if (!candidate.clip_or_mask) { Geom::OptRect b = root_item->desktopBounds(bbox_type); - getBBoxPoints(b, _points_to_snap_to, true, true, true, true, true); + getBBoxPoints(b, _points_to_snap_to, true, true, false, true, true); } } @@ -277,14 +277,19 @@ void Inkscape::AlignmentSnapper::freeSnap(IntermSnapResults &isr, std::vector const *it, std::vector *unselected_nodes) const { - // only snap if the source point is a bounding box or a handel - bool p_is_bbox = p.getSourceType() | SNAPSOURCE_BBOX_CATEGORY; - bool p_is_handel = p.getSourceType() | SNAPSOURCE_OTHER_HANDLE; + bool p_is_bbox = p.getSourceType() & SNAPSOURCE_BBOX_CATEGORY; + bool p_is_node = p.getSourceType() & SNAPSOURCE_NODE_HANDLE; + bool p_is_handel = p.getSourceType() & SNAPSOURCE_OTHER_HANDLE; + + + // toggle checks + if (!_snap_enabled || !_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_ALIGNMENT_CATEGORY)) + return; - if (!(p_is_bbox || p_is_handel)) + // only snap if the source point is a bounding box or a handel + if (!(p_is_bbox || p_is_handel || p_is_node)) return; - // TODO: add toggle checks here if (p.getSourceNum() <= 0){ _candidates->clear(); _findCandidates(_snapmanager->getDocument()->getRoot(), it, true, false); diff --git a/src/attributes.cpp b/src/attributes.cpp index 2165e7c008..d57bf192aa 100644 --- a/src/attributes.cpp +++ b/src/attributes.cpp @@ -99,6 +99,7 @@ static SPStyleProp const props[] = { {SPAttr::INKSCAPE_WINDOW_Y, "inkscape:window-y"}, {SPAttr::INKSCAPE_WINDOW_MAXIMIZED, "inkscape:window-maximized"}, {SPAttr::INKSCAPE_SNAP_GLOBAL, "inkscape:snap-global"}, + {SPAttr::INKSCAPE_SNAP_ALIGNMENT, "inkscape:snap-alignment"}, {SPAttr::INKSCAPE_SNAP_PERP, "inkscape:snap-perpendicular"}, {SPAttr::INKSCAPE_SNAP_TANG, "inkscape:snap-tangential"}, {SPAttr::INKSCAPE_SNAP_BBOX, "inkscape:snap-bbox"}, diff --git a/src/attributes.h b/src/attributes.h index 4d961aa9e3..7abae86f9a 100644 --- a/src/attributes.h +++ b/src/attributes.h @@ -98,6 +98,7 @@ enum class SPAttr { INKSCAPE_WINDOW_Y, INKSCAPE_WINDOW_MAXIMIZED, INKSCAPE_SNAP_GLOBAL, + INKSCAPE_SNAP_ALIGNMENT, INKSCAPE_SNAP_PERP, INKSCAPE_SNAP_TANG, INKSCAPE_SNAP_BBOX, diff --git a/src/object/sp-namedview.cpp b/src/object/sp-namedview.cpp index 8a943151c7..3624eabf09 100644 --- a/src/object/sp-namedview.cpp +++ b/src/object/sp-namedview.cpp @@ -537,6 +537,10 @@ void SPNamedView::set(SPAttr key, const gchar* value) { this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_PAGE_BORDER, value ? sp_str_to_bool(value) : FALSE); this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; + case SPAttr::INKSCAPE_SNAP_ALIGNMENT: + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_ALIGNMENT_CATEGORY, value ? sp_str_to_bool(value) : FALSE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; case SPAttr::INKSCAPE_CURRENT_LAYER: this->default_layer_id = value ? g_quark_from_string(value) : 0; this->requestModified(SP_OBJECT_MODIFIED_FLAG); diff --git a/src/snap-preferences.cpp b/src/snap-preferences.cpp index 69b5f921d9..91292b9ec7 100644 --- a/src/snap-preferences.cpp +++ b/src/snap-preferences.cpp @@ -22,6 +22,7 @@ Inkscape::SnapPreferences::SnapPreferences() : { // Check for powers of two; see the comments in snap-enums.h g_assert((SNAPTARGET_BBOX_CATEGORY != 0) && !(SNAPTARGET_BBOX_CATEGORY & (SNAPTARGET_BBOX_CATEGORY - 1))); + g_assert((SNAPTARGET_ALIGNMENT_CATEGORY != 0) && !(SNAPTARGET_ALIGNMENT_CATEGORY & (SNAPTARGET_ALIGNMENT_CATEGORY - 1))); g_assert((SNAPTARGET_NODE_CATEGORY != 0) && !(SNAPTARGET_NODE_CATEGORY & (SNAPTARGET_NODE_CATEGORY - 1))); g_assert((SNAPTARGET_DATUMS_CATEGORY != 0) && !(SNAPTARGET_DATUMS_CATEGORY & (SNAPTARGET_DATUMS_CATEGORY - 1))); g_assert((SNAPTARGET_OTHERS_CATEGORY != 0) && !(SNAPTARGET_OTHERS_CATEGORY & (SNAPTARGET_OTHERS_CATEGORY - 1))); @@ -46,7 +47,8 @@ void Inkscape::SnapPreferences::_mapTargetToArrayIndex(Inkscape::SnapTargetType if (target == SNAPTARGET_BBOX_CATEGORY || target == SNAPTARGET_NODE_CATEGORY || target == SNAPTARGET_OTHERS_CATEGORY || - target == SNAPTARGET_DATUMS_CATEGORY) { + target == SNAPTARGET_DATUMS_CATEGORY || + target == SNAPTARGET_ALIGNMENT_CATEGORY) { // These main targets should be handled separately, because otherwise we might call isTargetSnappable() // for them (to check whether the corresponding group is on) which would lead to an infinite recursive loop always_on = (target == SNAPTARGET_DATUMS_CATEGORY); @@ -118,6 +120,22 @@ void Inkscape::SnapPreferences::_mapTargetToArrayIndex(Inkscape::SnapTargetType return; } + if (target & Inkscape::SNAPTARGET_ALIGNMENT_CATEGORY) { + group_on = isTargetSnappable(SNAPTARGET_ALIGNMENT_CATEGORY); + //switch (target) { + //case SNAPTARGET_ALIGNMENT_BBOX_CORNER: + //case SNAPTARGET_ALIGNMENT_BBOX_MIDPOINT: + //case SNAPTARGET_ALIGNMENT_BBOX_EDGE_MIDPOINT: + //case SNAPTARGET_ALIGNMENT_PAGE_CENTER: + //case SNAPTARGET_ALIGNMENT_PAGE_CORNER: + //case SNAPTARGET_ALIGNMENT_HANDLE: + //target = SNAPTARGET_ALIGNMENT_CATEGORY; + //default: + //g_warning("Snap-preferences warning: Undefined snap target (#%i)", target); + //break; + //} + } + if (target & SNAPTARGET_OTHERS_CATEGORY) { // Only if the group with "other" snap sources/targets has been enabled, then we might snap to any of those targets // ... but this doesn't hold for the page border, grids, and guides -- GitLab From 29a68683aee424fece1c347a8678a8dbdecd3dbe Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Fri, 28 May 2021 14:11:17 +0530 Subject: [PATCH 06/66] added bounding box points in seltrans --- src/alignment-snapper.cpp | 12 ++---------- src/seltrans.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/alignment-snapper.cpp b/src/alignment-snapper.cpp index ff3deea640..8be363ce68 100644 --- a/src/alignment-snapper.cpp +++ b/src/alignment-snapper.cpp @@ -173,7 +173,6 @@ void Inkscape::AlignmentSnapper::_collectBBoxPoints(bool const &first_point) con SPItem::VISUAL_BBOX : SPItem::GEOMETRIC_BBOX; // collect page corners and center - // TODO: use the function in ObjectSnapper if (_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_PAGE_CORNER)) { Geom::Coord w = (_snapmanager->getDocument())->getWidth().value("px"); Geom::Coord h = (_snapmanager->getDocument())->getHeight().value("px"); @@ -258,14 +257,8 @@ void Inkscape::AlignmentSnapper::_snapBBoxPoints(IntermSnapResults &isr, if (success) { if (sx.getSnapDistance() < sy.getSnapDistance()) { isr.points.push_back(sx); - // Debug log - //std::cout<<"----X----"<snapprefs.isTargetSnappable(SNAPTARGET_ALIGNMENT_CATEGORY)) return; // only snap if the source point is a bounding box or a handel - if (!(p_is_bbox || p_is_handel || p_is_node)) + if (!(p_is_bbox || p_is_other || p_is_node)) return; if (p.getSourceNum() <= 0){ diff --git a/src/seltrans.cpp b/src/seltrans.cpp index f4d908961b..af858f78f2 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -300,9 +300,9 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s _bbox_points.clear(); // Collect the bounding box's corners and midpoints for each selected item - if (m.snapprefs.isTargetSnappable(SNAPTARGET_BBOX_CATEGORY)) { - bool c = m.snapprefs.isTargetSnappable(SNAPTARGET_BBOX_CORNER); - bool mp = m.snapprefs.isTargetSnappable(SNAPTARGET_BBOX_MIDPOINT); + if (m.snapprefs.isTargetSnappable(SNAPTARGET_BBOX_CATEGORY, SNAPTARGET_ALIGNMENT_CATEGORY)) { + bool c = m.snapprefs.isTargetSnappable(SNAPTARGET_BBOX_CORNER, SNAPTARGET_ALIGNMENT_CATEGORY); + bool mp = m.snapprefs.isTargetSnappable(SNAPTARGET_BBOX_MIDPOINT, SNAPTARGET_ALIGNMENT_CATEGORY); bool emp = m.snapprefs.isTargetSnappable(SNAPTARGET_BBOX_EDGE_MIDPOINT); // Preferably we'd use the bbox of each selected item, but for example 50 items will produce at least 200 bbox points, // which might make Inkscape crawl(see the comment a few lines above). In that case we will use the bbox of the selection as a whole @@ -1702,7 +1702,7 @@ void Inkscape::SelTrans::_keepClosestPointOnly(Geom::Point const &p) } // If we're not going to snap bounding boxes, then we might just as well get rid of their snappoints right away - if (!m.snapprefs.isTargetSnappable(SNAPTARGET_BBOX_CATEGORY)) { + if (!m.snapprefs.isTargetSnappable(SNAPTARGET_BBOX_CATEGORY) && !m.snapprefs.isTargetSnappable(SNAPTARGET_ALIGNMENT_CATEGORY)) { _bbox_points.clear(); } -- GitLab From 934db935250e2ce9b2eb7088f1878a308fd26463 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Fri, 28 May 2021 23:08:47 +0530 Subject: [PATCH 07/66] partially fix Snap while transforming, alignment snaps are second preference --- src/alignment-snapper.cpp | 11 ++++++++--- src/snap-candidate.h | 13 ++++++++++--- src/snap.h | 1 - src/snapped-point.cpp | 23 +++++++++++++++++++++-- 4 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/alignment-snapper.cpp b/src/alignment-snapper.cpp index 8be363ce68..839b238ad0 100644 --- a/src/alignment-snapper.cpp +++ b/src/alignment-snapper.cpp @@ -272,14 +272,15 @@ void Inkscape::AlignmentSnapper::freeSnap(IntermSnapResults &isr, { bool p_is_bbox = p.getSourceType() & SNAPSOURCE_BBOX_CATEGORY; bool p_is_node = p.getSourceType() & SNAPSOURCE_NODE_HANDLE; - bool p_is_other = p.getSourceType() & SNAPSOURCE_OTHER_HANDLE; // toggle checks if (!_snap_enabled || !_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_ALIGNMENT_CATEGORY)) return; - // only snap if the source point is a bounding box or a handel - if (!(p_is_bbox || p_is_other || p_is_node)) + unsigned n = (unselected_nodes == nullptr) ? 0 : unselected_nodes->size(); + + // n > 0 : node tool is active + if (!(p_is_bbox || (n > 0 && p_is_node) || (p.considerForAlignment() && p_is_node))) return; if (p.getSourceNum() <= 0){ @@ -287,6 +288,10 @@ void Inkscape::AlignmentSnapper::freeSnap(IntermSnapResults &isr, _findCandidates(_snapmanager->getDocument()->getRoot(), it, true, false); } + if (n > 0) { + //add unselected nodes to _points_to_snap_to + } + _snapBBoxPoints(isr, p, unselected_nodes); } diff --git a/src/snap-candidate.h b/src/snap-candidate.h index 4854fbabec..a3a1387b7d 100644 --- a/src/snap-candidate.h +++ b/src/snap-candidate.h @@ -38,7 +38,8 @@ public: _target_type(target), _source_num(source_num), _target_bbox(std::move(bbox)), - _dist() + _dist(), + _alignment(false) { }; @@ -47,7 +48,8 @@ public: _source_type(source), _target_type(target), _target_bbox(Geom::OptRect()), - _dist() + _dist(), + _alignment(false) { _source_num = -1; } @@ -58,7 +60,8 @@ public: _target_type(Inkscape::SNAPTARGET_UNDEFINED), _source_num(-1), _target_bbox(Geom::OptRect()), - _dist() + _dist(), + _alignment(true) { }; @@ -80,6 +83,7 @@ public: bool operator <(const SnapCandidatePoint &other) const { return _dist < other._dist; } // Needed for sorting the SnapCandidatePoints inline Geom::OptRect const getTargetBBox() const {return _target_bbox;} + inline bool considerForAlignment() const {return _alignment;} private: // Coordinates of the point Geom::Point _point; @@ -108,6 +112,9 @@ private: // For finding the snap candidate closest to the mouse pointer Geom::Coord _dist; + + // Consider this point for alignment snapping + bool _alignment; }; class SnapCandidateItem diff --git a/src/snap.h b/src/snap.h index c5a44de023..309f0c53f2 100644 --- a/src/snap.h +++ b/src/snap.h @@ -83,7 +83,6 @@ public: SKEW, ROTATE }; - /** * Construct a SnapManager for a SPNamedView. * diff --git a/src/snapped-point.cpp b/src/snapped-point.cpp index 6ef67881ab..d5f2a69dc1 100644 --- a/src/snapped-point.cpp +++ b/src/snapped-point.cpp @@ -130,18 +130,37 @@ void Inkscape::SnappedPoint::getPointIfSnapped(Geom::Point &p) const } // search for the closest snapped point +// This function give preference to the snapped points that are not in SNAPTARGET_ALIGNMENT_CATEGORY +// ie. for example, a longer Corner to Corner snap will be given prefrence over a Corner to alignment snap with lesser snapDistance. bool getClosestSP(std::list const &list, Inkscape::SnappedPoint &result) { bool success = false; + bool aligned_success = false; + + Inkscape::SnappedPoint aligned = *list.begin(); for (std::list::const_iterator i = list.begin(); i != list.end(); ++i) { - if ((i == list.begin()) || (*i).getSnapDistance() < result.getSnapDistance()) { + bool alignment = (*i).getTarget() & Inkscape::SNAPTARGET_ALIGNMENT_CATEGORY; + if (i == list.begin()) { + result = *i; + success = true; + aligned = *i; + aligned_success = true; + } else if (alignment && (*i).getSnapDistance() < aligned.getSnapDistance()) { + aligned = *i; + aligned_success = true; + } else if ((*i).getSnapDistance() < result.getSnapDistance()){ + // not alignment snapping result = *i; success = true; } + } - return success; + if (!success && aligned_success) + result = aligned; + + return success ? success : aligned_success; } bool Inkscape::SnappedPoint::isOtherSnapBetter(Inkscape::SnappedPoint const &other_one, bool weighted) const -- GitLab From fbaebcca8ec3327dca58f88d0c0a9479ad80694e Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Sat, 29 May 2021 21:54:08 +0530 Subject: [PATCH 08/66] Added Toggle snapping to nodes in same path --- share/ui/toolbar-snap.ui | 9 +++++++++ src/actions/actions-canvas-snapping.cpp | 9 ++++++++- src/alignment-snapper.cpp | 11 ++++++----- src/attributes.cpp | 1 + src/attributes.h | 1 + src/object/sp-namedview.cpp | 6 ++++++ src/snap-preferences.cpp | 13 +------------ 7 files changed, 32 insertions(+), 18 deletions(-) diff --git a/share/ui/toolbar-snap.ui b/share/ui/toolbar-snap.ui index 5f0c8e9b4e..b1be82a976 100644 --- a/share/ui/toolbar-snap.ui +++ b/share/ui/toolbar-snap.ui @@ -229,6 +229,15 @@ + + + True + doc.snap-alignment-self + snap + Self Alignment + + + diff --git a/src/actions/actions-canvas-snapping.cpp b/src/actions/actions-canvas-snapping.cpp index 1cbc2869cf..d8e737baff 100644 --- a/src/actions/actions-canvas-snapping.cpp +++ b/src/actions/actions-canvas-snapping.cpp @@ -68,6 +68,10 @@ canvas_snapping_toggle(SPDocument* document, const SPAttr option) v = nv->snap_manager.snapprefs.isTargetSnappable(Inkscape::SNAPTARGET_ALIGNMENT_CATEGORY); repr->setAttributeBoolean("inkscape:snap-alignment", !v); break; + case SPAttr::INKSCAPE_SNAP_ALIGNMENT_SELF: + v = nv->snap_manager.snapprefs.isTargetSnappable(Inkscape::SNAPTARGET_ALIGNMENT_HANDLE); + repr->setAttributeBoolean("inkscape:snap-alignment-self", !v); + break; // BBox case SPAttr::INKSCAPE_SNAP_BBOX: @@ -190,7 +194,8 @@ std::vector> raw_data_canvas_snapping = { {"doc.snap-global-toggle", N_("Snapping"), "Snap", N_("Toggle snapping on/off") }, - {"doc.snap-alignment", N_("Snap Objects that Align"), "Snap", N_("Toggle alignment snapping on/off") }, + {"doc.snap-alignment", N_("Snap Objects that Align"), "Snap", N_("Toggle alignment snapping") }, + {"doc.snap-alignment-self", N_("Snap Nodes that Align"), "Snap", N_("Toggle alignment snapping to nodes in the same path")}, {"doc.snap-bbox", N_("Snap Bounding Boxes"), "Snap", N_("Toggle snapping to bounding boxes (global)") }, {"doc.snap-bbox-edge", N_("Snap Bounding Box Edges"), "Snap", N_("Toggle snapping to bounding-box edges") }, @@ -226,6 +231,7 @@ add_actions_canvas_snapping(SPDocument* document) map->add_action_bool( "snap-global-toggle", sigc::bind(sigc::ptr_fun(&canvas_snapping_toggle), document, SPAttr::INKSCAPE_SNAP_GLOBAL)); map->add_action_bool( "snap-alignment", sigc::bind(sigc::ptr_fun(&canvas_snapping_toggle), document, SPAttr::INKSCAPE_SNAP_ALIGNMENT)); + map->add_action_bool( "snap-alignment-self", sigc::bind(sigc::ptr_fun(&canvas_snapping_toggle), document, SPAttr::INKSCAPE_SNAP_ALIGNMENT_SELF)); map->add_action_bool( "snap-bbox", sigc::bind(sigc::ptr_fun(&canvas_snapping_toggle), document, SPAttr::INKSCAPE_SNAP_BBOX)); map->add_action_bool( "snap-bbox-edge", sigc::bind(sigc::ptr_fun(&canvas_snapping_toggle), document, SPAttr::INKSCAPE_SNAP_BBOX_EDGE)); @@ -316,6 +322,7 @@ set_actions_canvas_snapping(SPDocument* document) bool alignment = nv->snap_manager.snapprefs.isTargetSnappable(Inkscape::SNAPTARGET_ALIGNMENT_CATEGORY); set_actions_canvas_snapping_helper(map, "snap-alignment", alignment, global); + set_actions_canvas_snapping_helper(map, "snap-alignment-self", nv->snap_manager.snapprefs.isSnapButtonEnabled(Inkscape::SNAPTARGET_ALIGNMENT_HANDLE), global && alignment); bool bbox = nv->snap_manager.snapprefs.isTargetSnappable(Inkscape::SNAPTARGET_BBOX_CATEGORY); set_actions_canvas_snapping_helper(map, "snap-bbox", bbox, global); diff --git a/src/alignment-snapper.cpp b/src/alignment-snapper.cpp index 839b238ad0..ddfd5773d3 100644 --- a/src/alignment-snapper.cpp +++ b/src/alignment-snapper.cpp @@ -48,7 +48,10 @@ Inkscape::AlignmentSnapper::AlignmentSnapper(SnapManager *sm, Geom::Coord const Inkscape::AlignmentSnapper::~AlignmentSnapper() { _candidates->clear(); + delete _candidates; + _points_to_snap_to->clear(); + delete _points_to_snap_to; } void Inkscape::AlignmentSnapper::_findCandidates(SPObject* parent, @@ -216,7 +219,9 @@ void Inkscape::AlignmentSnapper::_snapBBoxPoints(IntermSnapResults &isr, _collectBBoxPoints(p.getSourceNum() <= 0); - if (unselected_nodes != nullptr && unselected_nodes->size() > 0) { + if (unselected_nodes != nullptr && + unselected_nodes->size() > 0 && + _snapmanager->snapprefs.isTargetSnappable(Inkscape::SNAPTARGET_ALIGNMENT_HANDLE)) { g_assert(_points_to_snap_to != nullptr); _points_to_snap_to->insert(_points_to_snap_to->end(), unselected_nodes->begin(), unselected_nodes->end()); } @@ -288,10 +293,6 @@ void Inkscape::AlignmentSnapper::freeSnap(IntermSnapResults &isr, _findCandidates(_snapmanager->getDocument()->getRoot(), it, true, false); } - if (n > 0) { - //add unselected nodes to _points_to_snap_to - } - _snapBBoxPoints(isr, p, unselected_nodes); } diff --git a/src/attributes.cpp b/src/attributes.cpp index d57bf192aa..56a270b284 100644 --- a/src/attributes.cpp +++ b/src/attributes.cpp @@ -100,6 +100,7 @@ static SPStyleProp const props[] = { {SPAttr::INKSCAPE_WINDOW_MAXIMIZED, "inkscape:window-maximized"}, {SPAttr::INKSCAPE_SNAP_GLOBAL, "inkscape:snap-global"}, {SPAttr::INKSCAPE_SNAP_ALIGNMENT, "inkscape:snap-alignment"}, + {SPAttr::INKSCAPE_SNAP_ALIGNMENT_SELF, "inkscape:snap-alignment-self"}, {SPAttr::INKSCAPE_SNAP_PERP, "inkscape:snap-perpendicular"}, {SPAttr::INKSCAPE_SNAP_TANG, "inkscape:snap-tangential"}, {SPAttr::INKSCAPE_SNAP_BBOX, "inkscape:snap-bbox"}, diff --git a/src/attributes.h b/src/attributes.h index 7abae86f9a..468525652a 100644 --- a/src/attributes.h +++ b/src/attributes.h @@ -99,6 +99,7 @@ enum class SPAttr { INKSCAPE_WINDOW_MAXIMIZED, INKSCAPE_SNAP_GLOBAL, INKSCAPE_SNAP_ALIGNMENT, + INKSCAPE_SNAP_ALIGNMENT_SELF, INKSCAPE_SNAP_PERP, INKSCAPE_SNAP_TANG, INKSCAPE_SNAP_BBOX, diff --git a/src/object/sp-namedview.cpp b/src/object/sp-namedview.cpp index 3624eabf09..4ba481e0a2 100644 --- a/src/object/sp-namedview.cpp +++ b/src/object/sp-namedview.cpp @@ -247,6 +247,8 @@ void SPNamedView::build(SPDocument *document, Inkscape::XML::Node *repr) { this->readAttr(SPAttr::INKSCAPE_SNAP_BBOX_EDGE); this->readAttr(SPAttr::INKSCAPE_SNAP_BBOX_CORNER); this->readAttr(SPAttr::INKSCAPE_SNAP_PAGE_BORDER); + this->readAttr(SPAttr::INKSCAPE_SNAP_ALIGNMENT); + this->readAttr(SPAttr::INKSCAPE_SNAP_ALIGNMENT_SELF); this->readAttr(SPAttr::INKSCAPE_CURRENT_LAYER); this->readAttr(SPAttr::INKSCAPE_CONNECTOR_SPACING); this->readAttr(SPAttr::INKSCAPE_LOCKGUIDES); @@ -541,6 +543,10 @@ void SPNamedView::set(SPAttr key, const gchar* value) { this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_ALIGNMENT_CATEGORY, value ? sp_str_to_bool(value) : FALSE); this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; + case SPAttr::INKSCAPE_SNAP_ALIGNMENT_SELF: + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_ALIGNMENT_HANDLE, value ? sp_str_to_bool(value) : FALSE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; case SPAttr::INKSCAPE_CURRENT_LAYER: this->default_layer_id = value ? g_quark_from_string(value) : 0; this->requestModified(SP_OBJECT_MODIFIED_FLAG); diff --git a/src/snap-preferences.cpp b/src/snap-preferences.cpp index 91292b9ec7..a4b272cdcd 100644 --- a/src/snap-preferences.cpp +++ b/src/snap-preferences.cpp @@ -122,18 +122,7 @@ void Inkscape::SnapPreferences::_mapTargetToArrayIndex(Inkscape::SnapTargetType if (target & Inkscape::SNAPTARGET_ALIGNMENT_CATEGORY) { group_on = isTargetSnappable(SNAPTARGET_ALIGNMENT_CATEGORY); - //switch (target) { - //case SNAPTARGET_ALIGNMENT_BBOX_CORNER: - //case SNAPTARGET_ALIGNMENT_BBOX_MIDPOINT: - //case SNAPTARGET_ALIGNMENT_BBOX_EDGE_MIDPOINT: - //case SNAPTARGET_ALIGNMENT_PAGE_CENTER: - //case SNAPTARGET_ALIGNMENT_PAGE_CORNER: - //case SNAPTARGET_ALIGNMENT_HANDLE: - //target = SNAPTARGET_ALIGNMENT_CATEGORY; - //default: - //g_warning("Snap-preferences warning: Undefined snap target (#%i)", target); - //break; - //} + return; } if (target & SNAPTARGET_OTHERS_CATEGORY) { -- GitLab From ed8210835c65d57f67b936fd4cf274d804b9e469 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Sat, 29 May 2021 21:55:34 +0530 Subject: [PATCH 09/66] Modified getClosestSP and isOtherSnapBetter Other snap targets are given priority over Alignment Snapping Bug: upper left corner is only snapped by alignment --- src/snapped-point.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/snapped-point.cpp b/src/snapped-point.cpp index d5f2a69dc1..af80b5931e 100644 --- a/src/snapped-point.cpp +++ b/src/snapped-point.cpp @@ -137,20 +137,21 @@ bool getClosestSP(std::list const &list, Inkscape::Snapp bool success = false; bool aligned_success = false; - Inkscape::SnappedPoint aligned = *list.begin(); + Inkscape::SnappedPoint aligned; for (std::list::const_iterator i = list.begin(); i != list.end(); ++i) { bool alignment = (*i).getTarget() & Inkscape::SNAPTARGET_ALIGNMENT_CATEGORY; if (i == list.begin()) { result = *i; - success = true; + success = !alignment; aligned = *i; - aligned_success = true; - } else if (alignment && (*i).getSnapDistance() < aligned.getSnapDistance()) { + aligned_success = alignment; + } else if (alignment) { + if (!aligned_success || (*i).getSnapDistance() < aligned.getSnapDistance()) { aligned = *i; aligned_success = true; - } else if ((*i).getSnapDistance() < result.getSnapDistance()){ - // not alignment snapping + } + } else if (!success || (*i).getSnapDistance() < result.getSnapDistance()){ result = *i; success = true; } @@ -170,6 +171,10 @@ bool Inkscape::SnappedPoint::isOtherSnapBetter(Inkscape::SnappedPoint const &oth return false; } + if (other_one.getTarget() & Inkscape::SNAPTARGET_ALIGNMENT_CATEGORY) { + return false; + } + if (!getSnapped() && other_one.getSnapped()) { return true; } -- GitLab From adcff386601956e5477467af7ede1cfb1d010bbd Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Sun, 30 May 2021 11:26:18 +0530 Subject: [PATCH 10/66] fixed isOtherSnapBetter --- src/alignment-snapper.cpp | 1 + src/snapped-point.cpp | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/alignment-snapper.cpp b/src/alignment-snapper.cpp index ddfd5773d3..28498afe3b 100644 --- a/src/alignment-snapper.cpp +++ b/src/alignment-snapper.cpp @@ -141,6 +141,7 @@ void Inkscape::AlignmentSnapper::_findCandidates(SPObject* parent, if (dynamic_cast(item)) { _findCandidates(&o, it, false, clip_or_mask, additional_affine); } else { + // TODO: check if the item is visible on canvas // Finally add the object to _candidates. _candidates->push_back(SnapCandidateItem(item, clip_or_mask, additional_affine)); // For debugging: print the id of the candidate to the console diff --git a/src/snapped-point.cpp b/src/snapped-point.cpp index af80b5931e..2b33249021 100644 --- a/src/snapped-point.cpp +++ b/src/snapped-point.cpp @@ -171,10 +171,6 @@ bool Inkscape::SnappedPoint::isOtherSnapBetter(Inkscape::SnappedPoint const &oth return false; } - if (other_one.getTarget() & Inkscape::SNAPTARGET_ALIGNMENT_CATEGORY) { - return false; - } - if (!getSnapped() && other_one.getSnapped()) { return true; } -- GitLab From 77de80dd87b420ae1bcc3249f2312f25e7f07dfc Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Sun, 30 May 2021 12:10:48 +0530 Subject: [PATCH 11/66] _findCandidate only looks at items visible in the viewport --- src/alignment-snapper.cpp | 41 +++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/src/alignment-snapper.cpp b/src/alignment-snapper.cpp index 28498afe3b..068d6d3ac3 100644 --- a/src/alignment-snapper.cpp +++ b/src/alignment-snapper.cpp @@ -141,19 +141,36 @@ void Inkscape::AlignmentSnapper::_findCandidates(SPObject* parent, if (dynamic_cast(item)) { _findCandidates(&o, it, false, clip_or_mask, additional_affine); } else { - // TODO: check if the item is visible on canvas - // Finally add the object to _candidates. - _candidates->push_back(SnapCandidateItem(item, clip_or_mask, additional_affine)); - // For debugging: print the id of the candidate to the console - // SPObject *obj = (SPObject*)item; - // std::cout << "Snap candidate added: " << obj->getId() << std::endl; - if (_candidates->size() > 200) { // This makes Inkscape crawl already - static Glib::Timer timer; - if (timer.elapsed() > 1.0) { - timer.reset(); - std::cout << "Warning: limit of 200 snap target paths reached, some will be ignored" << std::endl; + Geom::OptRect bbox_of_item; + Preferences *prefs = Preferences::get(); + int prefs_bbox = prefs->getBool("/tools/bounding_box", false); + // We'll only need to obtain the visual bounding box if the user preferences tell + // us to, AND if we are snapping to the bounding box itself. If we're snapping to + // paths only, then we can just as well use the geometric bounding box (which is faster) + SPItem::BBoxType bbox_type = (!prefs_bbox && _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_BBOX_CATEGORY)) ? + SPItem::VISUAL_BBOX : SPItem::GEOMETRIC_BBOX; + if (clip_or_mask) { + // Oh oh, this will get ugly. We cannot use sp_item_i2d_affine directly because we need to + // insert an additional transformation in document coordinates (code copied from sp_item_i2d_affine) + bbox_of_item = item->bounds(bbox_type, item->i2doc_affine() * additional_affine * dt->doc2dt()); + } else { + bbox_of_item = item->desktopBounds(bbox_type); + } + if (bbox_of_item) { + if (_snapmanager->getDesktop()->get_display_area().contains(bbox_of_item->midpoint())) + // Finally add the object to _candidates. + _candidates->push_back(SnapCandidateItem(item, clip_or_mask, additional_affine)); + // For debugging: print the id of the candidate to the console + // SPObject *obj = (SPObject*)item; + // std::cout << "Snap candidate added: " << obj->getId() << std::endl; + if (_candidates->size() > 200) { // This makes Inkscape crawl already + static Glib::Timer timer; + if (timer.elapsed() > 1.0) { + timer.reset(); + std::cout << "Warning: limit of 200 snap target paths reached, some will be ignored" << std::endl; + } + break; } - break; } } } -- GitLab From 5ac9fb42add0ffdae9c74aee6f71048a12d90da4 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Sun, 30 May 2021 12:45:15 +0530 Subject: [PATCH 12/66] Added Constrained snap --- src/alignment-snapper.cpp | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/alignment-snapper.cpp b/src/alignment-snapper.cpp index 068d6d3ac3..2179af100c 100644 --- a/src/alignment-snapper.cpp +++ b/src/alignment-snapper.cpp @@ -246,6 +246,8 @@ void Inkscape::AlignmentSnapper::_snapBBoxPoints(IntermSnapResults &isr, SnappedPoint sx; SnappedPoint sy; + bool consider_x = true; + bool consider_y = true; bool success = false; //bool strict_snapping = _snapmanager->snapprefs.getStrictSnapping(); @@ -261,16 +263,19 @@ void Inkscape::AlignmentSnapper::_snapBBoxPoints(IntermSnapResults &isr, Geom::Point point_on_y(target_pt.x(), p.getPoint().y()); Geom::Coord distY = Geom::L2(point_on_y - p.getPoint()); - // TODO: What about constraints? - if (!c.isUndefined()) { + if (!c.isUndefined() && c.isLinear()) { + if (c.getDirection().x() == 0) + consider_y = false; // consider vertical snapping if moving vertically + else + consider_x = false; // consider horizontal snapping if moving horizontally } - if (distX < getSnapperTolerance()) { + if (consider_x && distX < getSnapperTolerance()) { sx = SnappedPoint(point_on_x, source2alignment(p.getSourceType()), p.getSourceNum(), k.getTargetType(), distX, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true, k.getTargetBBox()); success = true; } - if (distY < getSnapperTolerance()) { + if (consider_y && distY < getSnapperTolerance()) { sy = SnappedPoint(point_on_y, source2alignment(p.getSourceType()), p.getSourceNum(), k.getTargetType(), distY, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true, k.getTargetBBox()); success = true; } @@ -321,6 +326,28 @@ void Inkscape::AlignmentSnapper::constrainedSnap(IntermSnapResults &isr, std::vector const *it, std::vector *unselected_nodes) const { + bool p_is_bbox = p.getSourceType() & SNAPSOURCE_BBOX_CATEGORY; + bool p_is_node = p.getSourceType() & SNAPSOURCE_NODE_HANDLE; + + // project the mouse pointer onto the constraint. Only the projected point will be considered for snapping + Geom::Point pp = c.projection(p.getPoint()); + + // toggle checks + if (!_snap_enabled || !_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_ALIGNMENT_CATEGORY)) + return; + + unsigned n = (unselected_nodes == nullptr) ? 0 : unselected_nodes->size(); + + // n > 0 : node tool is active + if (!(p_is_bbox || (n > 0 && p_is_node) || (p.considerForAlignment() && p_is_node))) + return; + + if (p.getSourceNum() <= 0){ + _candidates->clear(); + _findCandidates(_snapmanager->getDocument()->getRoot(), it, true, false); + } + + _snapBBoxPoints(isr, p, unselected_nodes, c, pp); } bool Inkscape::AlignmentSnapper::ThisSnapperMightSnap() const -- GitLab From 988885165f989d94fcce5010530d8382af51ec67 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Wed, 2 Jun 2021 10:09:30 +0530 Subject: [PATCH 13/66] SnappedPoint now stores the Alignment Target --- src/alignment-snapper.cpp | 24 ++++++++++++++++++++++-- src/object/sp-namedview.cpp | 2 +- src/snapped-point.cpp | 26 ++++++++++++++++++++++++++ src/snapped-point.h | 3 +++ 4 files changed, 52 insertions(+), 3 deletions(-) diff --git a/src/alignment-snapper.cpp b/src/alignment-snapper.cpp index 2179af100c..94285cb947 100644 --- a/src/alignment-snapper.cpp +++ b/src/alignment-snapper.cpp @@ -271,12 +271,32 @@ void Inkscape::AlignmentSnapper::_snapBBoxPoints(IntermSnapResults &isr, } if (consider_x && distX < getSnapperTolerance()) { - sx = SnappedPoint(point_on_x, source2alignment(p.getSourceType()), p.getSourceNum(), k.getTargetType(), distX, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true, k.getTargetBBox()); + sx = SnappedPoint(point_on_x, + p.getPoint(), + source2alignment(p.getSourceType()), + p.getSourceNum(), + k.getTargetType(), + distX, + getSnapperTolerance(), + getSnapperAlwaysSnap(), + false, + true, + k.getTargetBBox()); success = true; } if (consider_y && distY < getSnapperTolerance()) { - sy = SnappedPoint(point_on_y, source2alignment(p.getSourceType()), p.getSourceNum(), k.getTargetType(), distY, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true, k.getTargetBBox()); + sy = SnappedPoint(point_on_y, + p.getPoint(), + source2alignment(p.getSourceType()), + p.getSourceNum(), + k.getTargetType(), + distY, + getSnapperTolerance(), + getSnapperAlwaysSnap(), + false, + true, + k.getTargetBBox()); success = true; } } diff --git a/src/object/sp-namedview.cpp b/src/object/sp-namedview.cpp index 4ba481e0a2..72b98c6927 100644 --- a/src/object/sp-namedview.cpp +++ b/src/object/sp-namedview.cpp @@ -317,7 +317,7 @@ void SPNamedView::set(SPAttr key, const gchar* value) { this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SPAttr::ALIGNMENTTOLERANCE: - this->snap_manager.snapprefs.setAlignementTolerance(value ? g_ascii_strtod(value, nullptr) : 20); + this->snap_manager.snapprefs.setAlignementTolerance(value ? g_ascii_strtod(value, nullptr) : 5); this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SPAttr::GUIDECOLOR: diff --git a/src/snapped-point.cpp b/src/snapped-point.cpp index 2b33249021..1dd4df4a92 100644 --- a/src/snapped-point.cpp +++ b/src/snapped-point.cpp @@ -17,6 +17,28 @@ // overloaded constructor Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained, Geom::OptRect target_bbox) : _point(p), + _alignment_target(Geom::Point(0,0)), + _tangent(Geom::Point(0,0)), + _source(source), + _source_num(source_num), + _target(target), + _at_intersection (false), + _constrained_snap (constrained_snap), + _fully_constrained (fully_constrained), + _distance(d), + _tolerance(std::max(t,1.0)),// tolerance should never be smaller than 1 px, as it is used for normalization in isOtherSnapBetter. We don't want a division by zero. + _always_snap(a), + _second_distance (Geom::infinity()), + _second_tolerance (1), + _second_always_snap (false), + _target_bbox(std::move(target_bbox)), + _pointer_distance (Geom::infinity()) +{ +} + +Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, Geom::Point const &ap, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained, Geom::OptRect target_bbox) : + _point(p), + _alignment_target(ap), _tangent(Geom::Point(0,0)), _source(source), _source_num(source_num), @@ -37,6 +59,7 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const Inkscape::SnappedPoint::SnappedPoint(Inkscape::SnapCandidatePoint const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained) : _point (p.getPoint()), + _alignment_target(Geom::Point(0,0)), _tangent (Geom::Point(0,0)), _source (p.getSourceType()), _source_num (p.getSourceNum()), @@ -57,6 +80,7 @@ Inkscape::SnappedPoint::SnappedPoint(Inkscape::SnapCandidatePoint const &p, Snap Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &at_intersection, bool const &constrained_snap, bool const &fully_constrained, Geom::Coord const &d2, Geom::Coord const &t2, bool const &a2) : _point(p), + _alignment_target(Geom::Point(0,0)), _tangent (Geom::Point(0,0)), _source(source), _source_num(source_num), @@ -79,6 +103,7 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const Inkscape::SnappedPoint::SnappedPoint(): _point (Geom::Point(0,0)), + _alignment_target(Geom::Point(0,0)), _tangent (Geom::Point(0,0)), _source (SNAPSOURCE_UNDEFINED), _source_num (-1), @@ -99,6 +124,7 @@ Inkscape::SnappedPoint::SnappedPoint(): Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p): _point (p), + _alignment_target(Geom::Point(0,0)), _tangent (Geom::Point(0,0)), _source (SNAPSOURCE_UNDEFINED), _source_num (-1), diff --git a/src/snapped-point.h b/src/snapped-point.h index 75b5472ccc..5954d5f672 100644 --- a/src/snapped-point.h +++ b/src/snapped-point.h @@ -31,6 +31,7 @@ public: SnappedPoint(Geom::Point const &p); SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &at_intersection, bool const &constrained_snap, bool const &fully_constrained, Geom::Coord const &d2, Geom::Coord const &t2, bool const &a2); SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained, Geom::OptRect target_bbox = Geom::OptRect()); + SnappedPoint(Geom::Point const &p, Geom::Point const &ap, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained, Geom::OptRect target_bbox); SnappedPoint(SnapCandidatePoint const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained); ~SnappedPoint(); @@ -62,6 +63,7 @@ public: Geom::Point getPoint() const {return _point;} void setPoint(Geom::Point const &p) {_point = p;} Geom::Point getTangent() const {return _tangent;} + Geom::Point getAlignmentTarget() const {return _alignment_target;} bool getAtIntersection() const {return _at_intersection;} bool getFullyConstrained() const {return _fully_constrained;} @@ -97,6 +99,7 @@ public: protected: Geom::Point _point; // Location of the snapped point Geom::Point _tangent; // Tangent of the curve we snapped to, at the snapped point + Geom::Point _alignment_target; // Target point for alignment snapping SnapSourceType _source; // Describes what snapped long _source_num; // Sequence number of the source point that snapped, if that point is part of a set of points. (starting at zero if we might have a set of points; -1 if we only have a single point) SnapTargetType _target; // Describes to what we've snapped to -- GitLab From 822e9640f13fb16128a6b2a6a234d40a931e0765 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Wed, 2 Jun 2021 18:50:58 +0530 Subject: [PATCH 14/66] Snap to Intersection of aligment guides --- src/alignment-snapper.cpp | 27 +++++++++++++++++++++++++++ src/snap-enums.h | 1 + 2 files changed, 28 insertions(+) diff --git a/src/alignment-snapper.cpp b/src/alignment-snapper.cpp index 94285cb947..e82e9a0483 100644 --- a/src/alignment-snapper.cpp +++ b/src/alignment-snapper.cpp @@ -246,9 +246,12 @@ void Inkscape::AlignmentSnapper::_snapBBoxPoints(IntermSnapResults &isr, SnappedPoint sx; SnappedPoint sy; + SnappedPoint si; + bool consider_x = true; bool consider_y = true; bool success = false; + bool intersection = false; //bool strict_snapping = _snapmanager->snapprefs.getStrictSnapping(); for (const auto & k : *_points_to_snap_to) { @@ -300,6 +303,30 @@ void Inkscape::AlignmentSnapper::_snapBBoxPoints(IntermSnapResults &isr, success = true; } } + + if (consider_x && consider_y) { + Geom::Point intersection_p = Geom::Point(sy.getPoint().x(), sx.getPoint().y()); + Geom::Coord d = Geom::L2(intersection_p - p.getPoint()); + + if (d < sqrt(2)*getSnapperTolerance()) { + si = SnappedPoint(intersection_p, + source2alignment(p.getSourceType()), + p.getSourceNum(), + SNAPTARGET_ALIGNMENT_INTERSECTION, + d, + getSnapperTolerance(), + getSnapperAlwaysSnap(), + false, + true, + k.getTargetBBox()); + intersection = true; + } + } + } + + if (intersection) { + isr.points.push_back(si); + return; } if (success) { diff --git a/src/snap-enums.h b/src/snap-enums.h index ae4e146e48..6c6f412a3c 100644 --- a/src/snap-enums.h +++ b/src/snap-enums.h @@ -117,6 +117,7 @@ enum SnapTargetType { SNAPTARGET_ALIGNMENT_PAGE_CENTER, SNAPTARGET_ALIGNMENT_PAGE_CORNER, SNAPTARGET_ALIGNMENT_HANDLE, + SNAPTARGET_ALIGNMENT_INTERSECTION, //------------------------------------------------------------------- SNAPTARGET_MAX_ENUM_VALUE }; -- GitLab From 7304a734500d215270b36b57f31eb9abec414c71 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Thu, 3 Jun 2021 20:01:20 +0530 Subject: [PATCH 15/66] Snap Indicators Bug: PreSnap indicators do not fully disappear Sometime the lines are incomplete --- src/alignment-snapper.cpp | 46 +- src/display/control/canvas-item-ctrl.cpp | 66 ++- src/display/control/canvas-item-ctrl.h | 3 + src/display/control/canvas-item-enums.h | 3 +- .../control/canvas-temporary-item-list.cpp | 7 +- src/display/control/snap-indicator.cpp | 478 ++++++++++-------- src/display/control/snap-indicator.h | 2 + src/seltrans.cpp | 2 + src/snapped-point.cpp | 28 + src/snapped-point.h | 3 + src/ui/tool/control-point-selection.cpp | 2 + 11 files changed, 406 insertions(+), 234 deletions(-) diff --git a/src/alignment-snapper.cpp b/src/alignment-snapper.cpp index e82e9a0483..30ebfec2b9 100644 --- a/src/alignment-snapper.cpp +++ b/src/alignment-snapper.cpp @@ -273,12 +273,13 @@ void Inkscape::AlignmentSnapper::_snapBBoxPoints(IntermSnapResults &isr, consider_x = false; // consider horizontal snapping if moving horizontally } + bool is_target_node = k.getTargetType() & SNAPTARGET_NODE_CATEGORY; if (consider_x && distX < getSnapperTolerance()) { sx = SnappedPoint(point_on_x, - p.getPoint(), + k.getPoint(), source2alignment(p.getSourceType()), p.getSourceNum(), - k.getTargetType(), + is_target_node ? SNAPTARGET_ALIGNMENT_HANDLE : k.getTargetType(), distX, getSnapperTolerance(), getSnapperAlwaysSnap(), @@ -290,10 +291,10 @@ void Inkscape::AlignmentSnapper::_snapBBoxPoints(IntermSnapResults &isr, if (consider_y && distY < getSnapperTolerance()) { sy = SnappedPoint(point_on_y, - p.getPoint(), + k.getPoint(), source2alignment(p.getSourceType()), p.getSourceNum(), - k.getTargetType(), + is_target_node ? SNAPTARGET_ALIGNMENT_HANDLE : k.getTargetType(), distY, getSnapperTolerance(), getSnapperAlwaysSnap(), @@ -302,24 +303,26 @@ void Inkscape::AlignmentSnapper::_snapBBoxPoints(IntermSnapResults &isr, k.getTargetBBox()); success = true; } - } - - if (consider_x && consider_y) { - Geom::Point intersection_p = Geom::Point(sy.getPoint().x(), sx.getPoint().y()); - Geom::Coord d = Geom::L2(intersection_p - p.getPoint()); - if (d < sqrt(2)*getSnapperTolerance()) { - si = SnappedPoint(intersection_p, - source2alignment(p.getSourceType()), - p.getSourceNum(), - SNAPTARGET_ALIGNMENT_INTERSECTION, - d, - getSnapperTolerance(), - getSnapperAlwaysSnap(), - false, - true, - k.getTargetBBox()); - intersection = true; + if (consider_x && consider_y) { + Geom::Point intersection_p = Geom::Point(sy.getPoint().x(), sx.getPoint().y()); + Geom::Coord d = Geom::L2(intersection_p - p.getPoint()); + + if (d < sqrt(2)*getSnapperTolerance()) { + si = SnappedPoint(intersection_p, + sy.getAlignmentTarget(), + sx.getAlignmentTarget(), + source2alignment(p.getSourceType()), + p.getSourceNum(), + SNAPTARGET_ALIGNMENT_INTERSECTION, + d, + getSnapperTolerance(), + getSnapperAlwaysSnap(), + false, + true, + k.getTargetBBox()); + intersection = true; + } } } } @@ -425,6 +428,7 @@ Inkscape::SnapSourceType Inkscape::AlignmentSnapper::source2alignment(SnapSource return SNAPSOURCE_ALIGNMENT_BBOX_MIDPOINT; case SNAPSOURCE_BBOX_EDGE_MIDPOINT: return SNAPSOURCE_ALIGNMENT_BBOX_EDGE_MIDPOINT; + case SNAPSOURCE_NODE_CATEGORY: case SNAPSOURCE_OTHER_HANDLE: return SNAPSOURCE_ALIGNMENT_HANDLE; default: diff --git a/src/display/control/canvas-item-ctrl.cpp b/src/display/control/canvas-item-ctrl.cpp index be9497f7fa..fd6afa5567 100644 --- a/src/display/control/canvas-item-ctrl.cpp +++ b/src/display/control/canvas-item-ctrl.cpp @@ -88,6 +88,22 @@ CanvasItemCtrl::CanvasItemCtrl(CanvasItemGroup *group, Inkscape::CanvasItemCtrlS request_update(); } +/** + * Create a control ctrl for alignment guides + */ +CanvasItemCtrl::CanvasItemCtrl(CanvasItemGroup *group, Inkscape::CanvasItemCtrlShape shape, Geom::Point const &p1, Geom::Point const &p2) + : CanvasItemCtrl(group, shape) +{ + g_assert(shape == CANVAS_ITEM_CTRL_SHAPE_LINE); + + _position = p1; + _position2 = p2; + _is_alignment = true; + + request_update(); +} + + /** * Set the postion. Point is in document coordinates. */ @@ -286,7 +302,7 @@ void CanvasItemCtrl::render(Inkscape::CanvasItemBuffer *buf) return; // Hidden. } - if (!_built) { + if (!_built && !_is_alignment) { build_cache(buf->device_scale); } @@ -296,6 +312,54 @@ void CanvasItemCtrl::render(Inkscape::CanvasItemBuffer *buf) buf->cr->save(); + // there is no cache in case of alignment guides + if (_is_alignment) { + + Geom::Point p1 = _position * _affine; + Geom::Point p2 = _position2 * _affine; + + buf->cr->translate( -buf->rect.left(), -buf->rect.top()); + buf->cr->set_source_rgba(SP_RGBA32_R_F(_stroke), SP_RGBA32_G_F(_stroke), + SP_RGBA32_B_F(_stroke), SP_RGBA32_A_F(_stroke)); + buf->cr->set_line_width(1); + + double x1 = p1.x(); + double y1 = p1.y(); + + double x2 = p2.x(); + double y2 = p2.y(); + + // reject lines that are not horizontal or vertical when rounding off + //if (x1 != x2 && y1 != y2) + //return; + + // this is needed so that the line does not intersect the circles at the ends + if (x1 == x2) { + if (y1 < y2) { + y1 += 4; + y2 -= 4; + } else { + y1 -= 4; + y2 += 4; + } + } else if (y1 == y2) { + if (x1 < x2) { + x1 += 4; + x2 -= 4; + } else { + x1 -= 4; + x2 += 4; + } + } + + buf->cr->move_to(x1, y1); + buf->cr->line_to(x2, y2); + + buf->cr->stroke(); + buf->cr->restore(); + + return; + } // This code works regardless of source type. // 1. Copy the affected part of output to a temporary surface diff --git a/src/display/control/canvas-item-ctrl.h b/src/display/control/canvas-item-ctrl.h index dcfd024302..ec8e247439 100644 --- a/src/display/control/canvas-item-ctrl.h +++ b/src/display/control/canvas-item-ctrl.h @@ -39,6 +39,7 @@ public: CanvasItemCtrl(CanvasItemGroup *group, CanvasItemCtrlType type, Geom::Point const &p); CanvasItemCtrl(CanvasItemGroup *group, CanvasItemCtrlShape shape); CanvasItemCtrl(CanvasItemGroup *group, CanvasItemCtrlShape shape, Geom::Point const &p); + CanvasItemCtrl(CanvasItemGroup *group, CanvasItemCtrlShape shape, Geom::Point const &p1, Geom::Point const &p2); // Geometry void set_position(Geom::Point const &position); @@ -73,10 +74,12 @@ protected: // Geometry Geom::Point _position; + Geom::Point _position2; // Display guint32 *_cache = nullptr; bool _built = false; + bool _is_alignment = false; // Properties CanvasItemCtrlType _type = CANVAS_ITEM_CTRL_TYPE_DEFAULT; diff --git a/src/display/control/canvas-item-enums.h b/src/display/control/canvas-item-enums.h index baad84f534..0fddde0b0c 100644 --- a/src/display/control/canvas-item-enums.h +++ b/src/display/control/canvas-item-enums.h @@ -36,7 +36,8 @@ enum CanvasItemCtrlShape { CANVAS_ITEM_CTRL_SHAPE_CALIGN, // Corner alignment. CANVAS_ITEM_CTRL_SHAPE_MALIGN, // Center (middle) alignment. CANVAS_ITEM_CTRL_SHAPE_BITMAP, - CANVAS_ITEM_CTRL_SHAPE_IMAGE + CANVAS_ITEM_CTRL_SHAPE_IMAGE, + CANVAS_ITEM_CTRL_SHAPE_LINE }; // Applies to control points. diff --git a/src/display/control/canvas-temporary-item-list.cpp b/src/display/control/canvas-temporary-item-list.cpp index b293e861d6..ef7fe6a09c 100644 --- a/src/display/control/canvas-temporary-item-list.cpp +++ b/src/display/control/canvas-temporary-item-list.cpp @@ -37,7 +37,12 @@ TemporaryItem * TemporaryItemList::add_item(CanvasItem *item, unsigned int lifetime) { // beware of strange things happening due to very short timeouts - TemporaryItem * tempitem = new TemporaryItem(item, lifetime); + TemporaryItem * tempitem; + if (lifetime == 0) + tempitem = new TemporaryItem(item, 0, true); + else + tempitem = new TemporaryItem(item, lifetime); + itemlist.push_back(tempitem); tempitem->signal_timeout.connect( sigc::mem_fun(*this, &TemporaryItemList::_item_timeout) ); return tempitem; diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index 4e6adfbc78..ff5d967446 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -66,191 +66,249 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap return; } + bool is_alignment = p.getTarget() & SNAPTARGET_ALIGNMENT_CATEGORY; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); bool value = prefs->getBool("/options/snapindicator/value", true); if (value) { - // TRANSLATORS: undefined target for snapping Glib::ustring target_name = _("UNDEFINED"); - switch (p.getTarget()) { - case SNAPTARGET_UNDEFINED: - target_name = _("UNDEFINED"); - g_warning("Snap target has not been specified"); - break; - case SNAPTARGET_GRID: - target_name = _("grid line"); - break; - case SNAPTARGET_GRID_INTERSECTION: - target_name = _("grid intersection"); - break; - case SNAPTARGET_GRID_PERPENDICULAR: - target_name = _("grid line (perpendicular)"); - break; - case SNAPTARGET_GUIDE: - target_name = _("guide"); - break; - case SNAPTARGET_GUIDE_INTERSECTION: - target_name = _("guide intersection"); - break; - case SNAPTARGET_GUIDE_ORIGIN: - target_name = _("guide origin"); - break; - case SNAPTARGET_GUIDE_PERPENDICULAR: - target_name = _("guide (perpendicular)"); - break; - case SNAPTARGET_GRID_GUIDE_INTERSECTION: - target_name = _("grid-guide intersection"); - break; - case SNAPTARGET_NODE_CUSP: - target_name = _("cusp node"); - break; - case SNAPTARGET_NODE_SMOOTH: - target_name = _("smooth node"); - break; - case SNAPTARGET_PATH: - target_name = _("path"); - break; - case SNAPTARGET_PATH_PERPENDICULAR: - target_name = _("path (perpendicular)"); - break; - case SNAPTARGET_PATH_TANGENTIAL: - target_name = _("path (tangential)"); - break; - case SNAPTARGET_PATH_INTERSECTION: - target_name = _("path intersection"); - break; - case SNAPTARGET_PATH_GUIDE_INTERSECTION: - target_name = _("guide-path intersection"); - break; - case SNAPTARGET_PATH_CLIP: - target_name = _("clip-path"); - break; - case SNAPTARGET_PATH_MASK: - target_name = _("mask-path"); - break; - case SNAPTARGET_BBOX_CORNER: - target_name = _("bounding box corner"); - break; - case SNAPTARGET_BBOX_EDGE: - target_name = _("bounding box side"); - break; - case SNAPTARGET_PAGE_BORDER: - target_name = _("page border"); - break; - case SNAPTARGET_LINE_MIDPOINT: - target_name = _("line midpoint"); - break; - case SNAPTARGET_OBJECT_MIDPOINT: - target_name = _("object midpoint"); - break; - case SNAPTARGET_ROTATION_CENTER: - target_name = _("object rotation center"); - break; - case SNAPTARGET_BBOX_EDGE_MIDPOINT: - target_name = _("bounding box side midpoint"); - break; - case SNAPTARGET_BBOX_MIDPOINT: - target_name = _("bounding box midpoint"); - break; - case SNAPTARGET_PAGE_CORNER: - target_name = _("page corner"); - break; - case SNAPTARGET_ELLIPSE_QUADRANT_POINT: - target_name = _("quadrant point"); - break; - case SNAPTARGET_RECT_CORNER: - case SNAPTARGET_IMG_CORNER: - target_name = _("corner"); - break; - case SNAPTARGET_TEXT_ANCHOR: - target_name = _("text anchor"); - break; - case SNAPTARGET_TEXT_BASELINE: - target_name = _("text baseline"); - break; - case SNAPTARGET_CONSTRAINED_ANGLE: - target_name = _("constrained angle"); - break; - case SNAPTARGET_CONSTRAINT: - target_name = _("constraint"); - break; - default: - g_warning("Snap target not in SnapTargetType enum"); - break; - } - Glib::ustring source_name = _("UNDEFINED"); - switch (p.getSource()) { - case SNAPSOURCE_UNDEFINED: - source_name = _("UNDEFINED"); - g_warning("Snap source has not been specified"); - break; - case SNAPSOURCE_BBOX_CORNER: - source_name = _("Bounding box corner"); - break; - case SNAPSOURCE_BBOX_MIDPOINT: - source_name = _("Bounding box midpoint"); - break; - case SNAPSOURCE_BBOX_EDGE_MIDPOINT: - source_name = _("Bounding box side midpoint"); - break; - case SNAPSOURCE_NODE_SMOOTH: - source_name = _("Smooth node"); - break; - case SNAPSOURCE_NODE_CUSP: - source_name = _("Cusp node"); - break; - case SNAPSOURCE_LINE_MIDPOINT: - source_name = _("Line midpoint"); - break; - case SNAPSOURCE_OBJECT_MIDPOINT: - source_name = _("Object midpoint"); - break; - case SNAPSOURCE_ROTATION_CENTER: - source_name = _("Object rotation center"); - break; - case SNAPSOURCE_NODE_HANDLE: - case SNAPSOURCE_OTHER_HANDLE: - source_name = _("Handle"); - break; - case SNAPSOURCE_PATH_INTERSECTION: - source_name = _("Path intersection"); - break; - case SNAPSOURCE_GUIDE: - source_name = _("Guide"); - break; - case SNAPSOURCE_GUIDE_ORIGIN: - source_name = _("Guide origin"); - break; - case SNAPSOURCE_CONVEX_HULL_CORNER: - source_name = _("Convex hull corner"); - break; - case SNAPSOURCE_ELLIPSE_QUADRANT_POINT: - source_name = _("Quadrant point"); - break; - case SNAPSOURCE_RECT_CORNER: - case SNAPSOURCE_IMG_CORNER: - source_name = _("Corner"); - break; - case SNAPSOURCE_TEXT_ANCHOR: - source_name = _("Text anchor"); - break; - case SNAPSOURCE_GRID_PITCH: - source_name = _("Multiple of grid spacing"); - break; - default: - g_warning("Snap source not in SnapSourceType enum"); - break; + + if (!is_alignment) { + // TRANSLATORS: undefined target for snapping + switch (p.getTarget()) { + case SNAPTARGET_UNDEFINED: + target_name = _("UNDEFINED"); + g_warning("Snap target has not been specified"); + break; + case SNAPTARGET_GRID: + target_name = _("grid line"); + break; + case SNAPTARGET_GRID_INTERSECTION: + target_name = _("grid intersection"); + break; + case SNAPTARGET_GRID_PERPENDICULAR: + target_name = _("grid line (perpendicular)"); + break; + case SNAPTARGET_GUIDE: + target_name = _("guide"); + break; + case SNAPTARGET_GUIDE_INTERSECTION: + target_name = _("guide intersection"); + break; + case SNAPTARGET_GUIDE_ORIGIN: + target_name = _("guide origin"); + break; + case SNAPTARGET_GUIDE_PERPENDICULAR: + target_name = _("guide (perpendicular)"); + break; + case SNAPTARGET_GRID_GUIDE_INTERSECTION: + target_name = _("grid-guide intersection"); + break; + case SNAPTARGET_NODE_CUSP: + target_name = _("cusp node"); + break; + case SNAPTARGET_NODE_SMOOTH: + target_name = _("smooth node"); + break; + case SNAPTARGET_PATH: + target_name = _("path"); + break; + case SNAPTARGET_PATH_PERPENDICULAR: + target_name = _("path (perpendicular)"); + break; + case SNAPTARGET_PATH_TANGENTIAL: + target_name = _("path (tangential)"); + break; + case SNAPTARGET_PATH_INTERSECTION: + target_name = _("path intersection"); + break; + case SNAPTARGET_PATH_GUIDE_INTERSECTION: + target_name = _("guide-path intersection"); + break; + case SNAPTARGET_PATH_CLIP: + target_name = _("clip-path"); + break; + case SNAPTARGET_PATH_MASK: + target_name = _("mask-path"); + break; + case SNAPTARGET_BBOX_CORNER: + target_name = _("bounding box corner"); + break; + case SNAPTARGET_BBOX_EDGE: + target_name = _("bounding box side"); + break; + case SNAPTARGET_PAGE_BORDER: + target_name = _("page border"); + break; + case SNAPTARGET_LINE_MIDPOINT: + target_name = _("line midpoint"); + break; + case SNAPTARGET_OBJECT_MIDPOINT: + target_name = _("object midpoint"); + break; + case SNAPTARGET_ROTATION_CENTER: + target_name = _("object rotation center"); + break; + case SNAPTARGET_BBOX_EDGE_MIDPOINT: + target_name = _("bounding box side midpoint"); + break; + case SNAPTARGET_BBOX_MIDPOINT: + target_name = _("bounding box midpoint"); + break; + case SNAPTARGET_PAGE_CORNER: + target_name = _("page corner"); + break; + case SNAPTARGET_ELLIPSE_QUADRANT_POINT: + target_name = _("quadrant point"); + break; + case SNAPTARGET_RECT_CORNER: + case SNAPTARGET_IMG_CORNER: + target_name = _("corner"); + break; + case SNAPTARGET_TEXT_ANCHOR: + target_name = _("text anchor"); + break; + case SNAPTARGET_TEXT_BASELINE: + target_name = _("text baseline"); + break; + case SNAPTARGET_CONSTRAINED_ANGLE: + target_name = _("constrained angle"); + break; + case SNAPTARGET_CONSTRAINT: + target_name = _("constraint"); + break; + default: + g_warning("Snap target not in SnapTargetType enum"); + break; + } + + switch (p.getSource()) { + case SNAPSOURCE_UNDEFINED: + source_name = _("UNDEFINED"); + g_warning("Snap source has not been specified"); + break; + case SNAPSOURCE_BBOX_CORNER: + source_name = _("Bounding box corner"); + break; + case SNAPSOURCE_BBOX_MIDPOINT: + source_name = _("Bounding box midpoint"); + break; + case SNAPSOURCE_BBOX_EDGE_MIDPOINT: + source_name = _("Bounding box side midpoint"); + break; + case SNAPSOURCE_NODE_SMOOTH: + source_name = _("Smooth node"); + break; + case SNAPSOURCE_NODE_CUSP: + source_name = _("Cusp node"); + break; + case SNAPSOURCE_LINE_MIDPOINT: + source_name = _("Line midpoint"); + break; + case SNAPSOURCE_OBJECT_MIDPOINT: + source_name = _("Object midpoint"); + break; + case SNAPSOURCE_ROTATION_CENTER: + source_name = _("Object rotation center"); + break; + case SNAPSOURCE_NODE_HANDLE: + case SNAPSOURCE_OTHER_HANDLE: + source_name = _("Handle"); + break; + case SNAPSOURCE_PATH_INTERSECTION: + source_name = _("Path intersection"); + break; + case SNAPSOURCE_GUIDE: + source_name = _("Guide"); + break; + case SNAPSOURCE_GUIDE_ORIGIN: + source_name = _("Guide origin"); + break; + case SNAPSOURCE_CONVEX_HULL_CORNER: + source_name = _("Convex hull corner"); + break; + case SNAPSOURCE_ELLIPSE_QUADRANT_POINT: + source_name = _("Quadrant point"); + break; + case SNAPSOURCE_RECT_CORNER: + case SNAPSOURCE_IMG_CORNER: + source_name = _("Corner"); + break; + case SNAPSOURCE_TEXT_ANCHOR: + source_name = _("Text anchor"); + break; + case SNAPSOURCE_GRID_PITCH: + source_name = _("Multiple of grid spacing"); + break; + default: + g_warning("Snap source not in SnapSourceType enum"); + break; + } } //std::cout << "Snapped " << source_name << " to " << target_name << std::endl; remove_snapsource(); // Don't set both the source and target indicators, as these will overlap + double timeout_val = prefs->getDouble("/options/snapindicatorpersistence/value", 2.0); + if (timeout_val < 0.1) { + timeout_val = 0.1; // a zero value would mean infinite persistence (i.e. until new snap occurs) + // Besides, negatives values would ....? + } + // Display the snap indicator (i.e. the cross) - auto ctrl = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CROSS); - ctrl->set_size(11); - ctrl->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); - ctrl->set_position(p.getPoint()); + + Inkscape::CanvasItemCtrl *ctrl; + Inkscape::CanvasItemCtrl *ctrl2; + Inkscape::CanvasItemCtrl *ctrl3; + Inkscape::CanvasItemCtrl *ctrl4; + Inkscape::CanvasItemCtrl *ctrl5; + if (is_alignment) { + // using floor() or ceil() sometimes causes incomplete lines. + double size = round(Geom::L2(p.getPoint() - p.getAlignmentTarget())); + ctrl = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_LINE, p.getPoint(), p.getAlignmentTarget()); + ctrl->set_size(size); + ctrl->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); + + if (p.getTarget() == SNAPTARGET_ALIGNMENT_INTERSECTION) { + double size = round(Geom::L2(p.getPoint() - p.getAlignmentTarget2())); + ctrl2 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_LINE, p.getPoint(), p.getAlignmentTarget2()); + ctrl2->set_size(size); + ctrl2->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); + _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl2, 0)); + + ctrl3 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); + ctrl3->set_size(9); + ctrl3->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); + ctrl3->set_fill(0x00000000); + ctrl3->set_position(p.getAlignmentTarget2()); + _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl3, 0)); + } + + ctrl4 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); + ctrl4->set_size(9); + ctrl4->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); + ctrl4->set_fill(0x00000000); + ctrl4->set_position(p.getPoint()); + + ctrl5 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); + ctrl5->set_size(9); + ctrl5->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); + ctrl5->set_fill(0x00000000); + ctrl5->set_position(p.getAlignmentTarget()); + + _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl, 0)); + _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl4, 0)); + _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl5, 0)); + } else { + ctrl = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CROSS); + ctrl->set_size(11); + ctrl->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); + ctrl->set_position(p.getPoint()); + + _snaptarget = _desktop->add_temporary_canvasitem(ctrl, timeout_val*1000.0); + } // The snap indicator will be deleted after some time-out, and sp_canvas_item_dispose // will be called. This will set canvas->current_item to NULL if the snap indicator was @@ -265,51 +323,46 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap // (https://bugs.launchpad.net/inkscape/+bug/1420301/comments/15) ctrl->set_pickable(false); - double timeout_val = prefs->getDouble("/options/snapindicatorpersistence/value", 2.0); - if (timeout_val < 0.1) { - timeout_val = 0.1; // a zero value would mean infinite persistence (i.e. until new snap occurs) - // Besides, negatives values would ....? - } - - _snaptarget = _desktop->add_temporary_canvasitem(ctrl, timeout_val*1000.0); _snaptarget_is_presnap = pre_snap; // Display the tooltip, which reveals the type of snap source and the type of snap target - Glib::ustring tooltip_str; - if ( (p.getSource() != SNAPSOURCE_GRID_PITCH) && (p.getTarget() != SNAPTARGET_UNDEFINED) ) { - tooltip_str = source_name + _(" to ") + target_name; - } else if (p.getSource() != SNAPSOURCE_UNDEFINED) { - tooltip_str = source_name; - } + if (!is_alignment) { + Glib::ustring tooltip_str; + if ( (p.getSource() != SNAPSOURCE_GRID_PITCH) && (p.getTarget() != SNAPTARGET_UNDEFINED) ) { + tooltip_str = source_name + _(" to ") + target_name; + } else if (p.getSource() != SNAPSOURCE_UNDEFINED) { + tooltip_str = source_name; + } - double fontsize = prefs->getDouble("/tools/measure/fontsize", 10.0); + double fontsize = prefs->getDouble("/tools/measure/fontsize", 10.0); - if (!tooltip_str.empty()) { - Geom::Point tooltip_pos = p.getPoint(); - if (dynamic_cast(_desktop->event_context)) { - // Make sure that the snap tooltips do not overlap the ones from the measure tool - tooltip_pos += _desktop->w2d(Geom::Point(0, -3*fontsize)); - } else { - tooltip_pos += _desktop->w2d(Geom::Point(0, -2*fontsize)); - } + if (!tooltip_str.empty()) { + Geom::Point tooltip_pos = p.getPoint(); + if (dynamic_cast(_desktop->event_context)) { + // Make sure that the snap tooltips do not overlap the ones from the measure tool + tooltip_pos += _desktop->w2d(Geom::Point(0, -3*fontsize)); + } else { + tooltip_pos += _desktop->w2d(Geom::Point(0, -2*fontsize)); + } - auto canvas_tooltip = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), tooltip_pos, tooltip_str); - canvas_tooltip->set_fontsize(fontsize); - canvas_tooltip->set_fill(0xffffffff); - canvas_tooltip->set_background(pre_snap ? 0x33337f40 : 0x33337f7f); + auto canvas_tooltip = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), tooltip_pos, tooltip_str); + canvas_tooltip->set_fontsize(fontsize); + canvas_tooltip->set_fill(0xffffffff); + canvas_tooltip->set_background(pre_snap ? 0x33337f40 : 0x33337f7f); - _snaptarget_tooltip = _desktop->add_temporary_canvasitem(canvas_tooltip, timeout_val*1000.0); - } + _snaptarget_tooltip = _desktop->add_temporary_canvasitem(canvas_tooltip, timeout_val*1000.0); + } - // Display the bounding box, if we snapped to one - Geom::OptRect const bbox = p.getTargetBBox(); - if (bbox) { - auto box = new Inkscape::CanvasItemRect(_desktop->getCanvasTemp(), *bbox); - box->set_stroke(pre_snap ? 0x7f7f7fff : 0xff0000ff); - box->set_dashed(true); - box->set_pickable(false); // Is false by default. - box->set_z_position(0); - _snaptarget_bbox = _desktop->add_temporary_canvasitem(box, timeout_val*1000.0); + // Display the bounding box, if we snapped to one + Geom::OptRect const bbox = p.getTargetBBox(); + if (bbox) { + auto box = new Inkscape::CanvasItemRect(_desktop->getCanvasTemp(), *bbox); + box->set_stroke(pre_snap ? 0x7f7f7fff : 0xff0000ff); + box->set_dashed(true); + box->set_pickable(false); // Is false by default. + box->set_z_position(0); + _snaptarget_bbox = _desktop->add_temporary_canvasitem(box, timeout_val*1000.0); + } } } } @@ -337,6 +390,11 @@ SnapIndicator::remove_snaptarget(bool only_if_presnap) _snaptarget_bbox = nullptr; } + for (auto *item : _alignment_snap_indicators) { + _desktop->remove_temporary_canvasitem(item); + } + _alignment_snap_indicators.clear(); + } void diff --git a/src/display/control/snap-indicator.h b/src/display/control/snap-indicator.h index 463acaf9f2..d961fa9f89 100644 --- a/src/display/control/snap-indicator.h +++ b/src/display/control/snap-indicator.h @@ -45,6 +45,8 @@ protected: TemporaryItem *_snaptarget_tooltip; TemporaryItem *_snaptarget_bbox; TemporaryItem *_snapsource; + + std::list _alignment_snap_indicators; std::list _debugging_points; bool _snaptarget_is_presnap; SPDesktop *_desktop; diff --git a/src/seltrans.cpp b/src/seltrans.cpp index af858f78f2..7e2b90691f 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -490,6 +490,8 @@ void Inkscape::SelTrans::ungrab() _items_centers.clear(); _updateHandles(); } + + _desktop->snapindicator->remove_snaptarget(); } /* fixme: This is really bad, as we compare positions for each stamp (Lauris) */ diff --git a/src/snapped-point.cpp b/src/snapped-point.cpp index 1dd4df4a92..86d0878f34 100644 --- a/src/snapped-point.cpp +++ b/src/snapped-point.cpp @@ -18,6 +18,7 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained, Geom::OptRect target_bbox) : _point(p), _alignment_target(Geom::Point(0,0)), + _alignment_target2(Geom::Point(0,0)), _tangent(Geom::Point(0,0)), _source(source), _source_num(source_num), @@ -39,6 +40,29 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, Geom::Point const &ap, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained, Geom::OptRect target_bbox) : _point(p), _alignment_target(ap), + _alignment_target2(Geom::Point(0,0)), + _tangent(Geom::Point(0,0)), + _source(source), + _source_num(source_num), + _target(target), + _at_intersection (false), + _constrained_snap (constrained_snap), + _fully_constrained (fully_constrained), + _distance(d), + _tolerance(std::max(t,1.0)),// tolerance should never be smaller than 1 px, as it is used for normalization in isOtherSnapBetter. We don't want a division by zero. + _always_snap(a), + _second_distance (Geom::infinity()), + _second_tolerance (1), + _second_always_snap (false), + _target_bbox(std::move(target_bbox)), + _pointer_distance (Geom::infinity()) +{ +} + +Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, Geom::Point const &ap, Geom::Point const &ap2, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained, Geom::OptRect target_bbox) : + _point(p), + _alignment_target(ap), + _alignment_target2(ap2), _tangent(Geom::Point(0,0)), _source(source), _source_num(source_num), @@ -60,6 +84,7 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, Geom::Point const &ap Inkscape::SnappedPoint::SnappedPoint(Inkscape::SnapCandidatePoint const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained) : _point (p.getPoint()), _alignment_target(Geom::Point(0,0)), + _alignment_target2(Geom::Point(0,0)), _tangent (Geom::Point(0,0)), _source (p.getSourceType()), _source_num (p.getSourceNum()), @@ -81,6 +106,7 @@ Inkscape::SnappedPoint::SnappedPoint(Inkscape::SnapCandidatePoint const &p, Snap Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &at_intersection, bool const &constrained_snap, bool const &fully_constrained, Geom::Coord const &d2, Geom::Coord const &t2, bool const &a2) : _point(p), _alignment_target(Geom::Point(0,0)), + _alignment_target2(Geom::Point(0,0)), _tangent (Geom::Point(0,0)), _source(source), _source_num(source_num), @@ -104,6 +130,7 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const Inkscape::SnappedPoint::SnappedPoint(): _point (Geom::Point(0,0)), _alignment_target(Geom::Point(0,0)), + _alignment_target2(Geom::Point(0,0)), _tangent (Geom::Point(0,0)), _source (SNAPSOURCE_UNDEFINED), _source_num (-1), @@ -125,6 +152,7 @@ Inkscape::SnappedPoint::SnappedPoint(): Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p): _point (p), _alignment_target(Geom::Point(0,0)), + _alignment_target2(Geom::Point(0,0)), _tangent (Geom::Point(0,0)), _source (SNAPSOURCE_UNDEFINED), _source_num (-1), diff --git a/src/snapped-point.h b/src/snapped-point.h index 5954d5f672..085ee1d86a 100644 --- a/src/snapped-point.h +++ b/src/snapped-point.h @@ -32,6 +32,7 @@ public: SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &at_intersection, bool const &constrained_snap, bool const &fully_constrained, Geom::Coord const &d2, Geom::Coord const &t2, bool const &a2); SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained, Geom::OptRect target_bbox = Geom::OptRect()); SnappedPoint(Geom::Point const &p, Geom::Point const &ap, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained, Geom::OptRect target_bbox); + SnappedPoint(Geom::Point const &p, Geom::Point const &ap, Geom::Point const &ap2, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained, Geom::OptRect target_bbox); SnappedPoint(SnapCandidatePoint const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained); ~SnappedPoint(); @@ -64,6 +65,7 @@ public: void setPoint(Geom::Point const &p) {_point = p;} Geom::Point getTangent() const {return _tangent;} Geom::Point getAlignmentTarget() const {return _alignment_target;} + Geom::Point getAlignmentTarget2() const {return _alignment_target2;} bool getAtIntersection() const {return _at_intersection;} bool getFullyConstrained() const {return _fully_constrained;} @@ -100,6 +102,7 @@ protected: Geom::Point _point; // Location of the snapped point Geom::Point _tangent; // Tangent of the curve we snapped to, at the snapped point Geom::Point _alignment_target; // Target point for alignment snapping + Geom::Point _alignment_target2; // Target point when alignment guides intersect SnapSourceType _source; // Describes what snapped long _source_num; // Sequence number of the source point that snapped, if that point is part of a set of points. (starting at zero if we might have a set of points; -1 if we only have a single point) SnapTargetType _target; // Describes to what we've snapped to diff --git a/src/ui/tool/control-point-selection.cpp b/src/ui/tool/control-point-selection.cpp index 39245f1771..2ee5d617d9 100644 --- a/src/ui/tool/control-point-selection.cpp +++ b/src/ui/tool/control-point-selection.cpp @@ -18,6 +18,7 @@ #include "ui/tool/event-utils.h" #include "ui/tool/transform-handle-set.h" #include "ui/tool/node.h" +#include "display/control/snap-indicator.h" @@ -442,6 +443,7 @@ void ControlPointSelection::_pointDragged(Geom::Point &new_pos, GdkEventMotion * void ControlPointSelection::_pointUngrabbed() { + _desktop->snapindicator->remove_snaptarget(); _original_positions.clear(); _last_trans.clear(); _dragging = false; -- GitLab From 90debc2c582afce6e7ea7fa8acb88e88ea1f7678 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Fri, 4 Jun 2021 21:41:58 +0530 Subject: [PATCH 16/66] minor fixes --- src/display/control/canvas-item-ctrl.cpp | 16 ++++++++-------- .../control/canvas-temporary-item-list.cpp | 5 +++-- src/display/control/snap-indicator.cpp | 10 +++++----- src/ui/tools/tool-base.cpp | 2 ++ 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/display/control/canvas-item-ctrl.cpp b/src/display/control/canvas-item-ctrl.cpp index fd6afa5567..c2fd13bf3e 100644 --- a/src/display/control/canvas-item-ctrl.cpp +++ b/src/display/control/canvas-item-ctrl.cpp @@ -336,19 +336,19 @@ void CanvasItemCtrl::render(Inkscape::CanvasItemBuffer *buf) // this is needed so that the line does not intersect the circles at the ends if (x1 == x2) { if (y1 < y2) { - y1 += 4; - y2 -= 4; + y1 += 3; + y2 -= 3; } else { - y1 -= 4; - y2 += 4; + y1 -= 3; + y2 += 3; } } else if (y1 == y2) { if (x1 < x2) { - x1 += 4; - x2 -= 4; + x1 += 3; + x2 -= 3; } else { - x1 -= 4; - x2 += 4; + x1 -= 3; + x2 += 3; } } diff --git a/src/display/control/canvas-temporary-item-list.cpp b/src/display/control/canvas-temporary-item-list.cpp index ef7fe6a09c..4be97f994c 100644 --- a/src/display/control/canvas-temporary-item-list.cpp +++ b/src/display/control/canvas-temporary-item-list.cpp @@ -40,11 +40,12 @@ TemporaryItemList::add_item(CanvasItem *item, unsigned int lifetime) TemporaryItem * tempitem; if (lifetime == 0) tempitem = new TemporaryItem(item, 0, true); - else + else { tempitem = new TemporaryItem(item, lifetime); + tempitem->signal_timeout.connect( sigc::mem_fun(*this, &TemporaryItemList::_item_timeout) ); + } itemlist.push_back(tempitem); - tempitem->signal_timeout.connect( sigc::mem_fun(*this, &TemporaryItemList::_item_timeout) ); return tempitem; } diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index ff5d967446..7cd32c5b37 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -266,20 +266,20 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap Inkscape::CanvasItemCtrl *ctrl5; if (is_alignment) { // using floor() or ceil() sometimes causes incomplete lines. - double size = round(Geom::L2(p.getPoint() - p.getAlignmentTarget())); + double size = floor(Geom::L2(p.getPoint() - p.getAlignmentTarget())); ctrl = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_LINE, p.getPoint(), p.getAlignmentTarget()); ctrl->set_size(size); ctrl->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); if (p.getTarget() == SNAPTARGET_ALIGNMENT_INTERSECTION) { - double size = round(Geom::L2(p.getPoint() - p.getAlignmentTarget2())); + double size = floor(Geom::L2(p.getPoint() - p.getAlignmentTarget2())); ctrl2 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_LINE, p.getPoint(), p.getAlignmentTarget2()); ctrl2->set_size(size); ctrl2->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl2, 0)); ctrl3 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); - ctrl3->set_size(9); + ctrl3->set_size(7); ctrl3->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); ctrl3->set_fill(0x00000000); ctrl3->set_position(p.getAlignmentTarget2()); @@ -287,13 +287,13 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap } ctrl4 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); - ctrl4->set_size(9); + ctrl4->set_size(7); ctrl4->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); ctrl4->set_fill(0x00000000); ctrl4->set_position(p.getPoint()); ctrl5 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); - ctrl5->set_size(9); + ctrl5->set_size(7); ctrl5->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); ctrl5->set_fill(0x00000000); ctrl5->set_position(p.getAlignmentTarget()); diff --git a/src/ui/tools/tool-base.cpp b/src/ui/tools/tool-base.cpp index b011ce5106..d55f42060c 100644 --- a/src/ui/tools/tool-base.cpp +++ b/src/ui/tools/tool-base.cpp @@ -33,6 +33,7 @@ #include "display/control/canvas-item-catchall.h" // Grab/Ungrab #include "display/control/canvas-item-rotate.h" +#include "display/control/snap-indicator.h" #include "include/gtkmm_version.h" #include "include/macros.h" @@ -1046,6 +1047,7 @@ void ToolBase::grabCanvasEvents(Gdk::EventMask mask) */ void ToolBase::ungrabCanvasEvents() { + desktop->snapindicator->remove_snaptarget(); desktop->getCanvasCatchall()->ungrab(); } -- GitLab From 7b996611d7b24469806c5ab9eb0789e8b5e3a2b0 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Sat, 5 Jun 2021 11:35:24 +0530 Subject: [PATCH 17/66] use CanvasItemCurve to display aligment guides --- src/display/control/canvas-item-ctrl.cpp | 66 +---------------- src/display/control/canvas-item-ctrl.h | 3 - src/display/control/snap-indicator.cpp | 91 ++++++++++++------------ 3 files changed, 47 insertions(+), 113 deletions(-) diff --git a/src/display/control/canvas-item-ctrl.cpp b/src/display/control/canvas-item-ctrl.cpp index c2fd13bf3e..be9497f7fa 100644 --- a/src/display/control/canvas-item-ctrl.cpp +++ b/src/display/control/canvas-item-ctrl.cpp @@ -88,22 +88,6 @@ CanvasItemCtrl::CanvasItemCtrl(CanvasItemGroup *group, Inkscape::CanvasItemCtrlS request_update(); } -/** - * Create a control ctrl for alignment guides - */ -CanvasItemCtrl::CanvasItemCtrl(CanvasItemGroup *group, Inkscape::CanvasItemCtrlShape shape, Geom::Point const &p1, Geom::Point const &p2) - : CanvasItemCtrl(group, shape) -{ - g_assert(shape == CANVAS_ITEM_CTRL_SHAPE_LINE); - - _position = p1; - _position2 = p2; - _is_alignment = true; - - request_update(); -} - - /** * Set the postion. Point is in document coordinates. */ @@ -302,7 +286,7 @@ void CanvasItemCtrl::render(Inkscape::CanvasItemBuffer *buf) return; // Hidden. } - if (!_built && !_is_alignment) { + if (!_built) { build_cache(buf->device_scale); } @@ -312,54 +296,6 @@ void CanvasItemCtrl::render(Inkscape::CanvasItemBuffer *buf) buf->cr->save(); - // there is no cache in case of alignment guides - if (_is_alignment) { - - Geom::Point p1 = _position * _affine; - Geom::Point p2 = _position2 * _affine; - - buf->cr->translate( -buf->rect.left(), -buf->rect.top()); - buf->cr->set_source_rgba(SP_RGBA32_R_F(_stroke), SP_RGBA32_G_F(_stroke), - SP_RGBA32_B_F(_stroke), SP_RGBA32_A_F(_stroke)); - buf->cr->set_line_width(1); - - double x1 = p1.x(); - double y1 = p1.y(); - - double x2 = p2.x(); - double y2 = p2.y(); - - // reject lines that are not horizontal or vertical when rounding off - //if (x1 != x2 && y1 != y2) - //return; - - // this is needed so that the line does not intersect the circles at the ends - if (x1 == x2) { - if (y1 < y2) { - y1 += 3; - y2 -= 3; - } else { - y1 -= 3; - y2 += 3; - } - } else if (y1 == y2) { - if (x1 < x2) { - x1 += 3; - x2 -= 3; - } else { - x1 -= 3; - x2 += 3; - } - } - - buf->cr->move_to(x1, y1); - buf->cr->line_to(x2, y2); - - buf->cr->stroke(); - buf->cr->restore(); - - return; - } // This code works regardless of source type. // 1. Copy the affected part of output to a temporary surface diff --git a/src/display/control/canvas-item-ctrl.h b/src/display/control/canvas-item-ctrl.h index ec8e247439..dcfd024302 100644 --- a/src/display/control/canvas-item-ctrl.h +++ b/src/display/control/canvas-item-ctrl.h @@ -39,7 +39,6 @@ public: CanvasItemCtrl(CanvasItemGroup *group, CanvasItemCtrlType type, Geom::Point const &p); CanvasItemCtrl(CanvasItemGroup *group, CanvasItemCtrlShape shape); CanvasItemCtrl(CanvasItemGroup *group, CanvasItemCtrlShape shape, Geom::Point const &p); - CanvasItemCtrl(CanvasItemGroup *group, CanvasItemCtrlShape shape, Geom::Point const &p1, Geom::Point const &p2); // Geometry void set_position(Geom::Point const &position); @@ -74,12 +73,10 @@ protected: // Geometry Geom::Point _position; - Geom::Point _position2; // Display guint32 *_cache = nullptr; bool _built = false; - bool _is_alignment = false; // Properties CanvasItemCtrlType _type = CANVAS_ITEM_CTRL_TYPE_DEFAULT; diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index 7cd32c5b37..03de7f7291 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -24,6 +24,7 @@ #include "canvas-item-ctrl.h" #include "canvas-item-rect.h" #include "canvas-item-text.h" +#include "canvas-item-curve.h" #include "ui/tools/measure-tool.h" @@ -262,45 +263,56 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap Inkscape::CanvasItemCtrl *ctrl; Inkscape::CanvasItemCtrl *ctrl2; Inkscape::CanvasItemCtrl *ctrl3; - Inkscape::CanvasItemCtrl *ctrl4; - Inkscape::CanvasItemCtrl *ctrl5; if (is_alignment) { // using floor() or ceil() sometimes causes incomplete lines. - double size = floor(Geom::L2(p.getPoint() - p.getAlignmentTarget())); - ctrl = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_LINE, p.getPoint(), p.getAlignmentTarget()); - ctrl->set_size(size); - ctrl->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); + auto line = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p.getPoint(), p.getAlignmentTarget()); + line->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); + line->set_fill(0x00000000); + _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line, 0)); if (p.getTarget() == SNAPTARGET_ALIGNMENT_INTERSECTION) { - double size = floor(Geom::L2(p.getPoint() - p.getAlignmentTarget2())); - ctrl2 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_LINE, p.getPoint(), p.getAlignmentTarget2()); - ctrl2->set_size(size); - ctrl2->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); - _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl2, 0)); - - ctrl3 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); - ctrl3->set_size(7); - ctrl3->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); - ctrl3->set_fill(0x00000000); - ctrl3->set_position(p.getAlignmentTarget2()); - _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl3, 0)); + auto line2 = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p.getPoint(), p.getAlignmentTarget2()); + line2->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); + line2->set_fill(0x00000000); + _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line2, 0)); + + ctrl = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); + ctrl->set_size(7); + ctrl->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); + ctrl->set_fill(0x00000000); + ctrl->set_position(p.getAlignmentTarget2()); + _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl, 0)); + ctrl->set_pickable(false); } - ctrl4 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); - ctrl4->set_size(7); - ctrl4->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); - ctrl4->set_fill(0x00000000); - ctrl4->set_position(p.getPoint()); - - ctrl5 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); - ctrl5->set_size(7); - ctrl5->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); - ctrl5->set_fill(0x00000000); - ctrl5->set_position(p.getAlignmentTarget()); - - _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl, 0)); - _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl4, 0)); - _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl5, 0)); + ctrl2 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); + ctrl2->set_size(7); + ctrl2->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); + ctrl2->set_fill(0x00000000); + ctrl2->set_position(p.getPoint()); + + // The snap indicator will be deleted after some time-out, and sp_canvas_item_dispose + // will be called. This will set canvas->current_item to NULL if the snap indicator was + // the current item, after which any events will go to the root handler instead of any + // item handler. Dragging an object which has just snapped might therefore not be possible + // without selecting / repicking it again. To avoid this, we make sure here that the + // snap indicator will never be picked, and will therefore never be the current item. + // Reported bugs: + // - scrolling when hovering above a pre-snap indicator won't work (for example) + // (https://bugs.launchpad.net/inkscape/+bug/522335/comments/8) + // - dragging doesn't work without repicking + // (https://bugs.launchpad.net/inkscape/+bug/1420301/comments/15) + ctrl2->set_pickable(false); + _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl2, 0)); + + ctrl3 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); + ctrl3->set_size(7); + ctrl3->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); + ctrl3->set_fill(0x00000000); + ctrl3->set_position(p.getAlignmentTarget()); + ctrl3->set_pickable(false); + _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl3, 0)); + } else { ctrl = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CROSS); ctrl->set_size(11); @@ -308,20 +320,9 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap ctrl->set_position(p.getPoint()); _snaptarget = _desktop->add_temporary_canvasitem(ctrl, timeout_val*1000.0); + ctrl->set_pickable(false); } - // The snap indicator will be deleted after some time-out, and sp_canvas_item_dispose - // will be called. This will set canvas->current_item to NULL if the snap indicator was - // the current item, after which any events will go to the root handler instead of any - // item handler. Dragging an object which has just snapped might therefore not be possible - // without selecting / repicking it again. To avoid this, we make sure here that the - // snap indicator will never be picked, and will therefore never be the current item. - // Reported bugs: - // - scrolling when hovering above a pre-snap indicator won't work (for example) - // (https://bugs.launchpad.net/inkscape/+bug/522335/comments/8) - // - dragging doesn't work without repicking - // (https://bugs.launchpad.net/inkscape/+bug/1420301/comments/15) - ctrl->set_pickable(false); _snaptarget_is_presnap = pre_snap; -- GitLab From b5dc15faaeed609c6eec907c517bc3b22367d078 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Sun, 6 Jun 2021 09:17:46 +0530 Subject: [PATCH 18/66] color coding guides --- src/alignment-snapper.cpp | 10 +++---- src/display/control/snap-indicator.cpp | 40 +++++++++++++++++++------- src/display/control/snap-indicator.h | 3 ++ 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/src/alignment-snapper.cpp b/src/alignment-snapper.cpp index 30ebfec2b9..485821db09 100644 --- a/src/alignment-snapper.cpp +++ b/src/alignment-snapper.cpp @@ -197,11 +197,11 @@ void Inkscape::AlignmentSnapper::_collectBBoxPoints(bool const &first_point) con if (_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_PAGE_CORNER)) { Geom::Coord w = (_snapmanager->getDocument())->getWidth().value("px"); Geom::Coord h = (_snapmanager->getDocument())->getHeight().value("px"); - _points_to_snap_to->push_back(SnapCandidatePoint(Geom::Point(0,0), SNAPSOURCE_UNDEFINED, SNAPTARGET_ALIGNMENT_PAGE_CORNER)); - _points_to_snap_to->push_back(SnapCandidatePoint(Geom::Point(0,h), SNAPSOURCE_UNDEFINED, SNAPTARGET_ALIGNMENT_PAGE_CORNER)); - _points_to_snap_to->push_back(SnapCandidatePoint(Geom::Point(w,h), SNAPSOURCE_UNDEFINED, SNAPTARGET_ALIGNMENT_PAGE_CORNER)); - _points_to_snap_to->push_back(SnapCandidatePoint(Geom::Point(w,0), SNAPSOURCE_UNDEFINED, SNAPTARGET_ALIGNMENT_PAGE_CORNER)); - _points_to_snap_to->push_back(SnapCandidatePoint(Geom::Point(w/2.0f,h/2.0f), SNAPSOURCE_UNDEFINED, SNAPTARGET_ALIGNMENT_PAGE_CENTER)); + _points_to_snap_to->push_back(SnapCandidatePoint(Geom::Point(0,0), SNAPSOURCE_ALIGNMENT_PAGE_CORNER, SNAPTARGET_ALIGNMENT_PAGE_CORNER)); + _points_to_snap_to->push_back(SnapCandidatePoint(Geom::Point(0,h), SNAPSOURCE_ALIGNMENT_PAGE_CORNER, SNAPTARGET_ALIGNMENT_PAGE_CORNER)); + _points_to_snap_to->push_back(SnapCandidatePoint(Geom::Point(w,h), SNAPSOURCE_ALIGNMENT_PAGE_CORNER, SNAPTARGET_ALIGNMENT_PAGE_CORNER)); + _points_to_snap_to->push_back(SnapCandidatePoint(Geom::Point(w,0), SNAPSOURCE_ALIGNMENT_PAGE_CORNER, SNAPTARGET_ALIGNMENT_PAGE_CORNER)); + _points_to_snap_to->push_back(SnapCandidatePoint(Geom::Point(w/2.0f,h/2.0f), SNAPSOURCE_ALIGNMENT_PAGE_CENTER, SNAPTARGET_ALIGNMENT_PAGE_CENTER)); } // collect bounding boxes of other objects diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index 03de7f7291..f6cc769dc1 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -263,23 +263,22 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap Inkscape::CanvasItemCtrl *ctrl; Inkscape::CanvasItemCtrl *ctrl2; Inkscape::CanvasItemCtrl *ctrl3; + if (is_alignment) { - // using floor() or ceil() sometimes causes incomplete lines. + auto color = pre_snap ? 0x7f7f7fff : get_guide_color(p.getTarget()); auto line = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p.getPoint(), p.getAlignmentTarget()); - line->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); - line->set_fill(0x00000000); + line->set_stroke(color); _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line, 0)); if (p.getTarget() == SNAPTARGET_ALIGNMENT_INTERSECTION) { auto line2 = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p.getPoint(), p.getAlignmentTarget2()); - line2->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); - line2->set_fill(0x00000000); + line2->set_stroke(color); _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line2, 0)); ctrl = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); ctrl->set_size(7); - ctrl->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); - ctrl->set_fill(0x00000000); + ctrl->set_stroke(color); + ctrl->set_fill(color); ctrl->set_position(p.getAlignmentTarget2()); _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl, 0)); ctrl->set_pickable(false); @@ -287,8 +286,8 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap ctrl2 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); ctrl2->set_size(7); - ctrl2->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); - ctrl2->set_fill(0x00000000); + ctrl2->set_stroke(color); + ctrl2->set_fill(color); ctrl2->set_position(p.getPoint()); // The snap indicator will be deleted after some time-out, and sp_canvas_item_dispose @@ -307,8 +306,8 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap ctrl3 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); ctrl3->set_size(7); - ctrl3->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); - ctrl3->set_fill(0x00000000); + ctrl3->set_stroke(color); + ctrl3->set_fill(color); ctrl3->set_position(p.getAlignmentTarget()); ctrl3->set_pickable(false); _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl3, 0)); @@ -446,6 +445,25 @@ SnapIndicator::remove_debugging_points() _debugging_points.clear(); } +guint32 SnapIndicator::get_guide_color(SnapTargetType t) +{ + switch(t) { + case SNAPTARGET_ALIGNMENT_BBOX_CORNER: + case SNAPTARGET_ALIGNMENT_BBOX_MIDPOINT: + case SNAPTARGET_ALIGNMENT_BBOX_EDGE_MIDPOINT: + return 0xff0000ff; + case SNAPTARGET_ALIGNMENT_PAGE_CENTER: + case SNAPTARGET_ALIGNMENT_PAGE_CORNER: + return 0x00ff00ff; + case SNAPTARGET_ALIGNMENT_HANDLE: + return 0x0000ffff; + case SNAPTARGET_ALIGNMENT_INTERSECTION: + return 0xd13bd1ff; + default: + g_warning("Alignment guide color not handled %i", t); + return 0x000000ff; + } +} } //namespace Display } /* namespace Inkscape */ diff --git a/src/display/control/snap-indicator.h b/src/display/control/snap-indicator.h index d961fa9f89..68f89e3d82 100644 --- a/src/display/control/snap-indicator.h +++ b/src/display/control/snap-indicator.h @@ -18,6 +18,7 @@ */ #include "snapped-point.h" +#include class SPDesktop; @@ -54,6 +55,8 @@ protected: private: SnapIndicator(const SnapIndicator&) = delete; SnapIndicator& operator=(const SnapIndicator&) = delete; + + guint32 get_guide_color(SnapTargetType t); }; } //namespace Display -- GitLab From cae96a7ef204d6ae8c7f81b308c44e8f2ba718fa Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Sun, 6 Jun 2021 09:43:14 +0530 Subject: [PATCH 19/66] fix: (0,0) was always considered for intersection alignment --- src/alignment-snapper.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/alignment-snapper.cpp b/src/alignment-snapper.cpp index 485821db09..0014a0225f 100644 --- a/src/alignment-snapper.cpp +++ b/src/alignment-snapper.cpp @@ -250,7 +250,8 @@ void Inkscape::AlignmentSnapper::_snapBBoxPoints(IntermSnapResults &isr, bool consider_x = true; bool consider_y = true; - bool success = false; + bool success_x = false; + bool success_y = false; bool intersection = false; //bool strict_snapping = _snapmanager->snapprefs.getStrictSnapping(); @@ -286,7 +287,7 @@ void Inkscape::AlignmentSnapper::_snapBBoxPoints(IntermSnapResults &isr, false, true, k.getTargetBBox()); - success = true; + success_x = true; } if (consider_y && distY < getSnapperTolerance()) { @@ -301,10 +302,10 @@ void Inkscape::AlignmentSnapper::_snapBBoxPoints(IntermSnapResults &isr, false, true, k.getTargetBBox()); - success = true; + success_y = true; } - if (consider_x && consider_y) { + if (consider_x && consider_y && success_x && success_y) { Geom::Point intersection_p = Geom::Point(sy.getPoint().x(), sx.getPoint().y()); Geom::Coord d = Geom::L2(intersection_p - p.getPoint()); @@ -332,7 +333,7 @@ void Inkscape::AlignmentSnapper::_snapBBoxPoints(IntermSnapResults &isr, return; } - if (success) { + if (success_x || success_y) { if (sx.getSnapDistance() < sy.getSnapDistance()) { isr.points.push_back(sx); } else { -- GitLab From 9c8d32831dd99f3e18bf846b33cbadc3531f2e6e Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Sun, 6 Jun 2021 11:11:15 +0530 Subject: [PATCH 20/66] always the closes snap TARGET is selected --- src/alignment-snapper.cpp | 4 ++-- src/snapped-point.cpp | 22 +++++++++++----------- src/snapped-point.h | 30 ++++++++++++++++++++++++++---- 3 files changed, 39 insertions(+), 17 deletions(-) diff --git a/src/alignment-snapper.cpp b/src/alignment-snapper.cpp index 0014a0225f..b333495aeb 100644 --- a/src/alignment-snapper.cpp +++ b/src/alignment-snapper.cpp @@ -275,7 +275,7 @@ void Inkscape::AlignmentSnapper::_snapBBoxPoints(IntermSnapResults &isr, } bool is_target_node = k.getTargetType() & SNAPTARGET_NODE_CATEGORY; - if (consider_x && distX < getSnapperTolerance()) { + if (consider_x && distX < getSnapperTolerance() && Geom::L2(target_pt - point_on_x) < sx.getDistanceToAignTarget()) { sx = SnappedPoint(point_on_x, k.getPoint(), source2alignment(p.getSourceType()), @@ -290,7 +290,7 @@ void Inkscape::AlignmentSnapper::_snapBBoxPoints(IntermSnapResults &isr, success_x = true; } - if (consider_y && distY < getSnapperTolerance()) { + if (consider_y && distY < getSnapperTolerance() && Geom::L2(target_pt - point_on_y) < sy.getDistanceToAignTarget()) { sy = SnappedPoint(point_on_y, k.getPoint(), source2alignment(p.getSourceType()), diff --git a/src/snapped-point.cpp b/src/snapped-point.cpp index 86d0878f34..3109f542bd 100644 --- a/src/snapped-point.cpp +++ b/src/snapped-point.cpp @@ -17,8 +17,8 @@ // overloaded constructor Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained, Geom::OptRect target_bbox) : _point(p), - _alignment_target(Geom::Point(0,0)), - _alignment_target2(Geom::Point(0,0)), + //_alignment_target(Geom::Point(0,0)), + //_alignment_target2(Geom::Point(0,0)), _tangent(Geom::Point(0,0)), _source(source), _source_num(source_num), @@ -40,7 +40,7 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, Geom::Point const &ap, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained, Geom::OptRect target_bbox) : _point(p), _alignment_target(ap), - _alignment_target2(Geom::Point(0,0)), + //_alignment_target2(Geom::Point(0,0)), _tangent(Geom::Point(0,0)), _source(source), _source_num(source_num), @@ -83,8 +83,8 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, Geom::Point const &ap Inkscape::SnappedPoint::SnappedPoint(Inkscape::SnapCandidatePoint const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained) : _point (p.getPoint()), - _alignment_target(Geom::Point(0,0)), - _alignment_target2(Geom::Point(0,0)), + //_alignment_target(Geom::Point(0,0)), + //_alignment_target2(Geom::Point(0,0)), _tangent (Geom::Point(0,0)), _source (p.getSourceType()), _source_num (p.getSourceNum()), @@ -105,8 +105,8 @@ Inkscape::SnappedPoint::SnappedPoint(Inkscape::SnapCandidatePoint const &p, Snap Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &at_intersection, bool const &constrained_snap, bool const &fully_constrained, Geom::Coord const &d2, Geom::Coord const &t2, bool const &a2) : _point(p), - _alignment_target(Geom::Point(0,0)), - _alignment_target2(Geom::Point(0,0)), + //_alignment_target(Geom::Point(0,0)), + //_alignment_target2(Geom::Point(0,0)), _tangent (Geom::Point(0,0)), _source(source), _source_num(source_num), @@ -129,8 +129,8 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const Inkscape::SnappedPoint::SnappedPoint(): _point (Geom::Point(0,0)), - _alignment_target(Geom::Point(0,0)), - _alignment_target2(Geom::Point(0,0)), + //_alignment_target(Geom::Point(0,0)), + //_alignment_target2(Geom::Point(0,0)), _tangent (Geom::Point(0,0)), _source (SNAPSOURCE_UNDEFINED), _source_num (-1), @@ -151,8 +151,8 @@ Inkscape::SnappedPoint::SnappedPoint(): Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p): _point (p), - _alignment_target(Geom::Point(0,0)), - _alignment_target2(Geom::Point(0,0)), + //_alignment_target(Geom::Point(0,0)), + //_alignment_target2(Geom::Point(0,0)), _tangent (Geom::Point(0,0)), _source (SNAPSOURCE_UNDEFINED), _source_num (-1), diff --git a/src/snapped-point.h b/src/snapped-point.h index 085ee1d86a..89b728c81d 100644 --- a/src/snapped-point.h +++ b/src/snapped-point.h @@ -15,7 +15,9 @@ #include <2geom/geom.h> #include +#include #include +#include #include "snap-candidate.h" @@ -64,8 +66,28 @@ public: Geom::Point getPoint() const {return _point;} void setPoint(Geom::Point const &p) {_point = p;} Geom::Point getTangent() const {return _tangent;} - Geom::Point getAlignmentTarget() const {return _alignment_target;} - Geom::Point getAlignmentTarget2() const {return _alignment_target2;} + Geom::Point getAlignmentTarget() const + { + if (_alignment_target.has_value()) + return _alignment_target.value(); + else + g_warning("alignment target does not exit"); + return Geom::Point(); + } + + Geom::Point getAlignmentTarget2() const + { + if (_alignment_target2.has_value()) + return _alignment_target2.value(); + else + g_warning("alignment target does not exit"); + return Geom::Point(); + } + + Geom::Coord getDistanceToAignTarget() const + { + return _alignment_target.has_value() ? Geom::L2(_point - _alignment_target.value()) : Geom::infinity(); + } bool getAtIntersection() const {return _at_intersection;} bool getFullyConstrained() const {return _fully_constrained;} @@ -101,8 +123,8 @@ public: protected: Geom::Point _point; // Location of the snapped point Geom::Point _tangent; // Tangent of the curve we snapped to, at the snapped point - Geom::Point _alignment_target; // Target point for alignment snapping - Geom::Point _alignment_target2; // Target point when alignment guides intersect + std::optional _alignment_target; // Target point for alignment snapping + std::optional _alignment_target2; // Target point when alignment guides intersect SnapSourceType _source; // Describes what snapped long _source_num; // Sequence number of the source point that snapped, if that point is part of a set of points. (starting at zero if we might have a set of points; -1 if we only have a single point) SnapTargetType _target; // Describes to what we've snapped to -- GitLab From 5c37912ddc4f3cfbf3512a285775ec8caf439655 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Sun, 6 Jun 2021 11:45:04 +0530 Subject: [PATCH 21/66] modified getClosestSP() to select the alignment snap with smaller distance --- src/snapped-point.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/snapped-point.cpp b/src/snapped-point.cpp index 3109f542bd..1bc1656a9d 100644 --- a/src/snapped-point.cpp +++ b/src/snapped-point.cpp @@ -201,10 +201,17 @@ bool getClosestSP(std::list const &list, Inkscape::Snapp aligned = *i; aligned_success = alignment; } else if (alignment) { - if (!aligned_success || (*i).getSnapDistance() < aligned.getSnapDistance()) { - aligned = *i; - aligned_success = true; - } + if (!aligned_success || (*i).getSnapDistance() <= aligned.getSnapDistance()) { + if ((*i).getSnapDistance() == aligned.getSnapDistance()) { + if ((*i).getDistanceToAignTarget() < aligned.getDistanceToAignTarget()) { + aligned = *i; + aligned_success = true; + } + } else { + aligned = *i; + aligned_success = true; + } + } } else if (!success || (*i).getSnapDistance() < result.getSnapDistance()){ result = *i; success = true; -- GitLab From d7365da44448d1101db98e1755f0db385dfb473b Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Mon, 7 Jun 2021 22:07:10 +0530 Subject: [PATCH 22/66] Move _findCandidates to SnapManager Remove snap targets in context_functions for rect tool --- src/alignment-snapper.cpp | 142 +------------------------------ src/alignment-snapper.h | 15 ---- src/context-fns.cpp | 1 + src/object-snapper.cpp | 153 +-------------------------------- src/object-snapper.h | 16 ---- src/snap.cpp | 175 ++++++++++++++++++++++++++++++++++++++ src/snap.h | 20 +++++ 7 files changed, 199 insertions(+), 323 deletions(-) diff --git a/src/alignment-snapper.cpp b/src/alignment-snapper.cpp index b333495aeb..b128dd0341 100644 --- a/src/alignment-snapper.cpp +++ b/src/alignment-snapper.cpp @@ -41,145 +41,15 @@ Inkscape::AlignmentSnapper::AlignmentSnapper(SnapManager *sm, Geom::Coord const d) : Snapper(sm, d) { - _candidates = new std::vector; _points_to_snap_to = new std::vector; } Inkscape::AlignmentSnapper::~AlignmentSnapper() { - _candidates->clear(); - delete _candidates; - _points_to_snap_to->clear(); delete _points_to_snap_to; } -void Inkscape::AlignmentSnapper::_findCandidates(SPObject* parent, - std::vector const *it, - bool const &first_point, - bool const clip_or_mask, - Geom::Affine const additional_affine) const -{ - SPDesktop const *dt = _snapmanager->getDesktop(); - if (dt == nullptr) { - g_warning("desktop == NULL, so we cannot snap; please inform the developers of this bug"); - // Apparently the setup() method from the SnapManager class hasn't been called before trying to snap. - } - - if (first_point) { - _candidates->clear(); - } - - for (auto& o: parent->children) { - g_assert(dt != nullptr); - SPItem *item = dynamic_cast(&o); - if (item && !(dt->itemIsHidden(item) && !clip_or_mask)) { - // Fix LPE boolops selfsnaping - bool stop = false; - if (item->style) { - SPFilter *filt = item->style->getFilter(); - if (filt && filt->getId() && strcmp(filt->getId(), "selectable_hidder_filter") == 0) { - stop = true; - } - SPLPEItem *lpeitem = dynamic_cast(item); - if (lpeitem && lpeitem->hasPathEffectOfType(Inkscape::LivePathEffect::EffectType::BOOL_OP)) { - stop = true; - } - } - if (stop) { - stop = false; - for (auto skipitem : *it) { - if (skipitem && skipitem->style) { - SPItem *toskip = const_cast(skipitem); - if (toskip) { - SPFilter *filt = toskip->style->getFilter(); - if (filt && filt->getId() && strcmp(filt->getId(), "selectable_hidder_filter") == 0) { - stop = true; - break; - } - - SPLPEItem *lpeitem = dynamic_cast(toskip); - if (!stop && lpeitem && - lpeitem->hasPathEffectOfType(Inkscape::LivePathEffect::EffectType::BOOL_OP)) { - stop = true; - break; - } - } - } - } - if (stop) { - continue; - } - } - // Snapping to items in a locked layer is allowed - // Don't snap to hidden objects, unless they're a clipped path or a mask - /* See if this item is on the ignore list */ - std::vector::const_iterator i; - if (it != nullptr) { - i = it->begin(); - while (i != it->end() && *i != &o) { - ++i; - } - } - - if (it == nullptr || i == it->end()) { - if (item) { - if (!clip_or_mask) { // cannot clip or mask more than once - // The current item is not a clipping path or a mask, but might - // still be the subject of clipping or masking itself ; if so, then - // we should also consider that path or mask for snapping to - SPObject *obj = item->getClipObject(); - if (obj && _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_PATH_CLIP)) { - _findCandidates(obj, it, false, true, item->i2doc_affine()); - } - obj = item->getMaskObject(); - if (obj && _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_PATH_MASK)) { - _findCandidates(obj, it, false, true, item->i2doc_affine()); - } - } - - if (dynamic_cast(item)) { - _findCandidates(&o, it, false, clip_or_mask, additional_affine); - } else { - Geom::OptRect bbox_of_item; - Preferences *prefs = Preferences::get(); - int prefs_bbox = prefs->getBool("/tools/bounding_box", false); - // We'll only need to obtain the visual bounding box if the user preferences tell - // us to, AND if we are snapping to the bounding box itself. If we're snapping to - // paths only, then we can just as well use the geometric bounding box (which is faster) - SPItem::BBoxType bbox_type = (!prefs_bbox && _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_BBOX_CATEGORY)) ? - SPItem::VISUAL_BBOX : SPItem::GEOMETRIC_BBOX; - if (clip_or_mask) { - // Oh oh, this will get ugly. We cannot use sp_item_i2d_affine directly because we need to - // insert an additional transformation in document coordinates (code copied from sp_item_i2d_affine) - bbox_of_item = item->bounds(bbox_type, item->i2doc_affine() * additional_affine * dt->doc2dt()); - } else { - bbox_of_item = item->desktopBounds(bbox_type); - } - if (bbox_of_item) { - if (_snapmanager->getDesktop()->get_display_area().contains(bbox_of_item->midpoint())) - // Finally add the object to _candidates. - _candidates->push_back(SnapCandidateItem(item, clip_or_mask, additional_affine)); - // For debugging: print the id of the candidate to the console - // SPObject *obj = (SPObject*)item; - // std::cout << "Snap candidate added: " << obj->getId() << std::endl; - if (_candidates->size() > 200) { // This makes Inkscape crawl already - static Glib::Timer timer; - if (timer.elapsed() > 1.0) { - timer.reset(); - std::cout << "Warning: limit of 200 snap target paths reached, some will be ignored" << std::endl; - } - break; - } - } - } - } - } - } - } -} - - void Inkscape::AlignmentSnapper::_collectBBoxPoints(bool const &first_point) const { if (!first_point) @@ -205,7 +75,7 @@ void Inkscape::AlignmentSnapper::_collectBBoxPoints(bool const &first_point) con } // collect bounding boxes of other objects - for (const auto & candidate : *_candidates) { + for (const auto & candidate : *(_snapmanager->align_snapper_candidates)) { SPItem *root_item = candidate.item; // get the root item in case we have a duplicate at hand @@ -362,11 +232,6 @@ void Inkscape::AlignmentSnapper::freeSnap(IntermSnapResults &isr, if (!(p_is_bbox || (n > 0 && p_is_node) || (p.considerForAlignment() && p_is_node))) return; - if (p.getSourceNum() <= 0){ - _candidates->clear(); - _findCandidates(_snapmanager->getDocument()->getRoot(), it, true, false); - } - _snapBBoxPoints(isr, p, unselected_nodes); } @@ -393,11 +258,6 @@ void Inkscape::AlignmentSnapper::constrainedSnap(IntermSnapResults &isr, if (!(p_is_bbox || (n > 0 && p_is_node) || (p.considerForAlignment() && p_is_node))) return; - if (p.getSourceNum() <= 0){ - _candidates->clear(); - _findCandidates(_snapmanager->getDocument()->getRoot(), it, true, false); - } - _snapBBoxPoints(isr, p, unselected_nodes, c, pp); } diff --git a/src/alignment-snapper.h b/src/alignment-snapper.h index 3ecbead87d..f8e9875f8a 100644 --- a/src/alignment-snapper.h +++ b/src/alignment-snapper.h @@ -63,23 +63,8 @@ public: std::vector *unselected_nodes) const override; private: - // Store some snap candidate, these are cached for the first point and not recalculated for each point - std::vector *_candidates; std::vector *_points_to_snap_to; - /** Find candidates that lie withing a certain range (visible on viewport). - * @param parent Pointer to the document's root, or to a clipped path or mask object. - * @param it List of items to ignore. - * @param bbox_to_snap Bounding box hulling the whole bunch of points, all from the same selection and having the same transformation. - * @param clip_or_mask The parent object being passed is either a clip or mask. - * @param additional_affine Affine of the clipped path or mask object. - */ - void _findCandidates(SPObject* parent, - std::vector const *it, - bool const &first_point, - bool const clip_or_mask, - Geom::Affine const additional_affine = Geom::identity()) const; - /** Collects and caches points on bounding boxes of the candidates * @param is the point first point in the selection? */ diff --git a/src/context-fns.cpp b/src/context-fns.cpp index 974396ff11..edfc62d258 100644 --- a/src/context-fns.cpp +++ b/src/context-fns.cpp @@ -89,6 +89,7 @@ bool Inkscape::have_viable_layer(SPDesktop *desktop, MessageStack *message) Geom::Rect Inkscape::snap_rectangular_box(SPDesktop const *desktop, SPItem *item, Geom::Point const &pt, Geom::Point const ¢er, int state) { + desktop->snapindicator->remove_snaptarget(); Geom::Point p[2]; auto confine = Modifiers::Modifier::get(Modifiers::Type::TRANS_CONFINE)->active(state); diff --git a/src/object-snapper.cpp b/src/object-snapper.cpp index b8435a5ba4..cca1690d0c 100644 --- a/src/object-snapper.cpp +++ b/src/object-snapper.cpp @@ -44,16 +44,12 @@ Inkscape::ObjectSnapper::ObjectSnapper(SnapManager *sm, Geom::Coord const d) : Snapper(sm, d) { - _candidates = new std::vector; _points_to_snap_to = new std::vector; _paths_to_snap_to = new std::vector; } Inkscape::ObjectSnapper::~ObjectSnapper() { - _candidates->clear(); - delete _candidates; - _points_to_snap_to->clear(); delete _points_to_snap_to; @@ -73,139 +69,6 @@ bool Inkscape::ObjectSnapper::getSnapperAlwaysSnap() const return _snapmanager->snapprefs.getObjectTolerance() == 10000; //TODO: Replace this threshold of 10000 by a constant; see also tolerance-slider.cpp } -void Inkscape::ObjectSnapper::_findCandidates(SPObject* parent, - std::vector const *it, - bool const &first_point, - Geom::Rect const &bbox_to_snap, - bool const clip_or_mask, - Geom::Affine const additional_affine) const // transformation of the item being clipped / masked -{ - SPDesktop const *dt = _snapmanager->getDesktop(); - if (dt == nullptr) { - g_warning("desktop == NULL, so we cannot snap; please inform the developers of this bug"); - // Apparently the setup() method from the SnapManager class hasn't been called before trying to snap. - } - - if (first_point) { - _candidates->clear(); - } - - Geom::Rect bbox_to_snap_incl = bbox_to_snap; // _incl means: will include the snapper tolerance - bbox_to_snap_incl.expandBy(getSnapperTolerance()); // see? - - for (auto& o: parent->children) { - g_assert(dt != nullptr); - SPItem *item = dynamic_cast(&o); - if (item && !(dt->itemIsHidden(item) && !clip_or_mask)) { - // Fix LPE boolops selfsnaping - bool stop = false; - if (item->style) { - SPFilter *filt = item->style->getFilter(); - if (filt && filt->getId() && strcmp(filt->getId(), "selectable_hidder_filter") == 0) { - stop = true; - } - SPLPEItem *lpeitem = dynamic_cast(item); - if (lpeitem && lpeitem->hasPathEffectOfType(Inkscape::LivePathEffect::EffectType::BOOL_OP)) { - stop = true; - } - } - if (stop) { - stop = false; - for (auto skipitem : *it) { - if (skipitem && skipitem->style) { - SPItem *toskip = const_cast(skipitem); - if (toskip) { - SPFilter *filt = toskip->style->getFilter(); - if (filt && filt->getId() && strcmp(filt->getId(), "selectable_hidder_filter") == 0) { - stop = true; - break; - } - - SPLPEItem *lpeitem = dynamic_cast(toskip); - if (!stop && lpeitem && - lpeitem->hasPathEffectOfType(Inkscape::LivePathEffect::EffectType::BOOL_OP)) { - stop = true; - break; - } - } - } - } - if (stop) { - continue; - } - } - // Snapping to items in a locked layer is allowed - // Don't snap to hidden objects, unless they're a clipped path or a mask - /* See if this item is on the ignore list */ - std::vector::const_iterator i; - if (it != nullptr) { - i = it->begin(); - while (i != it->end() && *i != &o) { - ++i; - } - } - - if (it == nullptr || i == it->end()) { - if (item) { - if (!clip_or_mask) { // cannot clip or mask more than once - // The current item is not a clipping path or a mask, but might - // still be the subject of clipping or masking itself ; if so, then - // we should also consider that path or mask for snapping to - SPObject *obj = item->getClipObject(); - if (obj && _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_PATH_CLIP)) { - _findCandidates(obj, it, false, bbox_to_snap, true, item->i2doc_affine()); - } - obj = item->getMaskObject(); - if (obj && _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_PATH_MASK)) { - _findCandidates(obj, it, false, bbox_to_snap, true, item->i2doc_affine()); - } - } - - if (dynamic_cast(item)) { - _findCandidates(&o, it, false, bbox_to_snap, clip_or_mask, additional_affine); - } else { - Geom::OptRect bbox_of_item; - Preferences *prefs = Preferences::get(); - int prefs_bbox = prefs->getBool("/tools/bounding_box", false); - // We'll only need to obtain the visual bounding box if the user preferences tell - // us to, AND if we are snapping to the bounding box itself. If we're snapping to - // paths only, then we can just as well use the geometric bounding box (which is faster) - SPItem::BBoxType bbox_type = (!prefs_bbox && _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_BBOX_CATEGORY)) ? - SPItem::VISUAL_BBOX : SPItem::GEOMETRIC_BBOX; - if (clip_or_mask) { - // Oh oh, this will get ugly. We cannot use sp_item_i2d_affine directly because we need to - // insert an additional transformation in document coordinates (code copied from sp_item_i2d_affine) - bbox_of_item = item->bounds(bbox_type, item->i2doc_affine() * additional_affine * dt->doc2dt()); - } else { - bbox_of_item = item->desktopBounds(bbox_type); - } - if (bbox_of_item) { - // See if the item is within range - if (bbox_to_snap_incl.intersects(*bbox_of_item) - || (_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_ROTATION_CENTER) && bbox_to_snap_incl.contains(item->getCenter()))) { // rotation center might be outside of the bounding box - // This item is within snapping range, so record it as a candidate - _candidates->push_back(SnapCandidateItem(item, clip_or_mask, additional_affine)); - // For debugging: print the id of the candidate to the console - // SPObject *obj = (SPObject*)item; - // std::cout << "Snap candidate added: " << obj->getId() << std::endl; - if (_candidates->size() > 200) { // This makes Inkscape crawl already - static Glib::Timer timer; - if (timer.elapsed() > 1.0) { - timer.reset(); - std::cout << "Warning: limit of 200 snap target paths reached, some will be ignored" << std::endl; - } - break; - } - } - } - } - } - } - } - } -} - - void Inkscape::ObjectSnapper::_collectNodes(SnapSourceType const &t, bool const &first_point) const { @@ -239,7 +102,7 @@ void Inkscape::ObjectSnapper::_collectNodes(SnapSourceType const &t, _getBorderNodes(_points_to_snap_to); } - for (const auto & _candidate : *_candidates) { + for (const auto & _candidate : *_snapmanager->obj_snapper_candidates) { //Geom::Affine i2doc(Geom::identity()); SPItem *root_item = _candidate.item; @@ -424,7 +287,7 @@ void Inkscape::ObjectSnapper::_collectPaths(Geom::Point /*p*/, } } - for (const auto & _candidate : *_candidates) { + for (const auto & _candidate : *_snapmanager->obj_snapper_candidates) { /* Transform the requested snap point to this item's coordinates */ Geom::Affine i2doc(Geom::identity()); @@ -708,12 +571,6 @@ void Inkscape::ObjectSnapper::freeSnap(IntermSnapResults &isr, return; } - /* Get a list of all the SPItems that we will try to snap to */ - if (p.getSourceNum() <= 0) { - Geom::Rect const local_bbox_to_snap = bbox_to_snap ? *bbox_to_snap : Geom::Rect(p.getPoint(), p.getPoint()); - _findCandidates(_snapmanager->getDocument()->getRoot(), it, p.getSourceNum() <= 0, local_bbox_to_snap, false, Geom::identity()); - } - _snapNodes(isr, p, unselected_nodes); if (_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_PATH, SNAPTARGET_PATH_INTERSECTION, SNAPTARGET_BBOX_EDGE, SNAPTARGET_PAGE_BORDER, SNAPTARGET_TEXT_BASELINE)) { @@ -753,12 +610,6 @@ void Inkscape::ObjectSnapper::constrainedSnap( IntermSnapResults &isr, // project the mouse pointer onto the constraint. Only the projected point will be considered for snapping Geom::Point pp = c.projection(p.getPoint()); - /* Get a list of all the SPItems that we will try to snap to */ - if (p.getSourceNum() <= 0) { - Geom::Rect const local_bbox_to_snap = bbox_to_snap ? *bbox_to_snap : Geom::Rect(pp, pp); - _findCandidates(_snapmanager->getDocument()->getRoot(), it, p.getSourceNum() <= 0, local_bbox_to_snap, false, Geom::identity()); - } - // A constrained snap, is a snap in only one degree of freedom (specified by the constraint line). // This is useful for example when scaling an object while maintaining a fixed aspect ratio. It's // nodes are only allowed to move in one direction (i.e. in one degree of freedom). diff --git a/src/object-snapper.h b/src/object-snapper.h index 929b57a1c8..8e5c3d16c9 100644 --- a/src/object-snapper.h +++ b/src/object-snapper.h @@ -60,25 +60,9 @@ public: std::vector *unselected_nodes) const override; private: - //store some lists of candidates, points and paths, so we don't have to rebuild them for each point we want to snap - std::vector *_candidates; std::vector *_points_to_snap_to; std::vector *_paths_to_snap_to; - /** - * Find all items within snapping range. - * @param parent Pointer to the document's root, or to a clipped path or mask object. - * @param it List of items to ignore. - * @param bbox_to_snap Bounding box hulling the whole bunch of points, all from the same selection and having the same transformation. - * @param clip_or_mask The parent object being passed is either a clip or mask. - */ - void _findCandidates(SPObject* parent, - std::vector const *it, - bool const &first_point, - Geom::Rect const &bbox_to_snap, - bool const _clip_or_mask, - Geom::Affine const additional_affine) const; - void _snapNodes(IntermSnapResults &isr, Inkscape::SnapCandidatePoint const &p, // in desktop coordinates std::vector *unselected_nodes, diff --git a/src/snap.cpp b/src/snap.cpp index c0afcd27fe..09d3f7ea30 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -22,6 +22,16 @@ #include <2geom/transforms.h> #include "snap.h" +#include "snap-enums.h" +#include "preferences.h" +#include "object/sp-use.h" +#include "object/sp-mask.h" +#include "live_effects/effect-enum.h" +#include "object/sp-filter.h" +#include "object/sp-object.h" +#include "object/sp-clippath.h" +#include "object/sp-root.h" +#include "style.h" #include "desktop.h" #include "inkscape.h" @@ -52,6 +62,17 @@ SnapManager::SnapManager(SPNamedView const *v) : _snapindicator(true), _unselected_nodes(nullptr) { + obj_snapper_candidates = new std::vector; + align_snapper_candidates = new std::vector; +} + +SnapManager::~SnapManager() +{ + obj_snapper_candidates->clear(); + delete obj_snapper_candidates; + + align_snapper_candidates->clear(); + delete align_snapper_candidates; } SnapManager::SnapperList SnapManager::getSnappers() const @@ -134,6 +155,11 @@ Inkscape::SnappedPoint SnapManager::freeSnap(Inkscape::SnapCandidatePoint const IntermSnapResults isr; SnapperList const snappers = getSnappers(); + if (p.getSourceNum() <= 0){ + Geom::Rect const local_bbox_to_snap = bbox_to_snap ? *bbox_to_snap : Geom::Rect(p.getPoint(), p.getPoint()); + _findCandidates(getDocument()->getRoot(), &_items_to_ignore, p.getSourceNum() <= 0, local_bbox_to_snap, false, Geom::identity()); + } + for (auto snapper : snappers) { snapper->freeSnap(isr, p, bbox_to_snap, &_items_to_ignore, _unselected_nodes); } @@ -791,6 +817,155 @@ void SnapManager::displaySnapsource(Inkscape::SnapCandidatePoint const &p) const } } } + +void SnapManager::_findCandidates(SPObject* parent, + std::vector const *it, + bool const &first_point, + Geom::Rect const &bbox_to_snap, + bool const clip_or_mask, + Geom::Affine const additional_affine) const +{ + SPDesktop const *dt = getDesktop(); + if (dt == nullptr) { + g_warning("desktop == NULL, so we cannot snap; please inform the developers of this bug"); + // Apparently the setup() method from the SnapManager class hasn't been called before trying to snap. + } + + if (first_point) { + obj_snapper_candidates->clear(); + align_snapper_candidates->clear(); + } + + Geom::Rect bbox_to_snap_incl = bbox_to_snap; // _incl means: will include the snapper tolerance + bbox_to_snap_incl.expandBy(object.getSnapperTolerance()); // see? + + for (auto& o: parent->children) { + g_assert(dt != nullptr); + SPItem *item = dynamic_cast(&o); + if (item && !(dt->itemIsHidden(item) && !clip_or_mask)) { + // Fix LPE boolops selfsnaping + bool stop = false; + if (item->style) { + SPFilter *filt = item->style->getFilter(); + if (filt && filt->getId() && strcmp(filt->getId(), "selectable_hidder_filter") == 0) { + stop = true; + } + SPLPEItem *lpeitem = dynamic_cast(item); + if (lpeitem && lpeitem->hasPathEffectOfType(Inkscape::LivePathEffect::EffectType::BOOL_OP)) { + stop = true; + } + } + if (stop) { + stop = false; + for (auto skipitem : *it) { + if (skipitem && skipitem->style) { + SPItem *toskip = const_cast(skipitem); + if (toskip) { + SPFilter *filt = toskip->style->getFilter(); + if (filt && filt->getId() && strcmp(filt->getId(), "selectable_hidder_filter") == 0) { + stop = true; + break; + } + + SPLPEItem *lpeitem = dynamic_cast(toskip); + if (!stop && lpeitem && + lpeitem->hasPathEffectOfType(Inkscape::LivePathEffect::EffectType::BOOL_OP)) { + stop = true; + break; + } + } + } + } + if (stop) { + continue; + } + } + // Snapping to items in a locked layer is allowed + // Don't snap to hidden objects, unless they're a clipped path or a mask + /* See if this item is on the ignore list */ + std::vector::const_iterator i; + if (it != nullptr) { + i = it->begin(); + while (i != it->end() && *i != &o) { + ++i; + } + } + + if (it == nullptr || i == it->end()) { + if (item) { + if (!clip_or_mask) { // cannot clip or mask more than once + // The current item is not a clipping path or a mask, but might + // still be the subject of clipping or masking itself ; if so, then + // we should also consider that path or mask for snapping to + SPObject *obj = item->getClipObject(); + if (obj && snapprefs.isTargetSnappable(Inkscape::SNAPTARGET_PATH_CLIP)) { + _findCandidates(obj, it, false, bbox_to_snap, true, item->i2doc_affine()); + } + obj = item->getMaskObject(); + if (obj && snapprefs.isTargetSnappable(Inkscape::SNAPTARGET_PATH_MASK)) { + _findCandidates(obj, it, false, bbox_to_snap, true, item->i2doc_affine()); + } + } + + if (dynamic_cast(item)) { + _findCandidates(&o, it, false, bbox_to_snap, clip_or_mask, additional_affine); + } else { + Geom::OptRect bbox_of_item; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + int prefs_bbox = prefs->getBool("/tools/bounding_box", false); + // We'll only need to obtain the visual bounding box if the user preferences tell + // us to, AND if we are snapping to the bounding box itself. If we're snapping to + // paths only, then we can just as well use the geometric bounding box (which is faster) + SPItem::BBoxType bbox_type = (!prefs_bbox && snapprefs.isTargetSnappable(Inkscape::SNAPTARGET_BBOX_CATEGORY)) ? + SPItem::VISUAL_BBOX : SPItem::GEOMETRIC_BBOX; + if (clip_or_mask) { + // Oh oh, this will get ugly. We cannot use sp_item_i2d_affine directly because we need to + // insert an additional transformation in document coordinates (code copied from sp_item_i2d_affine) + bbox_of_item = item->bounds(bbox_type, item->i2doc_affine() * additional_affine * dt->doc2dt()); + } else { + bbox_of_item = item->desktopBounds(bbox_type); + } + if (bbox_of_item) { + bool overflow = false; + // See if the item is within range + if (getDesktop()->get_display_area().contains(bbox_of_item->midpoint())) { + // Finally add the object to _candidates. + align_snapper_candidates->push_back(Inkscape::SnapCandidateItem(item, clip_or_mask, additional_affine)); + // For debugging: print the id of the candidate to the console + // SPObject *obj = (SPObject*)item; + // std::cout << "Snap candidate added: " << obj->getId() << std::endl; + if (align_snapper_candidates->size() > 200) { // This makes Inkscape crawl already + overflow = true; + } + } + + if (bbox_to_snap_incl.intersects(*bbox_of_item) + || (snapprefs.isTargetSnappable(Inkscape::SNAPTARGET_ROTATION_CENTER) && bbox_to_snap_incl.contains(item->getCenter()))) { // rotation center might be outside of the bounding box + // This item is within snapping range, so record it as a candidate + obj_snapper_candidates->push_back(Inkscape::SnapCandidateItem(item, clip_or_mask, additional_affine)); + // For debugging: print the id of the candidate to the console + // SPObject *obj = (SPObject*)item; + // std::cout << "Snap candidate added: " << obj->getId() << std::endl; + if (obj_snapper_candidates->size() > 200) { // This makes Inkscape crawl already + overflow = true; + } + } + + if (overflow) { + static Glib::Timer timer; + if (timer.elapsed() > 1.0) { + timer.reset(); + std::cout << "Warning: limit of 200 snap target paths reached, some will be ignored" << std::endl; + } + break; + } + } + } + } + } + } + } +} /* Local Variables: mode:c++ diff --git a/src/snap.h b/src/snap.h index 309f0c53f2..9d8a91713f 100644 --- a/src/snap.h +++ b/src/snap.h @@ -89,6 +89,7 @@ public: * @param v 'Owning' SPNamedView. */ SnapManager(SPNamedView const *v); + ~SnapManager(); typedef std::list SnapperList; @@ -429,6 +430,25 @@ private: bool _snapindicator; ///< When true, an indicator will be drawn at the position that was being snapped to std::vector *_unselected_nodes; ///< Nodes of the path that is currently being edited and which have not been selected and which will therefore be stationary. Only these nodes will be considered for snapping to. Of each unselected node both the position (Geom::Point) and the type (Inkscape::SnapTargetType) will be stored + /** + * Find all items within snapping range. + * @param parent Pointer to the document's root, or to a clipped path or mask object. + * @param it List of items to ignore. + * @param bbox_to_snap Bounding box hulling the whole bunch of points, all from the same selection and having the same transformation. + * @param clip_or_mask The parent object being passed is either a clip or mask. + */ + void _findCandidates(SPObject* parent, + std::vector const *it, + bool const &first_point, + Geom::Rect const &bbox_to_snap, + bool const _clip_or_mask, + Geom::Affine const additional_affine) const; + + std::vector *obj_snapper_candidates; + std::vector *align_snapper_candidates; + + friend class Inkscape::ObjectSnapper; + friend class Inkscape::AlignmentSnapper; }; #endif // !SEEN_SNAP_H -- GitLab From a3737946e86752059e0ca5c2f54ea5e189692afb Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Tue, 8 Jun 2021 21:27:14 +0530 Subject: [PATCH 23/66] Distribution Snapping with all the attributes and a toggle. Also modified getColosestSP() to merge the snappedPoint when there is an alignment-snap along with a distribution-snap. --- share/ui/toolbar-snap.ui | 17 + src/CMakeLists.txt | 2 + src/actions/actions-canvas-snapping.cpp | 12 + src/attributes.cpp | 2 + src/attributes.h | 2 + src/distribution-snapper.cpp | 470 ++++++++++++++++++++++++ src/distribution-snapper.h | 89 +++++ src/object/sp-namedview.cpp | 10 + src/seltrans.cpp | 6 +- src/snap-enums.h | 11 + src/snap-preferences.cpp | 11 +- src/snap-preferences.h | 3 + src/snap.cpp | 5 +- src/snap.h | 3 + src/snapped-point.cpp | 29 +- src/ui/dialog/document-properties.cpp | 11 + src/ui/dialog/document-properties.h | 1 + 17 files changed, 677 insertions(+), 7 deletions(-) create mode 100644 src/distribution-snapper.cpp create mode 100644 src/distribution-snapper.h diff --git a/share/ui/toolbar-snap.ui b/share/ui/toolbar-snap.ui index b1be82a976..91e6cda415 100644 --- a/share/ui/toolbar-snap.ui +++ b/share/ui/toolbar-snap.ui @@ -238,6 +238,23 @@ + + + + + True + + + + + + True + doc.snap-distribution + snap + Distribution + + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e975d6fe27..52fe72825c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -22,6 +22,7 @@ set(inkscape_SRC desktop-style.cpp desktop.cpp device-manager.cpp + distribution-snapper.cpp document-subset.cpp document-undo.cpp document.cpp @@ -113,6 +114,7 @@ set(inkscape_SRC desktop-style.h desktop.h device-manager.h + distribution-snapper.h document-subset.h document-undo.h document.h diff --git a/src/actions/actions-canvas-snapping.cpp b/src/actions/actions-canvas-snapping.cpp index d8e737baff..10daccbcd6 100644 --- a/src/actions/actions-canvas-snapping.cpp +++ b/src/actions/actions-canvas-snapping.cpp @@ -73,6 +73,11 @@ canvas_snapping_toggle(SPDocument* document, const SPAttr option) repr->setAttributeBoolean("inkscape:snap-alignment-self", !v); break; + case SPAttr::INKSCAPE_SNAP_DISTRIBUTION: + v = nv->snap_manager.snapprefs.isTargetSnappable(Inkscape::SNAPTARGET_DISTRIBUTION_CATEGORY); + repr->setAttributeBoolean("inkscape:snap-distribution", !v); + break; + // BBox case SPAttr::INKSCAPE_SNAP_BBOX: v = nv->snap_manager.snapprefs.isTargetSnappable(Inkscape::SNAPTARGET_BBOX_CATEGORY); @@ -197,6 +202,8 @@ std::vector> raw_data_canvas_snapping = {"doc.snap-alignment", N_("Snap Objects that Align"), "Snap", N_("Toggle alignment snapping") }, {"doc.snap-alignment-self", N_("Snap Nodes that Align"), "Snap", N_("Toggle alignment snapping to nodes in the same path")}, + {"doc.snap-distribution", N_("Snap Objects at Equal Distances"), "Snap", N_("Toggle snapping objects at equal distances")}, + {"doc.snap-bbox", N_("Snap Bounding Boxes"), "Snap", N_("Toggle snapping to bounding boxes (global)") }, {"doc.snap-bbox-edge", N_("Snap Bounding Box Edges"), "Snap", N_("Toggle snapping to bounding-box edges") }, {"doc.snap-bbox-corner", N_("Snap Bounding Box Corners"), "Snap", N_("Toggle snapping to bounding-box corners") }, @@ -230,6 +237,8 @@ add_actions_canvas_snapping(SPDocument* document) map->add_action_bool( "snap-global-toggle", sigc::bind(sigc::ptr_fun(&canvas_snapping_toggle), document, SPAttr::INKSCAPE_SNAP_GLOBAL)); + map->add_action_bool( "snap-distribution", sigc::bind(sigc::ptr_fun(&canvas_snapping_toggle), document, SPAttr::INKSCAPE_SNAP_DISTRIBUTION)); + map->add_action_bool( "snap-alignment", sigc::bind(sigc::ptr_fun(&canvas_snapping_toggle), document, SPAttr::INKSCAPE_SNAP_ALIGNMENT)); map->add_action_bool( "snap-alignment-self", sigc::bind(sigc::ptr_fun(&canvas_snapping_toggle), document, SPAttr::INKSCAPE_SNAP_ALIGNMENT_SELF)); @@ -324,6 +333,9 @@ set_actions_canvas_snapping(SPDocument* document) set_actions_canvas_snapping_helper(map, "snap-alignment", alignment, global); set_actions_canvas_snapping_helper(map, "snap-alignment-self", nv->snap_manager.snapprefs.isSnapButtonEnabled(Inkscape::SNAPTARGET_ALIGNMENT_HANDLE), global && alignment); + bool distribution = nv->snap_manager.snapprefs.isTargetSnappable(Inkscape::SNAPTARGET_DISTRIBUTION_CATEGORY); + set_actions_canvas_snapping_helper(map, "snap-distribution", distribution, global); + bool bbox = nv->snap_manager.snapprefs.isTargetSnappable(Inkscape::SNAPTARGET_BBOX_CATEGORY); set_actions_canvas_snapping_helper(map, "snap-bbox", bbox, global); set_actions_canvas_snapping_helper(map, "snap-bbox-edge", nv->snap_manager.snapprefs.isSnapButtonEnabled(Inkscape::SNAPTARGET_BBOX_EDGE), global && bbox); diff --git a/src/attributes.cpp b/src/attributes.cpp index 56a270b284..f960d3d7a1 100644 --- a/src/attributes.cpp +++ b/src/attributes.cpp @@ -72,6 +72,7 @@ static SPStyleProp const props[] = { {SPAttr::GUIDETOLERANCE, "guidetolerance"}, {SPAttr::OBJECTTOLERANCE, "objecttolerance"}, {SPAttr::ALIGNMENTTOLERANCE, "alignmenttolerance"}, + {SPAttr::DISTRIBUTIONTOLERANCE, "distributiontolerance"}, {SPAttr::GUIDECOLOR, "guidecolor"}, {SPAttr::GUIDEOPACITY, "guideopacity"}, {SPAttr::GUIDEHICOLOR, "guidehicolor"}, @@ -99,6 +100,7 @@ static SPStyleProp const props[] = { {SPAttr::INKSCAPE_WINDOW_Y, "inkscape:window-y"}, {SPAttr::INKSCAPE_WINDOW_MAXIMIZED, "inkscape:window-maximized"}, {SPAttr::INKSCAPE_SNAP_GLOBAL, "inkscape:snap-global"}, + {SPAttr::INKSCAPE_SNAP_DISTRIBUTION, "inkscape:snap-distribution"}, {SPAttr::INKSCAPE_SNAP_ALIGNMENT, "inkscape:snap-alignment"}, {SPAttr::INKSCAPE_SNAP_ALIGNMENT_SELF, "inkscape:snap-alignment-self"}, {SPAttr::INKSCAPE_SNAP_PERP, "inkscape:snap-perpendicular"}, diff --git a/src/attributes.h b/src/attributes.h index 468525652a..7eaea5fcdf 100644 --- a/src/attributes.h +++ b/src/attributes.h @@ -71,6 +71,7 @@ enum class SPAttr { GUIDETOLERANCE, OBJECTTOLERANCE, ALIGNMENTTOLERANCE, + DISTRIBUTIONTOLERANCE, GUIDECOLOR, GUIDEOPACITY, GUIDEHICOLOR, @@ -98,6 +99,7 @@ enum class SPAttr { INKSCAPE_WINDOW_Y, INKSCAPE_WINDOW_MAXIMIZED, INKSCAPE_SNAP_GLOBAL, + INKSCAPE_SNAP_DISTRIBUTION, INKSCAPE_SNAP_ALIGNMENT, INKSCAPE_SNAP_ALIGNMENT_SELF, INKSCAPE_SNAP_PERP, diff --git a/src/distribution-snapper.cpp b/src/distribution-snapper.cpp new file mode 100644 index 0000000000..e3b2e2a756 --- /dev/null +++ b/src/distribution-snapper.cpp @@ -0,0 +1,470 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** \file + * Snapping equidistant objects + * + * Authors: + * Parth Pant + * + * Copyright (C) 2021 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include <2geom/circle.h> +#include <2geom/line.h> +#include <2geom/path-intersection.h> +#include <2geom/path-sink.h> + +#include "desktop.h" +#include "display/curve.h" +#include "document.h" +#include "inkscape.h" +#include "live_effects/effect-enum.h" +#include "object/sp-clippath.h" +#include "object/sp-flowtext.h" +#include "object/sp-image.h" +#include "object/sp-item-group.h" +#include "object/sp-mask.h" +#include "object/sp-namedview.h" +#include "object/sp-path.h" +#include "object/sp-root.h" +#include "object/sp-shape.h" +#include "object/sp-text.h" +#include "object/sp-use.h" +#include "path/path-util.h" // curve_for_item +#include "preferences.h" +#include "snap-enums.h" +#include "style.h" +#include "svg/svg.h" +#include "text-editing.h" + +static int sortBoxesRight(Geom::Rect const &a, Geom::Rect const &b) +{ + if (a.midpoint().x() < b.midpoint().x()) + return 1; + return 0; +} + +static int sortBoxesLeft(Geom::Rect const &a, Geom::Rect const &b) +{ + if (a.midpoint().x() > b.midpoint().x()) + return 1; + return 0; +} + +static int sortBoxesUp(Geom::Rect const &a, Geom::Rect const &b) +{ + if (a.midpoint().y() > b.midpoint().y()) + return 1; + return 0; +} + +static int sortBoxesDown(Geom::Rect const &a, Geom::Rect const &b) +{ + if (a.midpoint().y() < b.midpoint().y()) + return 1; + return 0; +} + +static int findRightSnaps(std::vector::iterator it, std::vector::iterator end, Geom::Coord &dist, int level = 0) +{ + if (level > 5) + return 5; + + //if (it == end) + //return level; + + if (std::next(it) == end) + return level; + + if (it->intersects(*std::next(it))) + return level; + + if (level == 0) { + dist = - it->max().x() + std::next(it)->min().x(); + return findRightSnaps(++it, end, dist, ++level); + } + + // 1e-5 for accuracy if we use equality (==), it never satisfies. + if (-dist - it->max().x() + std::next(it)->min().x() < 1e-5) { + return findRightSnaps(++it, end, dist, ++level); + } else { + return level; + } +} + +static int findLeftSnaps(std::vector::iterator it, std::vector::iterator end, Geom::Coord &dist, int level = 0) +{ + if (level > 5) + return 5; + + //if (it == end) + //return level; + + if (std::next(it) == end) + return level; + + if ((it)->intersects(*std::next(it))) + return level; + + if (level == 0) { + dist = it->min().x() - std::next(it)->max().x(); + return findLeftSnaps(++it, end, dist, ++level); + } + + // 1e-5 for accuracy if we use equality (==), it never satisfies. + if (-dist + it->min().x() - std::next(it)->max().x() < 1e-5) { + return findLeftSnaps(++it, end, dist, ++level); + } else { + return level; + } +} + +static int findUpSnaps(std::vector::iterator it, std::vector::iterator end, Geom::Coord &dist, int level = 0) +{ + if (level > 5) + return 5; + + //if (it == end) + //return level; + + if (std::next(it) == end) + return level; + + if ((std::next(it))->intersects(*it)) + return level; + + if (level == 0) { + dist = it->min().y() - std::next(it)->max().y(); + return findUpSnaps(++it, end, dist, ++level); + } + + // 1e-5 for accuracy if we use equality (==), it never satisfies. + if (dist - it->min().y() + std::next(it)->max().y() < 1e-5) { + return findUpSnaps(++it, end, dist, ++level); + } else { + return level; + } +} + +static int findDownSnaps(std::vector::iterator it, std::vector::iterator end, Geom::Coord &dist, int level = 0) +{ + if (level > 5) + return 5; + + //if (it == end) + //return level; + + if (std::next(it) == end) + return level; + + if ((std::next(it))->intersects(*it)) + return level; + + if (level == 0) { + dist = - it->max().y() + std::next(it)->min().y(); + return findDownSnaps(++it, end, dist, ++level); + } + + // 1e-5 for accuracy if we use equality (==), it never satisfies. + if (dist + it->max().y() - std::next(it)->min().y() < 1e-5) { + return findDownSnaps(++it, end, dist, ++level); + } else { + return level; + } +} + +Inkscape::DistributionSnapper::DistributionSnapper(SnapManager *sm, Geom::Coord const d) + : Snapper(sm, d) +{ + _bboxes_right = new std::vector; + _bboxes_left = new std::vector; + _bboxes_up = new std::vector; + _bboxes_down = new std::vector; +} + +Inkscape::DistributionSnapper::~DistributionSnapper() +{ + _bboxes_right->clear(); + delete _bboxes_right; + + _bboxes_left->clear(); + delete _bboxes_left; + + _bboxes_up->clear(); + delete _bboxes_up; + + _bboxes_down->clear(); + delete _bboxes_down; +} + +void Inkscape::DistributionSnapper::_collectBBoxes(Geom::OptRect const &bbox_to_snap, bool const &first_point) const +{ + if (!first_point) + return; + + _bboxes_right->clear(); + _bboxes_left->clear(); + _bboxes_down->clear(); + _bboxes_up->clear(); + + SPItem::BBoxType bbox_type = SPItem::GEOMETRIC_BBOX; + + Preferences *prefs = Preferences::get(); + bool prefs_bbox = prefs->getBool("/tools/bounding_box"); + bbox_type = !prefs_bbox ? + SPItem::VISUAL_BBOX : SPItem::GEOMETRIC_BBOX; + + // collect bounding boxes of other objects + for (const auto & candidate : *(_snapmanager->align_snapper_candidates)) { + SPItem *root_item = candidate.item; + + // get the root item in case we have a duplicate at hand + SPUse *use = dynamic_cast(candidate.item); + if (use) { + root_item = use->root(); + } + g_return_if_fail(root_item); + + // if candidate is not a clip or a mask object then extract its BBox points + if (!candidate.clip_or_mask) { + Geom::OptRect b = root_item->desktopBounds(bbox_type); + if (!b.intersects(bbox_to_snap)) { + auto diff_vec = b->midpoint() - bbox_to_snap->midpoint(); + + Geom::Rect Xbounds = *bbox_to_snap; + Xbounds.expandBy(_snapmanager->_desktop->get_display_area().maxExtent(), 0); + + Geom::Rect Ybounds = *bbox_to_snap; + Ybounds.expandBy(0, _snapmanager->_desktop->get_display_area().maxExtent()); + + if (Xbounds.intersects(b)) { + if (diff_vec.x() > 0) { + _bboxes_right->push_back(*b); + } else { + _bboxes_left->push_back(*b); + } + } else if (Ybounds.intersects(b)) { + if (diff_vec.y() < 0) { + _bboxes_up->push_back(*b); + } else { + _bboxes_down->push_back(*b); + } + } + } + } + } + + std::stable_sort(_bboxes_right->begin(), _bboxes_right->end(), sortBoxesRight); + std::stable_sort(_bboxes_left->begin(), _bboxes_left->end(), sortBoxesLeft); + std::stable_sort(_bboxes_up->begin(), _bboxes_up->end(), sortBoxesUp); + std::stable_sort(_bboxes_down->begin(), _bboxes_down->end(), sortBoxesDown); + + // Debug log + //std::cout<<"----------"<size()<size()<size()<size()< *unselected_nodes, + SnapConstraint const &c, + Geom::Point const &p_proj_on_constraint) const +{ + bool consider_x = true; + bool consider_y = true; + if (!c.isUndefined() && c.isLinear()) { + if (c.getDirection().x() == 0) + consider_x = false; // consider horizontl snapping if moving vertically + else + consider_y = false; // consider vertical snapping if moving horizontally + } + _collectBBoxes(bbox_to_snap, p.getSourceNum() <= 0); + + Geom::Coord dist; + + if (p.getSourceType() != SNAPSOURCE_BBOX_MIDPOINT) + return; + + // in between snap + Geom::Point pointR = Geom::Point(Geom::infinity(), Geom::infinity()); + if (_bboxes_right->size() > 0) + pointR = _bboxes_right->begin()->min(); + + Geom::Point pointL = Geom::Point(Geom::infinity(), Geom::infinity()); + if (_bboxes_left->size() > 0) + pointL = _bboxes_left->begin()->max(); + + Geom::Point pointU = Geom::Point(Geom::infinity(), Geom::infinity()); + if (_bboxes_up->size() > 0) + pointU = _bboxes_up->begin()->max(); + + Geom::Point pointD = Geom::Point(Geom::infinity(), Geom::infinity()); + if (_bboxes_down->size() > 0) + pointD = _bboxes_down->begin()->min(); + + // horizontally in between + auto x = Geom::Point((pointR + pointL)/2).x(); + dist = abs(x - bbox_to_snap->midpoint().x()); + if (consider_x && dist < getSnapperTolerance()) { + auto s = SnappedPoint(Geom::Point(x, bbox_to_snap->midpoint().y()), p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_X, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true, *(_bboxes_right->begin())); + //std::cout<<"X snap to"<midpoint().y())<midpoint().y()); + if (consider_y && dist < getSnapperTolerance()) { + auto s = SnappedPoint(Geom::Point(bbox_to_snap->midpoint().x(), y), p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_Y, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true, *(_bboxes_up->begin())); + //std::cout<<"Y snap to"<<<size() > 1) { + int num = findRightSnaps(_bboxes_right->begin(), _bboxes_right->end(), equal_dist); + if (num > 0) { + Geom::Coord offset = - bbox_to_snap->max().x() + _bboxes_right->begin()->min().x() - equal_dist; + Geom::Point target = bbox_to_snap->midpoint() + Geom::Point(offset, 0); + + if (abs(offset) < getSnapperTolerance()) { + auto s = SnappedPoint(target, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_RIGHT, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true, *(_bboxes_right->begin())); + isr.points.push_back(s); + + // Debug log + //std::cout<<"------"<size() > 1 ) { + int num = findLeftSnaps(_bboxes_left->begin(), _bboxes_left->end(), equal_dist); + if (num > 0) { + Geom::Coord offset = bbox_to_snap->min().x() - _bboxes_left->begin()->max().x() - equal_dist; + Geom::Point target = bbox_to_snap->midpoint() - Geom::Point(offset, 0); + + if (abs(offset) < getSnapperTolerance()) { + auto s = SnappedPoint(target, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_LEFT, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true, *(_bboxes_left->begin())); + isr.points.push_back(s); + + // Debug log + //std::cout<<"------"<size() > 1 ) { + int num = findUpSnaps(_bboxes_up->begin(), _bboxes_up->end(), equal_dist); + if (num > 0) { + Geom::Coord offset = bbox_to_snap->min().y() - _bboxes_up->begin()->max().y() - equal_dist; + Geom::Point target = bbox_to_snap->midpoint() - Geom::Point(0, offset); + + if (abs(offset) < getSnapperTolerance()) { + auto s = SnappedPoint(target, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_UP, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true, *(_bboxes_up->begin())); + isr.points.push_back(s); + + // Debug log + //std::cout<<"------"<size() > 1 ) { + int num = findDownSnaps(_bboxes_down->begin(), _bboxes_down->end(), equal_dist); + if (num > 0) { + Geom::Coord offset = - bbox_to_snap->max().y() + _bboxes_down->begin()->min().y() - equal_dist; + Geom::Point target = bbox_to_snap->midpoint() + Geom::Point(0, offset); + + if (abs(offset) < getSnapperTolerance()) { + auto s = SnappedPoint(target, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_DOWN, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true, *(_bboxes_down->begin())); + isr.points.push_back(s); + + // Debug log + //std::cout<<"------"< const *it, + std::vector *unselected_nodes) const +{ + if (bbox_to_snap.empty()) + return; + + if (!(p.getSourceType() & SNAPSOURCE_BBOX_CATEGORY)) { + return; + } + + // toggle checks + if (!_snap_enabled || !_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_DISTRIBUTION_CATEGORY)) + return; + + _snapEquidistantPoints(isr, p, bbox_to_snap, unselected_nodes); +} + +void Inkscape::DistributionSnapper::constrainedSnap(IntermSnapResults &isr, + Inkscape::SnapCandidatePoint const &p, + Geom::OptRect const &bbox_to_snap, + SnapConstraint const &c, + std::vector const *it, + std::vector *unselected_nodes) const +{ + if (bbox_to_snap.empty()) + return; + + // project the mouse pointer onto the constraint. Only the projected point will be considered for snapping + Geom::Point pp = c.projection(p.getPoint()); + + // toggle checks + if (!_snap_enabled || !_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_DISTRIBUTION_CATEGORY)) + return; + + _snapEquidistantPoints(isr, p, bbox_to_snap, unselected_nodes, c, pp); +} + +bool Inkscape::DistributionSnapper::ThisSnapperMightSnap() const +{ + return true; +} + +bool Inkscape::DistributionSnapper::getSnapperAlwaysSnap() const +{ + return _snapmanager->snapprefs.getAlignmentTolerance() == 10000; //TODO: Replace this threshold of 10000 by a constant; see also tolerance-slider.cpp +} + +Geom::Coord Inkscape::DistributionSnapper::getSnapperTolerance() const +{ + SPDesktop const *dt = _snapmanager->getDesktop(); + double const zoom = dt ? dt->current_zoom() : 1; + return _snapmanager->snapprefs.getDistributionTolerance() / zoom; +} diff --git a/src/distribution-snapper.h b/src/distribution-snapper.h new file mode 100644 index 0000000000..fc9915f868 --- /dev/null +++ b/src/distribution-snapper.h @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** \file + * Authors: + * Parth Pant + * + * Copyright (C) 2021 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#ifndef SEEN_DISTRIBUTION_SNAPPER_H +#define SEEN_DISTRIBUTION_SNAPPER_H + +#include <2geom/affine.h> + +#include "snap-enums.h" +#include "snapper.h" +#include "snap-candidate.h" +#include "boost/graph/adjacency_list.hpp" + +class SPDesktop; +class SPNamedView; +class SPItem; +class SPObject; +class SPPath; +class SPDesktop; + +namespace Inkscape +{ + +/** + * Snapping equidistant objects + */ +class DistributionSnapper : public Snapper +{ + +public: + DistributionSnapper(SnapManager *sm, Geom::Coord const d); + ~DistributionSnapper() override; + + /** + * @return true if this Snapper will snap at least one kind of point. + */ + bool ThisSnapperMightSnap() const override; + + /** + * @return Snap tolerance (desktop coordinates); depends on current zoom so that it's always the same in screen pixels. + */ + Geom::Coord getSnapperTolerance() const override; //returns the tolerance of the snapper in screen pixels (i.e. independent of zoom) + + bool getSnapperAlwaysSnap() const override; //if true, then the snapper will always snap, regardless of its tolerance + + void freeSnap(IntermSnapResults &isr, + Inkscape::SnapCandidatePoint const &p, + Geom::OptRect const &bbox_to_snap, + std::vector const *it, + std::vector *unselected_nodes) const override; + + void constrainedSnap(IntermSnapResults &isr, + Inkscape::SnapCandidatePoint const &p, + Geom::OptRect const &bbox_to_snap, + SnapConstraint const &c, + std::vector const *it, + std::vector *unselected_nodes) const override; + +private: + std::vector *_bboxes_left; + std::vector *_bboxes_right; + std::vector *_bboxes_down; + std::vector *_bboxes_up; + + /** Collects and caches bounding boxes to the left, right, up, and down of the + * selected object. + * @param bounding box of the selected object + * @param is the point first point in the selection? + */ + void _collectBBoxes(Geom::OptRect const &bbox_to_snap, bool const &first_point) const; + + void _snapEquidistantPoints(IntermSnapResults &isr, + SnapCandidatePoint const &p, + Geom::OptRect const &bbox_to_snap, + std::vector *unselected_nodes, + SnapConstraint const &c = SnapConstraint(), + Geom::Point const &p_proj_on_constraint = Geom::Point()) const; +}; // end of AlignmentSnapper class + +} // end of namespace Inkscape + +#endif diff --git a/src/object/sp-namedview.cpp b/src/object/sp-namedview.cpp index 72b98c6927..7ec84cda75 100644 --- a/src/object/sp-namedview.cpp +++ b/src/object/sp-namedview.cpp @@ -201,6 +201,7 @@ void SPNamedView::build(SPDocument *document, Inkscape::XML::Node *repr) { this->readAttr(SPAttr::GUIDETOLERANCE); this->readAttr(SPAttr::OBJECTTOLERANCE); this->readAttr(SPAttr::ALIGNMENTTOLERANCE); + this->readAttr(SPAttr::DISTRIBUTIONTOLERANCE); this->readAttr(SPAttr::GUIDECOLOR); this->readAttr(SPAttr::GUIDEOPACITY); this->readAttr(SPAttr::GUIDEHICOLOR); @@ -249,6 +250,7 @@ void SPNamedView::build(SPDocument *document, Inkscape::XML::Node *repr) { this->readAttr(SPAttr::INKSCAPE_SNAP_PAGE_BORDER); this->readAttr(SPAttr::INKSCAPE_SNAP_ALIGNMENT); this->readAttr(SPAttr::INKSCAPE_SNAP_ALIGNMENT_SELF); + this->readAttr(SPAttr::INKSCAPE_SNAP_DISTRIBUTION); this->readAttr(SPAttr::INKSCAPE_CURRENT_LAYER); this->readAttr(SPAttr::INKSCAPE_CONNECTOR_SPACING); this->readAttr(SPAttr::INKSCAPE_LOCKGUIDES); @@ -320,6 +322,10 @@ void SPNamedView::set(SPAttr key, const gchar* value) { this->snap_manager.snapprefs.setAlignementTolerance(value ? g_ascii_strtod(value, nullptr) : 5); this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; + case SPAttr::DISTRIBUTIONTOLERANCE: + this->snap_manager.snapprefs.setDistributionTolerance(value ? g_ascii_strtod(value, nullptr) : 5); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; case SPAttr::GUIDECOLOR: this->guidecolor = (this->guidecolor & 0xff) | (DEFAULTGUIDECOLOR & 0xffffff00); @@ -547,6 +553,10 @@ void SPNamedView::set(SPAttr key, const gchar* value) { this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_ALIGNMENT_HANDLE, value ? sp_str_to_bool(value) : FALSE); this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; + case SPAttr::INKSCAPE_SNAP_DISTRIBUTION: + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_DISTRIBUTION_CATEGORY, value ? sp_str_to_bool(value) : FALSE); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; case SPAttr::INKSCAPE_CURRENT_LAYER: this->default_layer_id = value ? g_quark_from_string(value) : 0; this->requestModified(SP_OBJECT_MODIFIED_FLAG); diff --git a/src/seltrans.cpp b/src/seltrans.cpp index 7e2b90691f..922b5a8005 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -300,9 +300,9 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s _bbox_points.clear(); // Collect the bounding box's corners and midpoints for each selected item - if (m.snapprefs.isTargetSnappable(SNAPTARGET_BBOX_CATEGORY, SNAPTARGET_ALIGNMENT_CATEGORY)) { - bool c = m.snapprefs.isTargetSnappable(SNAPTARGET_BBOX_CORNER, SNAPTARGET_ALIGNMENT_CATEGORY); - bool mp = m.snapprefs.isTargetSnappable(SNAPTARGET_BBOX_MIDPOINT, SNAPTARGET_ALIGNMENT_CATEGORY); + if (m.snapprefs.isTargetSnappable(SNAPTARGET_BBOX_CATEGORY, SNAPTARGET_ALIGNMENT_CATEGORY, SNAPTARGET_DISTRIBUTION_CATEGORY)) { + bool c = m.snapprefs.isTargetSnappable(SNAPTARGET_BBOX_CORNER, SNAPTARGET_ALIGNMENT_CATEGORY, SNAPTARGET_DISTRIBUTION_CATEGORY); + bool mp = m.snapprefs.isTargetSnappable(SNAPTARGET_BBOX_MIDPOINT, SNAPTARGET_ALIGNMENT_CATEGORY, SNAPTARGET_DISTRIBUTION_CATEGORY); bool emp = m.snapprefs.isTargetSnappable(SNAPTARGET_BBOX_EDGE_MIDPOINT); // Preferably we'd use the bbox of each selected item, but for example 50 items will produce at least 200 bbox points, // which might make Inkscape crawl(see the comment a few lines above). In that case we will use the bbox of the selection as a whole diff --git a/src/snap-enums.h b/src/snap-enums.h index 6c6f412a3c..e69875d748 100644 --- a/src/snap-enums.h +++ b/src/snap-enums.h @@ -118,6 +118,17 @@ enum SnapTargetType { SNAPTARGET_ALIGNMENT_PAGE_CORNER, SNAPTARGET_ALIGNMENT_HANDLE, SNAPTARGET_ALIGNMENT_INTERSECTION, + + //------------------------------------------------------------------- + // Distribution snapping + SNAPTARGET_DISTRIBUTION_CATEGORY = 512, // will be used as a flag and must therefore be a power of two + SNAPTARGET_DISTRIBUTION_X, + SNAPTARGET_DISTRIBUTION_Y, + SNAPTARGET_DISTRIBUTION_RIGHT, + SNAPTARGET_DISTRIBUTION_LEFT, + SNAPTARGET_DISTRIBUTION_UP, + SNAPTARGET_DISTRIBUTION_DOWN, + //------------------------------------------------------------------- SNAPTARGET_MAX_ENUM_VALUE }; diff --git a/src/snap-preferences.cpp b/src/snap-preferences.cpp index a4b272cdcd..5074182d69 100644 --- a/src/snap-preferences.cpp +++ b/src/snap-preferences.cpp @@ -22,6 +22,7 @@ Inkscape::SnapPreferences::SnapPreferences() : { // Check for powers of two; see the comments in snap-enums.h g_assert((SNAPTARGET_BBOX_CATEGORY != 0) && !(SNAPTARGET_BBOX_CATEGORY & (SNAPTARGET_BBOX_CATEGORY - 1))); + g_assert((SNAPTARGET_DISTRIBUTION_CATEGORY != 0) && !(SNAPTARGET_DISTRIBUTION_CATEGORY & (SNAPTARGET_DISTRIBUTION_CATEGORY - 1))); g_assert((SNAPTARGET_ALIGNMENT_CATEGORY != 0) && !(SNAPTARGET_ALIGNMENT_CATEGORY & (SNAPTARGET_ALIGNMENT_CATEGORY - 1))); g_assert((SNAPTARGET_NODE_CATEGORY != 0) && !(SNAPTARGET_NODE_CATEGORY & (SNAPTARGET_NODE_CATEGORY - 1))); g_assert((SNAPTARGET_DATUMS_CATEGORY != 0) && !(SNAPTARGET_DATUMS_CATEGORY & (SNAPTARGET_DATUMS_CATEGORY - 1))); @@ -48,7 +49,8 @@ void Inkscape::SnapPreferences::_mapTargetToArrayIndex(Inkscape::SnapTargetType target == SNAPTARGET_NODE_CATEGORY || target == SNAPTARGET_OTHERS_CATEGORY || target == SNAPTARGET_DATUMS_CATEGORY || - target == SNAPTARGET_ALIGNMENT_CATEGORY) { + target == SNAPTARGET_ALIGNMENT_CATEGORY || + target == SNAPTARGET_DISTRIBUTION_CATEGORY) { // These main targets should be handled separately, because otherwise we might call isTargetSnappable() // for them (to check whether the corresponding group is on) which would lead to an infinite recursive loop always_on = (target == SNAPTARGET_DATUMS_CATEGORY); @@ -120,11 +122,16 @@ void Inkscape::SnapPreferences::_mapTargetToArrayIndex(Inkscape::SnapTargetType return; } - if (target & Inkscape::SNAPTARGET_ALIGNMENT_CATEGORY) { + if (target & SNAPTARGET_ALIGNMENT_CATEGORY) { group_on = isTargetSnappable(SNAPTARGET_ALIGNMENT_CATEGORY); return; } + if (target & SNAPTARGET_DISTRIBUTION_CATEGORY) { + group_on = isTargetSnappable(SNAPTARGET_DISTRIBUTION_CATEGORY); + return; + } + if (target & SNAPTARGET_OTHERS_CATEGORY) { // Only if the group with "other" snap sources/targets has been enabled, then we might snap to any of those targets // ... but this doesn't hold for the page border, grids, and guides diff --git a/src/snap-preferences.h b/src/snap-preferences.h index bcf3b81a44..34709c942d 100644 --- a/src/snap-preferences.h +++ b/src/snap-preferences.h @@ -54,11 +54,13 @@ public: double getGuideTolerance() const {return _guide_tolerance;} double getObjectTolerance() const {return _object_tolerance;} double getAlignmentTolerance() const {return _alignment_tolerance;} + double getDistributionTolerance() const {return _distribution_tolerance;} void setGridTolerance(double val) {_grid_tolerance = val;} void setGuideTolerance(double val) {_guide_tolerance = val;} void setObjectTolerance(double val) {_object_tolerance = val;} void setAlignementTolerance(double val) {_alignment_tolerance = val;} + void setDistributionTolerance(double val) {_distribution_tolerance = val;} private: @@ -98,6 +100,7 @@ private: double _guide_tolerance; double _object_tolerance; double _alignment_tolerance; + double _distribution_tolerance; }; } diff --git a/src/snap.cpp b/src/snap.cpp index 09d3f7ea30..084e1aef40 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -54,6 +54,7 @@ SnapManager::SnapManager(SPNamedView const *v) : guide(this, 0), object(this, 0), alignment(this, 0), + distribution(this, 0), snapprefs(), _named_view(v), _rotation_center_source_items(std::vector()), @@ -81,6 +82,7 @@ SnapManager::SnapperList SnapManager::getSnappers() const s.push_back(&guide); s.push_back(&object); s.push_back(&alignment); + s.push_back(&distribution); SnapManager::SnapperList gs = getGridSnappers(); s.splice(s.begin(), gs); @@ -928,7 +930,8 @@ void SnapManager::_findCandidates(SPObject* parent, if (bbox_of_item) { bool overflow = false; // See if the item is within range - if (getDesktop()->get_display_area().contains(bbox_of_item->midpoint())) { + auto display_area = getDesktop()->get_display_area(); + if (display_area.contains(bbox_of_item->min()) || display_area.contains(bbox_of_item->max())) { // Finally add the object to _candidates. align_snapper_candidates->push_back(Inkscape::SnapCandidateItem(item, clip_or_mask, additional_affine)); // For debugging: print the id of the candidate to the console diff --git a/src/snap.h b/src/snap.h index 9d8a91713f..c0b5f7d6f6 100644 --- a/src/snap.h +++ b/src/snap.h @@ -24,6 +24,7 @@ #include "object-snapper.h" #include "alignment-snapper.h" #include "snap-preferences.h" +#include "distribution-snapper.h" // Guides @@ -339,6 +340,7 @@ public: Inkscape::GuideSnapper guide; ///< guide snapper Inkscape::ObjectSnapper object; ///< snapper to other objects Inkscape::AlignmentSnapper alignment; ///< snapper to align with other objects + Inkscape::DistributionSnapper distribution; Inkscape::SnapPreferences snapprefs; /** @@ -449,6 +451,7 @@ private: friend class Inkscape::ObjectSnapper; friend class Inkscape::AlignmentSnapper; + friend class Inkscape::DistributionSnapper; }; #endif // !SEEN_SNAP_H diff --git a/src/snapped-point.cpp b/src/snapped-point.cpp index 1bc1656a9d..2019f2f129 100644 --- a/src/snapped-point.cpp +++ b/src/snapped-point.cpp @@ -185,7 +185,11 @@ void Inkscape::SnappedPoint::getPointIfSnapped(Geom::Point &p) const // search for the closest snapped point // This function give preference to the snapped points that are not in SNAPTARGET_ALIGNMENT_CATEGORY -// ie. for example, a longer Corner to Corner snap will be given prefrence over a Corner to alignment snap with lesser snapDistance. +// ie. for example, a longer Corner to Corner snap will be given prefrence over +// a Corner to alignment snap with lesser snapDistance. +// +// Incase there is an alignment snap along with a distribution snap possible, this +// function returns a new SnappedPoint that is are mix of the both bool getClosestSP(std::list const &list, Inkscape::SnappedPoint &result) { bool success = false; @@ -222,6 +226,29 @@ bool getClosestSP(std::list const &list, Inkscape::Snapp if (!success && aligned_success) result = aligned; + // the following code merges an alignment snap and a distribution snap + if (success && aligned_success) { + auto type = result.getTarget(); + if (type & Inkscape::SNAPTARGET_DISTRIBUTION_CATEGORY) { + switch (type) { + case Inkscape::SNAPTARGET_DISTRIBUTION_X: + case Inkscape::SNAPTARGET_DISTRIBUTION_RIGHT: + case Inkscape::SNAPTARGET_DISTRIBUTION_LEFT: + result.setPoint({result.getPoint().x(), aligned.getPoint().y()}); + break; + case Inkscape::SNAPTARGET_DISTRIBUTION_Y: + case Inkscape::SNAPTARGET_DISTRIBUTION_UP: + case Inkscape::SNAPTARGET_DISTRIBUTION_DOWN: + result.setPoint({aligned.getPoint().x() ,result.getPoint().y()}); + break; + default: + g_warning("getClosestSP(): unknown distribution snap target %i", result.getTarget()); + break; + } + return true; + } + } + return success ? success : aligned_success; } diff --git a/src/ui/dialog/document-properties.cpp b/src/ui/dialog/document-properties.cpp index d9ac14779f..16d59f9d86 100644 --- a/src/ui/dialog/document-properties.cpp +++ b/src/ui/dialog/document-properties.cpp @@ -135,6 +135,11 @@ DocumentProperties::DocumentProperties() _("Snapping distance, in screen pixels, for alignment snapping"), _("Always snap to alignment guides, regardless of the distance"), _("If set, objects only snap to as alignment guide when it's within the range specified below"), "alignmenttolerance", _wr) + //Options for distribution snapping + , _rsu_dssn(_("Snap distanc_e"), _("Snap only _when closer than:"), _("Always snap"), + _("Snapping distance, in screen pixels, for distribution snapping"), _("Always snap objects at equal distance, regardless of the distance"), + _("If set, objects only snap to at equal distances when it's within the range specified below"), + "distributiontolerance", _wr) //--------------------------------------------------------------- , _rcb_snclp(_("Snap to clip paths"), _("When snapping to paths, then also try snapping to clip paths"), "inkscape:snap-path-clip", _wr) , _rcb_snmsk(_("Snap to mask paths"), _("When snapping to paths, then also try snapping to mask paths"), "inkscape:snap-path-mask", _wr) @@ -368,6 +373,8 @@ void DocumentProperties::build_snap() label_gu->set_markup (_("Snap to guides")); Gtk::Label *label_as = Gtk::manage (new Gtk::Label); label_as->set_markup (_("Alignment Snapping")); + Gtk::Label *label_ds = Gtk::manage (new Gtk::Label); + label_ds->set_markup (_("Distance Snapping")); Gtk::Label *label_m = Gtk::manage (new Gtk::Label); label_m->set_markup (_("Miscellaneous")); @@ -389,6 +396,9 @@ void DocumentProperties::build_snap() label_as, nullptr, nullptr, _rsu_assn._vbox, nullptr, nullptr, + label_ds, nullptr, + nullptr, _rsu_dssn._vbox, + nullptr, nullptr, label_m, nullptr, nullptr, &_rcb_perp, nullptr, &_rcb_tang @@ -1415,6 +1425,7 @@ void DocumentProperties::update_widgets() _rsu_sn.setValue (nv->snap_manager.snapprefs.getGridTolerance()); _rsu_gusn.setValue (nv->snap_manager.snapprefs.getGuideTolerance()); _rsu_assn.setValue (nv->snap_manager.snapprefs.getAlignmentTolerance()); + _rsu_dssn.setValue (nv->snap_manager.snapprefs.getDistributionTolerance()); _rcb_snclp.setActive (nv->snap_manager.snapprefs.isSnapButtonEnabled(Inkscape::SNAPTARGET_PATH_CLIP)); _rcb_snmsk.setActive (nv->snap_manager.snapprefs.isSnapButtonEnabled(Inkscape::SNAPTARGET_PATH_MASK)); _rcb_perp.setActive (nv->snap_manager.snapprefs.getSnapPerp()); diff --git a/src/ui/dialog/document-properties.h b/src/ui/dialog/document-properties.h index fee6c38552..79d2b43fca 100644 --- a/src/ui/dialog/document-properties.h +++ b/src/ui/dialog/document-properties.h @@ -142,6 +142,7 @@ protected: UI::Widget::ToleranceSlider _rsu_sn; UI::Widget::ToleranceSlider _rsu_gusn; UI::Widget::ToleranceSlider _rsu_assn; + UI::Widget::ToleranceSlider _rsu_dssn; UI::Widget::RegisteredCheckButton _rcb_snclp; UI::Widget::RegisteredCheckButton _rcb_snmsk; UI::Widget::RegisteredCheckButton _rcb_perp; -- GitLab From ceabf2bcdc13b2a47633ae77a0cd5f2af84c1a78 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Wed, 9 Jun 2021 21:29:14 +0530 Subject: [PATCH 24/66] Added snap indicators for distribution snapping --- src/display/control/canvas-item-curve.cpp | 12 +- src/display/control/canvas-item-curve.h | 5 +- src/display/control/snap-indicator.cpp | 213 +++++++++++++++++++++- src/display/control/snap-indicator.h | 2 + src/distribution-snapper.cpp | 24 ++- src/snapped-point.cpp | 32 ++++ src/snapped-point.h | 10 + 7 files changed, 284 insertions(+), 14 deletions(-) diff --git a/src/display/control/canvas-item-curve.cpp b/src/display/control/canvas-item-curve.cpp index 74cce44f85..3590551c0c 100644 --- a/src/display/control/canvas-item-curve.cpp +++ b/src/display/control/canvas-item-curve.cpp @@ -84,6 +84,16 @@ void CanvasItemCurve::set_coords(Geom::Point const &p0, Geom::Point const &p1, G request_update(); } +/** + * Set stroke width. + */ +void CanvasItemCurve::set_width(int w) +{ + width = w; + + request_update(); +} + /** * Returns distance between point in canvas units and nearest point on curve. */ @@ -188,7 +198,7 @@ void CanvasItemCurve::render(Inkscape::CanvasItemBuffer *buf) buf->cr->set_source_rgba(SP_RGBA32_R_F(_stroke), SP_RGBA32_G_F(_stroke), SP_RGBA32_B_F(_stroke), SP_RGBA32_A_F(_stroke)); - buf->cr->set_line_width(1); + buf->cr->set_line_width(width); buf->cr->stroke(); // Uncomment to show bounds diff --git a/src/display/control/canvas-item-curve.h b/src/display/control/canvas-item-curve.h index 37129aad25..aae4a804f0 100644 --- a/src/display/control/canvas-item-curve.h +++ b/src/display/control/canvas-item-curve.h @@ -38,6 +38,7 @@ public: void set_coords(Geom::Point const &p0, Geom::Point const &p1); void set_coords(Geom::Point const &p0, Geom::Point const &p1, Geom::Point const &p2, Geom::Point const &p3); void set(Geom::BezierCurve &curve); + void set_width(int w); bool is_line() { return _curve->size() == 2; } void update(Geom::Affine const &affine) override; @@ -58,10 +59,10 @@ public: int get_corner1() { return _corner1; } protected: - std::unique_ptr _curve; - + std::unique_ptr _curve; bool _is_fill = true; // Fill or stroke, used by meshes. + int width = 1; int _corner0 = -1; // For meshes int _corner1 = -1; // For meshes }; diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index f6cc769dc1..bcb60eb27a 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -13,6 +13,7 @@ */ #include +#include #include "snap-indicator.h" @@ -68,15 +69,18 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap } bool is_alignment = p.getTarget() & SNAPTARGET_ALIGNMENT_CATEGORY; + bool is_distribution = p.getTarget() & SNAPTARGET_DISTRIBUTION_CATEGORY; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + double scale = prefs->getDouble("/tools/measure/scale", 100.0) / 100.0; + bool value = prefs->getBool("/options/snapindicator/value", true); if (value) { Glib::ustring target_name = _("UNDEFINED"); Glib::ustring source_name = _("UNDEFINED"); - if (!is_alignment) { + if (!is_alignment && !is_distribution) { // TRANSLATORS: undefined target for snapping switch (p.getTarget()) { case SNAPTARGET_UNDEFINED: @@ -264,6 +268,12 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap Inkscape::CanvasItemCtrl *ctrl2; Inkscape::CanvasItemCtrl *ctrl3; + double fontsize = prefs->getDouble("/tools/measure/fontsize", 10.0); + + if (is_distribution) { + make_distribution_indicators(p.getBBoxes(), *p.getSourceBBox(), p.getDistributionDistance(), p.getTarget(), fontsize, scale); + } + if (is_alignment) { auto color = pre_snap ? 0x7f7f7fff : get_guide_color(p.getTarget()); auto line = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p.getPoint(), p.getAlignmentTarget()); @@ -326,7 +336,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap _snaptarget_is_presnap = pre_snap; // Display the tooltip, which reveals the type of snap source and the type of snap target - if (!is_alignment) { + if (!is_alignment && !is_distribution) { Glib::ustring tooltip_str; if ( (p.getSource() != SNAPSOURCE_GRID_PITCH) && (p.getTarget() != SNAPTARGET_UNDEFINED) ) { tooltip_str = source_name + _(" to ") + target_name; @@ -334,7 +344,6 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap tooltip_str = source_name; } - double fontsize = prefs->getDouble("/tools/measure/fontsize", 10.0); if (!tooltip_str.empty()) { Geom::Point tooltip_pos = p.getPoint(); @@ -395,6 +404,10 @@ SnapIndicator::remove_snaptarget(bool only_if_presnap) } _alignment_snap_indicators.clear(); + for (auto *item : _distribution_snap_indicators) { + _desktop->remove_temporary_canvasitem(item); + } + _distribution_snap_indicators.clear(); } void @@ -465,6 +478,200 @@ guint32 SnapIndicator::get_guide_color(SnapTargetType t) } } +void SnapIndicator::make_distribution_indicators(std::vector const &bboxes, + Geom::Rect const &source_bbox, + Geom::Coord equal_dist, + SnapTargetType t, + double fontsize, + double scale) +{ + guint32 color = 0xff5f1fff; + guint32 text_fill = 0xffffffff; + guint32 text_bg = 0x33337f7f; + Geom::Point text_pos; + + switch (t) { + case SNAPTARGET_DISTRIBUTION_Y: + case SNAPTARGET_DISTRIBUTION_X: { + Geom::Point p1, p2, p3, p4; + switch (t) { + case SNAPTARGET_DISTRIBUTION_X: { + Geom::Coord y = source_bbox.midpoint().y(); + p1 = Geom::Point(bboxes.front().max().x(), y); + p2 = Geom::Point(source_bbox.min().x(), y); + p3 = Geom::Point(source_bbox.max().x(), y); + p4 = Geom::Point(bboxes.back().min().x(), y); + text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(0, -2*fontsize)); + break; + } + + case SNAPTARGET_DISTRIBUTION_Y: { + Geom::Coord x = source_bbox.midpoint().x(); + p1 = Geom::Point(x, bboxes.front().max().y()); + p2 = Geom::Point(x, source_bbox.min().y()); + p3 = Geom::Point(x, source_bbox.max().y()); + p4 = Geom::Point(x, bboxes.back().min().y()); + text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(-3*fontsize, 0)); + break; + } + } + + auto point1 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE, p1); + point1->set_size(7); + point1->set_stroke(color); + point1->set_fill(color); + point1->set_pickable(false); + + auto point2 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE, p2); + point2->set_size(7); + point2->set_stroke(color); + point2->set_fill(color); + point2->set_pickable(false); + + auto point3 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE, p3); + point3->set_size(7); + point3->set_stroke(color); + point3->set_fill(color); + point3->set_pickable(false); + + auto point4 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE, p4); + point4->set_size(7); + point4->set_stroke(color); + point4->set_fill(color); + point4->set_pickable(false); + + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point1, 0)); + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point2, 0)); + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point3, 0)); + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point4, 0)); + + auto line = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p1, p2); + line->set_stroke(color); + line->set_width(2); + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line, 0)); + + auto line2 = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p3, p4); + line2->set_stroke(color); + line2->set_width(2); + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line2, 0)); + + Glib::ustring distance = std::to_string(int(scale * equal_dist)); + auto text = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), text_pos, distance); + text->set_fontsize(fontsize); + text->set_fill(text_fill); + text->set_background(text_bg); + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(text, 0)); + break; + } + + case SNAPTARGET_DISTRIBUTION_RIGHT: + case SNAPTARGET_DISTRIBUTION_LEFT: + case SNAPTARGET_DISTRIBUTION_UP: + case SNAPTARGET_DISTRIBUTION_DOWN: { + Geom::Coord y = source_bbox.midpoint().y(); + Geom::Coord x = source_bbox.midpoint().x(); + Geom::Point p1; + Geom::Point p2; + switch (t) { + case SNAPTARGET_DISTRIBUTION_RIGHT: + p1 = Geom::Point(source_bbox.max().x(), y); + p2 = Geom::Point(bboxes.front().min().x(), y); + text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(0, -2*fontsize)); + break; + + case SNAPTARGET_DISTRIBUTION_LEFT: + p1 = Geom::Point(source_bbox.min().x(), y); + p2 = Geom::Point(bboxes.front().max().x(), y); + text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(0, -2*fontsize)); + break; + + case SNAPTARGET_DISTRIBUTION_UP: + p1 = Geom::Point(x, source_bbox.min().y()); + p2 = Geom::Point(x, bboxes.front().max().y()); + text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(-3*fontsize, 0)); + break; + + case SNAPTARGET_DISTRIBUTION_DOWN: + p1 = Geom::Point(x, source_bbox.max().y()); + p2 = Geom::Point(x, bboxes.front().min().y()); + text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(-3*fontsize, 0)); + break; + } + + auto point1 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE, p1); + point1->set_size(7); + point1->set_stroke(color); + point1->set_fill(color); + point1->set_pickable(false); + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point1, 0)); + + auto point2 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE, p2); + point2->set_size(7); + point2->set_stroke(color); + point2->set_fill(color); + point2->set_pickable(false); + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point2, 0)); + + auto line1 = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p1, p2); + line1->set_stroke(color); + line1->set_width(2); + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line1, 0)); + + Glib::ustring distance = std::to_string(int(equal_dist * scale)); + auto text = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), text_pos, distance); + text->set_fontsize(fontsize); + text->set_fill(text_fill); + text->set_background(text_bg); + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(text, 0)); + + for (auto it = bboxes.begin(); it + 1 != bboxes.end(); it++) { + switch (t) { + case SNAPTARGET_DISTRIBUTION_RIGHT: + p1 = Geom::Point(it->max().x(), y); + p2 = Geom::Point(std::next(it)->min().x(), y); + break; + + case SNAPTARGET_DISTRIBUTION_LEFT: + p1 = Geom::Point(it->min().x(), y); + p2 = Geom::Point(std::next(it)->max().x(), y); + break; + + case SNAPTARGET_DISTRIBUTION_UP: + p1 = Geom::Point(x, it->min().y()); + p2 = Geom::Point(x, std::next(it)->max().y()); + break; + + case SNAPTARGET_DISTRIBUTION_DOWN: + p1 = Geom::Point(x, it->max().y()); + p2 = Geom::Point(x, std::next(it)->min().y()); + break; + } + + point1 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE, p1); + point1->set_size(7); + point1->set_stroke(color); + point1->set_fill(color); + point1->set_pickable(false); + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point1, 0)); + + point2 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE, p2); + point2->set_size(7); + point2->set_stroke(color); + point2->set_fill(color); + point2->set_pickable(false); + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point2, 0)); + + line1 = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p1, p2); + line1->set_stroke(color); + line1->set_width(2); + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line1, 0)); + } + break; + } + + } +} + } //namespace Display } /* namespace Inkscape */ diff --git a/src/display/control/snap-indicator.h b/src/display/control/snap-indicator.h index 68f89e3d82..b00e526c05 100644 --- a/src/display/control/snap-indicator.h +++ b/src/display/control/snap-indicator.h @@ -48,6 +48,7 @@ protected: TemporaryItem *_snapsource; std::list _alignment_snap_indicators; + std::list _distribution_snap_indicators; std::list _debugging_points; bool _snaptarget_is_presnap; SPDesktop *_desktop; @@ -56,6 +57,7 @@ private: SnapIndicator(const SnapIndicator&) = delete; SnapIndicator& operator=(const SnapIndicator&) = delete; + void make_distribution_indicators(std::vector const &bboxes, Geom::Rect const &source_bbox, Geom::Coord equal_dist, SnapTargetType t, double fontsize, double scale); guint32 get_guide_color(SnapTargetType t); }; diff --git a/src/distribution-snapper.cpp b/src/distribution-snapper.cpp index e3b2e2a756..7049141a03 100644 --- a/src/distribution-snapper.cpp +++ b/src/distribution-snapper.cpp @@ -36,7 +36,6 @@ #include "snap-enums.h" #include "style.h" #include "svg/svg.h" -#include "text-editing.h" static int sortBoxesRight(Geom::Rect const &a, Geom::Rect const &b) { @@ -307,26 +306,31 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is if (_bboxes_down->size() > 0) pointD = _bboxes_down->begin()->min(); + Geom::Coord equal_dist; + // horizontally in between auto x = Geom::Point((pointR + pointL)/2).x(); + equal_dist = x - pointL.x(); dist = abs(x - bbox_to_snap->midpoint().x()); if (consider_x && dist < getSnapperTolerance()) { - auto s = SnappedPoint(Geom::Point(x, bbox_to_snap->midpoint().y()), p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_X, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true, *(_bboxes_right->begin())); + std::vector bboxes = {*_bboxes_left->begin(), *_bboxes_right->begin()}; + auto s = SnappedPoint(Geom::Point(x, bbox_to_snap->midpoint().y()), bboxes, *bbox_to_snap, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_X, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); //std::cout<<"X snap to"<midpoint().y())<midpoint().y()); if (consider_y && dist < getSnapperTolerance()) { - auto s = SnappedPoint(Geom::Point(bbox_to_snap->midpoint().x(), y), p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_Y, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true, *(_bboxes_up->begin())); + std::vector bboxes = {*_bboxes_up->begin(), *_bboxes_down->begin()}; + auto s = SnappedPoint(Geom::Point(bbox_to_snap->midpoint().x(), y), bboxes, *bbox_to_snap, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_Y, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); //std::cout<<"Y snap to"<<<size() > 1) { int num = findRightSnaps(_bboxes_right->begin(), _bboxes_right->end(), equal_dist); if (num > 0) { @@ -334,7 +338,8 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is Geom::Point target = bbox_to_snap->midpoint() + Geom::Point(offset, 0); if (abs(offset) < getSnapperTolerance()) { - auto s = SnappedPoint(target, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_RIGHT, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true, *(_bboxes_right->begin())); + std::vector bboxes(_bboxes_right->begin(), _bboxes_right->begin() + num + 1); + auto s = SnappedPoint(target, bboxes, *bbox_to_snap, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_RIGHT, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); isr.points.push_back(s); // Debug log @@ -356,7 +361,8 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is Geom::Point target = bbox_to_snap->midpoint() - Geom::Point(offset, 0); if (abs(offset) < getSnapperTolerance()) { - auto s = SnappedPoint(target, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_LEFT, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true, *(_bboxes_left->begin())); + std::vector bboxes(_bboxes_left->begin(), _bboxes_left->begin() + num + 1); + auto s = SnappedPoint(target, bboxes, *bbox_to_snap, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_LEFT, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); isr.points.push_back(s); // Debug log @@ -377,7 +383,8 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is Geom::Point target = bbox_to_snap->midpoint() - Geom::Point(0, offset); if (abs(offset) < getSnapperTolerance()) { - auto s = SnappedPoint(target, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_UP, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true, *(_bboxes_up->begin())); + std::vector bboxes(_bboxes_up->begin(), _bboxes_up->begin() + num + 1); + auto s = SnappedPoint(target, bboxes, *bbox_to_snap, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_UP, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); isr.points.push_back(s); // Debug log @@ -398,7 +405,8 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is Geom::Point target = bbox_to_snap->midpoint() + Geom::Point(0, offset); if (abs(offset) < getSnapperTolerance()) { - auto s = SnappedPoint(target, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_DOWN, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true, *(_bboxes_down->begin())); + std::vector bboxes(_bboxes_down->begin(), _bboxes_down->begin() + num + 1); + auto s = SnappedPoint(target, bboxes, *bbox_to_snap, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_DOWN, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); isr.points.push_back(s); // Debug log diff --git a/src/snapped-point.cpp b/src/snapped-point.cpp index 2019f2f129..127ca8454c 100644 --- a/src/snapped-point.cpp +++ b/src/snapped-point.cpp @@ -19,6 +19,7 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const _point(p), //_alignment_target(Geom::Point(0,0)), //_alignment_target2(Geom::Point(0,0)), + _equal_distance(Geom::infinity()), _tangent(Geom::Point(0,0)), _source(source), _source_num(source_num), @@ -41,6 +42,7 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, Geom::Point const &ap _point(p), _alignment_target(ap), //_alignment_target2(Geom::Point(0,0)), + _equal_distance(Geom::infinity()), _tangent(Geom::Point(0,0)), _source(source), _source_num(source_num), @@ -63,6 +65,7 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, Geom::Point const &ap _point(p), _alignment_target(ap), _alignment_target2(ap2), + _equal_distance(Geom::infinity()), _tangent(Geom::Point(0,0)), _source(source), _source_num(source_num), @@ -81,10 +84,36 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, Geom::Point const &ap { } +Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, std::vector const &bboxes, Geom::Rect const &source_bbox, Geom::Coord equal_dist, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained) : + _point(p), + //_alignment_target(Geom::Point(0,0)), + //_alignment_target2(Geom::Point(0,0)), + _equal_distance(equal_dist), + _distribution_bboxes(std::move(bboxes)), + _source_bbox(source_bbox), + _tangent(Geom::Point(0,0)), + _source(source), + _source_num(source_num), + _target(target), + _at_intersection (false), + _constrained_snap (constrained_snap), + _fully_constrained (fully_constrained), + _distance(d), + _tolerance(std::max(t,1.0)),// tolerance should never be smaller than 1 px, as it is used for normalization in isOtherSnapBetter. We don't want a division by zero. + _always_snap(a), + _second_distance (Geom::infinity()), + _second_tolerance (1), + _second_always_snap (false), + //_target_bbox(std::move(target_bbox)), + _pointer_distance (Geom::infinity()) +{ +} + Inkscape::SnappedPoint::SnappedPoint(Inkscape::SnapCandidatePoint const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained) : _point (p.getPoint()), //_alignment_target(Geom::Point(0,0)), //_alignment_target2(Geom::Point(0,0)), + _equal_distance(Geom::infinity()), _tangent (Geom::Point(0,0)), _source (p.getSourceType()), _source_num (p.getSourceNum()), @@ -107,6 +136,7 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const _point(p), //_alignment_target(Geom::Point(0,0)), //_alignment_target2(Geom::Point(0,0)), + _equal_distance(Geom::infinity()), _tangent (Geom::Point(0,0)), _source(source), _source_num(source_num), @@ -131,6 +161,7 @@ Inkscape::SnappedPoint::SnappedPoint(): _point (Geom::Point(0,0)), //_alignment_target(Geom::Point(0,0)), //_alignment_target2(Geom::Point(0,0)), + _equal_distance(Geom::infinity()), _tangent (Geom::Point(0,0)), _source (SNAPSOURCE_UNDEFINED), _source_num (-1), @@ -153,6 +184,7 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p): _point (p), //_alignment_target(Geom::Point(0,0)), //_alignment_target2(Geom::Point(0,0)), + _equal_distance(Geom::infinity()), _tangent (Geom::Point(0,0)), _source (SNAPSOURCE_UNDEFINED), _source_num (-1), diff --git a/src/snapped-point.h b/src/snapped-point.h index 89b728c81d..e7146ed8df 100644 --- a/src/snapped-point.h +++ b/src/snapped-point.h @@ -35,6 +35,7 @@ public: SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained, Geom::OptRect target_bbox = Geom::OptRect()); SnappedPoint(Geom::Point const &p, Geom::Point const &ap, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained, Geom::OptRect target_bbox); SnappedPoint(Geom::Point const &p, Geom::Point const &ap, Geom::Point const &ap2, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained, Geom::OptRect target_bbox); + SnappedPoint(Geom::Point const &p, std::vector const &bboxes, Geom::Rect const &source_bbox, Geom::Coord equal_dist, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained); SnappedPoint(SnapCandidatePoint const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained); ~SnappedPoint(); @@ -49,6 +50,8 @@ public: Geom::Coord getPointerDistance() const {return _pointer_distance;} void setPointerDistance(Geom::Coord const d) {_pointer_distance = d;} + std::vector const &getBBoxes() const {return _distribution_bboxes;} + /* This is the preferred method to find out which point we have snapped * to, because it only returns a point if snapping has actually occurred * (by overwriting p) @@ -97,6 +100,8 @@ public: SnapTargetType getTarget() const {return _target;} void setTargetBBox(Geom::OptRect const target) {_target_bbox = target;} Geom::OptRect const getTargetBBox() const {return _target_bbox;} + Geom::OptRect const getSourceBBox() const {return _source_bbox;} + Geom::Coord getDistributionDistance() const {return _equal_distance;} void setSource(SnapSourceType const source) {_source = source;} SnapSourceType getSource() const {return _source;} long getSourceNum() const {return _source_num;} @@ -125,6 +130,7 @@ protected: Geom::Point _tangent; // Tangent of the curve we snapped to, at the snapped point std::optional _alignment_target; // Target point for alignment snapping std::optional _alignment_target2; // Target point when alignment guides intersect + std::vector _distribution_bboxes; // A list of bounding boxes in case of distribution snapping SnapSourceType _source; // Describes what snapped long _source_num; // Sequence number of the source point that snapped, if that point is part of a set of points. (starting at zero if we might have a set of points; -1 if we only have a single point) SnapTargetType _target; // Describes to what we've snapped to @@ -147,10 +153,14 @@ protected: Geom::Coord _second_distance; /* The snapping tolerance in screen pixels (depends on zoom)*/ Geom::Coord _second_tolerance; + /* The equal distance between objects in screen pixels (depends on zoom) in case of distribution snapping*/ + Geom::Coord _equal_distance; /* If true then "Always snap" is on */ bool _second_always_snap; /* The bounding box we've snapped to (when applicable); will be used by the snapindicator */ Geom::OptRect _target_bbox; + /* The bounding box of the object we've snapped */ + Geom::OptRect _source_bbox; /* Distance from the un-transformed point to the mouse pointer, measured at the point in time when dragging started */ Geom::Coord _pointer_distance; }; -- GitLab From af4479a52fc2a958764d526943231ff6d592ac84 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Thu, 10 Jun 2021 11:58:56 +0530 Subject: [PATCH 25/66] position of distribution indicators now change relative to the position --- src/display/control/snap-indicator.cpp | 48 +++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index bcb60eb27a..600e859d92 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -478,6 +478,34 @@ guint32 SnapIndicator::get_guide_color(SnapTargetType t) } } +Geom::Coord get_y(Geom::Rect const &source, Geom::Rect const &target) +{ + Geom::Coord y; + + if (source.midpoint().y() == target.midpoint().y()) + y = target.midpoint().y(); + else if (source.midpoint().y() > target.midpoint().y()) + y = target.max().y(); + else + y = target.min().y(); + + return y; +} + +Geom::Coord get_x(Geom::Rect const &source, Geom::Rect const &target) +{ + Geom::Coord x; + + if (source.midpoint().x() == target.midpoint().x()) + x = target.midpoint().x(); + else if (source.midpoint().x() > target.midpoint().x()) + x = target.max().x(); + else + x = target.min().x(); + + return x; +} + void SnapIndicator::make_distribution_indicators(std::vector const &bboxes, Geom::Rect const &source_bbox, Geom::Coord equal_dist, @@ -496,7 +524,8 @@ void SnapIndicator::make_distribution_indicators(std::vector const & Geom::Point p1, p2, p3, p4; switch (t) { case SNAPTARGET_DISTRIBUTION_X: { - Geom::Coord y = source_bbox.midpoint().y(); + Geom::Coord y = get_y(source_bbox, bboxes.front()); + p1 = Geom::Point(bboxes.front().max().x(), y); p2 = Geom::Point(source_bbox.min().x(), y); p3 = Geom::Point(source_bbox.max().x(), y); @@ -506,7 +535,8 @@ void SnapIndicator::make_distribution_indicators(std::vector const & } case SNAPTARGET_DISTRIBUTION_Y: { - Geom::Coord x = source_bbox.midpoint().x(); + Geom::Coord x = get_x(source_bbox, bboxes.front()); + p1 = Geom::Point(x, bboxes.front().max().y()); p2 = Geom::Point(x, source_bbox.min().y()); p3 = Geom::Point(x, source_bbox.max().y()); @@ -568,30 +598,38 @@ void SnapIndicator::make_distribution_indicators(std::vector const & case SNAPTARGET_DISTRIBUTION_LEFT: case SNAPTARGET_DISTRIBUTION_UP: case SNAPTARGET_DISTRIBUTION_DOWN: { - Geom::Coord y = source_bbox.midpoint().y(); - Geom::Coord x = source_bbox.midpoint().x(); + Geom::Coord y; + Geom::Coord x; Geom::Point p1; Geom::Point p2; switch (t) { case SNAPTARGET_DISTRIBUTION_RIGHT: + y = get_y(source_bbox, bboxes.front()); + p1 = Geom::Point(source_bbox.max().x(), y); p2 = Geom::Point(bboxes.front().min().x(), y); text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(0, -2*fontsize)); break; case SNAPTARGET_DISTRIBUTION_LEFT: + y = get_y(source_bbox, bboxes.front()); + p1 = Geom::Point(source_bbox.min().x(), y); p2 = Geom::Point(bboxes.front().max().x(), y); text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(0, -2*fontsize)); break; case SNAPTARGET_DISTRIBUTION_UP: + x = get_x(source_bbox, bboxes.front()); + p1 = Geom::Point(x, source_bbox.min().y()); p2 = Geom::Point(x, bboxes.front().max().y()); text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(-3*fontsize, 0)); break; case SNAPTARGET_DISTRIBUTION_DOWN: + x = get_x(source_bbox, bboxes.front()); + p1 = Geom::Point(x, source_bbox.max().y()); p2 = Geom::Point(x, bboxes.front().min().y()); text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(-3*fontsize, 0)); @@ -617,7 +655,7 @@ void SnapIndicator::make_distribution_indicators(std::vector const & line1->set_width(2); _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line1, 0)); - Glib::ustring distance = std::to_string(int(equal_dist * scale)); + Glib::ustring distance = std::to_string(round(equal_dist * scale)); auto text = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), text_pos, distance); text->set_fontsize(fontsize); text->set_fill(text_fill); -- GitLab From 0f7067c5be38e562caeea713bfc0e7ce31be9beb Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Thu, 10 Jun 2021 16:20:27 +0530 Subject: [PATCH 26/66] fix source bbox is passed after translation --- src/display/control/snap-indicator.cpp | 10 +++--- src/distribution-snapper.cpp | 45 ++++++++++++++++++++------ 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index 600e859d92..d6728b2426 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -482,7 +482,7 @@ Geom::Coord get_y(Geom::Rect const &source, Geom::Rect const &target) { Geom::Coord y; - if (source.midpoint().y() == target.midpoint().y()) + if (abs(source.midpoint().y() - target.midpoint().y()) < 1e-5) y = target.midpoint().y(); else if (source.midpoint().y() > target.midpoint().y()) y = target.max().y(); @@ -496,7 +496,7 @@ Geom::Coord get_x(Geom::Rect const &source, Geom::Rect const &target) { Geom::Coord x; - if (source.midpoint().x() == target.midpoint().x()) + if (abs(source.midpoint().x() - target.midpoint().x()) < 1e-5) x = target.midpoint().x(); else if (source.midpoint().x() > target.midpoint().x()) x = target.max().x(); @@ -624,7 +624,7 @@ void SnapIndicator::make_distribution_indicators(std::vector const & p1 = Geom::Point(x, source_bbox.min().y()); p2 = Geom::Point(x, bboxes.front().max().y()); - text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(-3*fontsize, 0)); + text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(-2*fontsize, 0)); break; case SNAPTARGET_DISTRIBUTION_DOWN: @@ -632,7 +632,7 @@ void SnapIndicator::make_distribution_indicators(std::vector const & p1 = Geom::Point(x, source_bbox.max().y()); p2 = Geom::Point(x, bboxes.front().min().y()); - text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(-3*fontsize, 0)); + text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(-2*fontsize, 0)); break; } @@ -655,7 +655,7 @@ void SnapIndicator::make_distribution_indicators(std::vector const & line1->set_width(2); _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line1, 0)); - Glib::ustring distance = std::to_string(round(equal_dist * scale)); + Glib::ustring distance = std::to_string(int(equal_dist * scale)); auto text = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), text_pos, distance); text->set_fontsize(fontsize); text->set_fill(text_fill); diff --git a/src/distribution-snapper.cpp b/src/distribution-snapper.cpp index 7049141a03..1246481aaf 100644 --- a/src/distribution-snapper.cpp +++ b/src/distribution-snapper.cpp @@ -310,22 +310,33 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is // horizontally in between auto x = Geom::Point((pointR + pointL)/2).x(); - equal_dist = x - pointL.x(); dist = abs(x - bbox_to_snap->midpoint().x()); if (consider_x && dist < getSnapperTolerance()) { std::vector bboxes = {*_bboxes_left->begin(), *_bboxes_right->begin()}; - auto s = SnappedPoint(Geom::Point(x, bbox_to_snap->midpoint().y()), bboxes, *bbox_to_snap, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_X, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + Geom::Point target = Geom::Point(x, bbox_to_snap->midpoint().y()); + + // translate the source bbox to the snap position + Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); + Geom::Rect bbox = *bbox_to_snap * translation; + equal_dist = bbox.min().x() - pointL.x(); + auto s = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_X, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); //std::cout<<"X snap to"<midpoint().y())<min().y() - pointU.y(); dist = abs(y - bbox_to_snap->midpoint().y()); if (consider_y && dist < getSnapperTolerance()) { std::vector bboxes = {*_bboxes_up->begin(), *_bboxes_down->begin()}; - auto s = SnappedPoint(Geom::Point(bbox_to_snap->midpoint().x(), y), bboxes, *bbox_to_snap, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_Y, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + Geom::Point target = Geom::Point(bbox_to_snap->midpoint().x(), y); + + // translate the source bbox to the snap position + Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); + Geom::Rect bbox = *bbox_to_snap * translation; + equal_dist = bbox.min().y() - pointU.y(); + auto s = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_Y, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); //std::cout<<"Y snap to"<<< bboxes(_bboxes_right->begin(), _bboxes_right->begin() + num + 1); - auto s = SnappedPoint(target, bboxes, *bbox_to_snap, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_RIGHT, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + + // translate the source bbox to the snap position + Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); + Geom::Rect bbox = *bbox_to_snap * translation; + auto s = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_RIGHT, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); isr.points.push_back(s); // Debug log @@ -362,7 +377,11 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is if (abs(offset) < getSnapperTolerance()) { std::vector bboxes(_bboxes_left->begin(), _bboxes_left->begin() + num + 1); - auto s = SnappedPoint(target, bboxes, *bbox_to_snap, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_LEFT, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + + // translate the source bbox to the snap position + Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); + Geom::Rect bbox = *bbox_to_snap * translation; + auto s = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_LEFT, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); isr.points.push_back(s); // Debug log @@ -384,7 +403,11 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is if (abs(offset) < getSnapperTolerance()) { std::vector bboxes(_bboxes_up->begin(), _bboxes_up->begin() + num + 1); - auto s = SnappedPoint(target, bboxes, *bbox_to_snap, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_UP, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + + // translate the source bbox to the snap position + Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); + Geom::Rect bbox = *bbox_to_snap * translation; + auto s = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_UP, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); isr.points.push_back(s); // Debug log @@ -406,7 +429,11 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is if (abs(offset) < getSnapperTolerance()) { std::vector bboxes(_bboxes_down->begin(), _bboxes_down->begin() + num + 1); - auto s = SnappedPoint(target, bboxes, *bbox_to_snap, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_DOWN, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + + // translate the source bbox to the snap position + Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); + Geom::Rect bbox = *bbox_to_snap * translation; + auto s = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_DOWN, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); isr.points.push_back(s); // Debug log @@ -467,7 +494,7 @@ bool Inkscape::DistributionSnapper::ThisSnapperMightSnap() const bool Inkscape::DistributionSnapper::getSnapperAlwaysSnap() const { - return _snapmanager->snapprefs.getAlignmentTolerance() == 10000; //TODO: Replace this threshold of 10000 by a constant; see also tolerance-slider.cpp + return _snapmanager->snapprefs.getDistributionTolerance() == 10000; //TODO: Replace this threshold of 10000 by a constant; see also tolerance-slider.cpp } Geom::Coord Inkscape::DistributionSnapper::getSnapperTolerance() const -- GitLab From be9735ba77f5015db97f93f1e91f7608419fcbdf Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Thu, 10 Jun 2021 19:07:11 +0530 Subject: [PATCH 27/66] added stub lines to distribution snap indicators --- src/display/control/snap-indicator.cpp | 106 +++++++++++++------------ src/display/control/snap-indicator.h | 4 + 2 files changed, 59 insertions(+), 51 deletions(-) diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index d6728b2426..7720e5f1c2 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -506,6 +506,22 @@ Geom::Coord get_x(Geom::Rect const &source, Geom::Rect const &target) return x; } +Inkscape::CanvasItemCurve* SnapIndicator::make_stub_line_v(Geom::Point const & p) +{ + Geom::Coord length = 20; + auto line = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p + Geom::Point(0, length/2), p - Geom::Point(0, length/2)); + line->set_stroke(0xff5f1fff); + return line; +} + +Inkscape::CanvasItemCurve* SnapIndicator::make_stub_line_h(Geom::Point const & p) +{ + Geom::Coord length = 20; + auto line = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p + Geom::Point(length/2, 0), p - Geom::Point(length/2, 0)); + line->set_stroke(0xff5f1fff); + return line; +} + void SnapIndicator::make_distribution_indicators(std::vector const &bboxes, Geom::Rect const &source_bbox, Geom::Coord equal_dist, @@ -515,13 +531,14 @@ void SnapIndicator::make_distribution_indicators(std::vector const & { guint32 color = 0xff5f1fff; guint32 text_fill = 0xffffffff; - guint32 text_bg = 0x33337f7f; + guint32 text_bg = 0xff5f1fff; //0x33337f7f Geom::Point text_pos; switch (t) { case SNAPTARGET_DISTRIBUTION_Y: case SNAPTARGET_DISTRIBUTION_X: { Geom::Point p1, p2, p3, p4; + Inkscape::CanvasItemCurve *point1, *point2, *point3, *point4; switch (t) { case SNAPTARGET_DISTRIBUTION_X: { Geom::Coord y = get_y(source_bbox, bboxes.front()); @@ -531,6 +548,11 @@ void SnapIndicator::make_distribution_indicators(std::vector const & p3 = Geom::Point(source_bbox.max().x(), y); p4 = Geom::Point(bboxes.back().min().x(), y); text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(0, -2*fontsize)); + + point1 = make_stub_line_v(p1); + point2 = make_stub_line_v(p2); + point3 = make_stub_line_v(p3); + point4 = make_stub_line_v(p4); break; } @@ -542,34 +564,15 @@ void SnapIndicator::make_distribution_indicators(std::vector const & p3 = Geom::Point(x, source_bbox.max().y()); p4 = Geom::Point(x, bboxes.back().min().y()); text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(-3*fontsize, 0)); + + point1 = make_stub_line_h(p1); + point2 = make_stub_line_h(p2); + point3 = make_stub_line_h(p3); + point4 = make_stub_line_h(p4); break; } } - auto point1 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE, p1); - point1->set_size(7); - point1->set_stroke(color); - point1->set_fill(color); - point1->set_pickable(false); - - auto point2 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE, p2); - point2->set_size(7); - point2->set_stroke(color); - point2->set_fill(color); - point2->set_pickable(false); - - auto point3 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE, p3); - point3->set_size(7); - point3->set_stroke(color); - point3->set_fill(color); - point3->set_pickable(false); - - auto point4 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE, p4); - point4->set_size(7); - point4->set_stroke(color); - point4->set_fill(color); - point4->set_pickable(false); - _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point1, 0)); _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point2, 0)); _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point3, 0)); @@ -598,10 +601,9 @@ void SnapIndicator::make_distribution_indicators(std::vector const & case SNAPTARGET_DISTRIBUTION_LEFT: case SNAPTARGET_DISTRIBUTION_UP: case SNAPTARGET_DISTRIBUTION_DOWN: { - Geom::Coord y; - Geom::Coord x; - Geom::Point p1; - Geom::Point p2; + Geom::Coord x, y; + Geom::Point p1, p2; + Inkscape::CanvasItemCurve *point1, *point2; switch (t) { case SNAPTARGET_DISTRIBUTION_RIGHT: y = get_y(source_bbox, bboxes.front()); @@ -609,6 +611,9 @@ void SnapIndicator::make_distribution_indicators(std::vector const & p1 = Geom::Point(source_bbox.max().x(), y); p2 = Geom::Point(bboxes.front().min().x(), y); text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(0, -2*fontsize)); + + point1 = make_stub_line_v(p1); + point2 = make_stub_line_v(p2); break; case SNAPTARGET_DISTRIBUTION_LEFT: @@ -617,6 +622,9 @@ void SnapIndicator::make_distribution_indicators(std::vector const & p1 = Geom::Point(source_bbox.min().x(), y); p2 = Geom::Point(bboxes.front().max().x(), y); text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(0, -2*fontsize)); + + point1 = make_stub_line_v(p1); + point2 = make_stub_line_v(p2); break; case SNAPTARGET_DISTRIBUTION_UP: @@ -625,6 +633,9 @@ void SnapIndicator::make_distribution_indicators(std::vector const & p1 = Geom::Point(x, source_bbox.min().y()); p2 = Geom::Point(x, bboxes.front().max().y()); text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(-2*fontsize, 0)); + + point1 = make_stub_line_h(p1); + point2 = make_stub_line_h(p2); break; case SNAPTARGET_DISTRIBUTION_DOWN: @@ -633,21 +644,13 @@ void SnapIndicator::make_distribution_indicators(std::vector const & p1 = Geom::Point(x, source_bbox.max().y()); p2 = Geom::Point(x, bboxes.front().min().y()); text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(-2*fontsize, 0)); + + point1 = make_stub_line_h(p1); + point2 = make_stub_line_h(p2); break; } - auto point1 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE, p1); - point1->set_size(7); - point1->set_stroke(color); - point1->set_fill(color); - point1->set_pickable(false); _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point1, 0)); - - auto point2 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE, p2); - point2->set_size(7); - point2->set_stroke(color); - point2->set_fill(color); - point2->set_pickable(false); _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point2, 0)); auto line1 = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p1, p2); @@ -667,36 +670,37 @@ void SnapIndicator::make_distribution_indicators(std::vector const & case SNAPTARGET_DISTRIBUTION_RIGHT: p1 = Geom::Point(it->max().x(), y); p2 = Geom::Point(std::next(it)->min().x(), y); + + point1 = make_stub_line_v(p1); + point2 = make_stub_line_v(p2); break; case SNAPTARGET_DISTRIBUTION_LEFT: p1 = Geom::Point(it->min().x(), y); p2 = Geom::Point(std::next(it)->max().x(), y); + + point1 = make_stub_line_v(p1); + point2 = make_stub_line_v(p2); break; case SNAPTARGET_DISTRIBUTION_UP: p1 = Geom::Point(x, it->min().y()); p2 = Geom::Point(x, std::next(it)->max().y()); + + point1 = make_stub_line_h(p1); + point2 = make_stub_line_h(p2); break; case SNAPTARGET_DISTRIBUTION_DOWN: p1 = Geom::Point(x, it->max().y()); p2 = Geom::Point(x, std::next(it)->min().y()); + + point1 = make_stub_line_h(p1); + point2 = make_stub_line_h(p2); break; } - point1 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE, p1); - point1->set_size(7); - point1->set_stroke(color); - point1->set_fill(color); - point1->set_pickable(false); _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point1, 0)); - - point2 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE, p2); - point2->set_size(7); - point2->set_stroke(color); - point2->set_fill(color); - point2->set_pickable(false); _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point2, 0)); line1 = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p1, p2); diff --git a/src/display/control/snap-indicator.h b/src/display/control/snap-indicator.h index b00e526c05..bfaad8e0a1 100644 --- a/src/display/control/snap-indicator.h +++ b/src/display/control/snap-indicator.h @@ -18,6 +18,8 @@ */ #include "snapped-point.h" +#include "display/control/canvas-item-curve.h" + #include class SPDesktop; @@ -59,6 +61,8 @@ private: void make_distribution_indicators(std::vector const &bboxes, Geom::Rect const &source_bbox, Geom::Coord equal_dist, SnapTargetType t, double fontsize, double scale); guint32 get_guide_color(SnapTargetType t); + Inkscape::CanvasItemCurve* make_stub_line_h(Geom::Point const &p); + Inkscape::CanvasItemCurve* make_stub_line_v(Geom::Point const &p); }; } //namespace Display -- GitLab From ab28e875f67056723a135df4bc492c937384d77c Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Fri, 11 Jun 2021 17:31:39 +0530 Subject: [PATCH 28/66] alignment and distribution snap indicators show up together --- src/alignment-snapper.cpp | 4 ++-- src/display/control/snap-indicator.cpp | 14 +++++++------- src/snapped-point.cpp | 5 +++++ src/snapped-point.h | 24 ++++++++++++++++++------ 4 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/alignment-snapper.cpp b/src/alignment-snapper.cpp index b128dd0341..a36443822e 100644 --- a/src/alignment-snapper.cpp +++ b/src/alignment-snapper.cpp @@ -181,8 +181,8 @@ void Inkscape::AlignmentSnapper::_snapBBoxPoints(IntermSnapResults &isr, if (d < sqrt(2)*getSnapperTolerance()) { si = SnappedPoint(intersection_p, - sy.getAlignmentTarget(), - sx.getAlignmentTarget(), + *sy.getAlignmentTarget(), + *sx.getAlignmentTarget(), source2alignment(p.getSourceType()), p.getSourceNum(), SNAPTARGET_ALIGNMENT_INTERSECTION, diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index 7720e5f1c2..6ec45f4121 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -68,7 +68,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap return; } - bool is_alignment = p.getTarget() & SNAPTARGET_ALIGNMENT_CATEGORY; + bool is_alignment = p.getAlignmentTarget().has_value(); bool is_distribution = p.getTarget() & SNAPTARGET_DISTRIBUTION_CATEGORY; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); @@ -275,13 +275,13 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap } if (is_alignment) { - auto color = pre_snap ? 0x7f7f7fff : get_guide_color(p.getTarget()); - auto line = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p.getPoint(), p.getAlignmentTarget()); + auto color = pre_snap ? 0x7f7f7fff : get_guide_color(p.getAlignmentTargetType()); + auto line = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p.getPoint(), *p.getAlignmentTarget()); line->set_stroke(color); _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line, 0)); - if (p.getTarget() == SNAPTARGET_ALIGNMENT_INTERSECTION) { - auto line2 = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p.getPoint(), p.getAlignmentTarget2()); + if (p.getAlignmentTargetType() == SNAPTARGET_ALIGNMENT_INTERSECTION) { + auto line2 = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p.getPoint(), *p.getAlignmentTarget2()); line2->set_stroke(color); _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line2, 0)); @@ -289,7 +289,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap ctrl->set_size(7); ctrl->set_stroke(color); ctrl->set_fill(color); - ctrl->set_position(p.getAlignmentTarget2()); + ctrl->set_position(*p.getAlignmentTarget2()); _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl, 0)); ctrl->set_pickable(false); } @@ -318,7 +318,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap ctrl3->set_size(7); ctrl3->set_stroke(color); ctrl3->set_fill(color); - ctrl3->set_position(p.getAlignmentTarget()); + ctrl3->set_position(*p.getAlignmentTarget()); ctrl3->set_pickable(false); _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl3, 0)); diff --git a/src/snapped-point.cpp b/src/snapped-point.cpp index 127ca8454c..07c505f033 100644 --- a/src/snapped-point.cpp +++ b/src/snapped-point.cpp @@ -42,6 +42,7 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, Geom::Point const &ap _point(p), _alignment_target(ap), //_alignment_target2(Geom::Point(0,0)), + _alignment_target_type(target), _equal_distance(Geom::infinity()), _tangent(Geom::Point(0,0)), _source(source), @@ -65,6 +66,7 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, Geom::Point const &ap _point(p), _alignment_target(ap), _alignment_target2(ap2), + _alignment_target_type(target), _equal_distance(Geom::infinity()), _tangent(Geom::Point(0,0)), _source(source), @@ -277,6 +279,9 @@ bool getClosestSP(std::list const &list, Inkscape::Snapp g_warning("getClosestSP(): unknown distribution snap target %i", result.getTarget()); break; } + result.setAlignmentTargetType(aligned.getAlignmentTargetType()); + result.setAlignmentTarget(aligned.getAlignmentTarget()); + result.setAlignmentTarget2(aligned.getAlignmentTarget2()); return true; } } diff --git a/src/snapped-point.h b/src/snapped-point.h index e7146ed8df..5515c90dd3 100644 --- a/src/snapped-point.h +++ b/src/snapped-point.h @@ -68,23 +68,29 @@ public: */ Geom::Point getPoint() const {return _point;} void setPoint(Geom::Point const &p) {_point = p;} + void setAlignmentTarget(std::optional const &p) { + if (p.has_value()) + _alignment_target = p; + } + void setAlignmentTarget2(std::optional const &p) { + if (p.has_value()) + _alignment_target2 = p; + } Geom::Point getTangent() const {return _tangent;} - Geom::Point getAlignmentTarget() const + std::optional getAlignmentTarget() const { if (_alignment_target.has_value()) return _alignment_target.value(); else - g_warning("alignment target does not exit"); - return Geom::Point(); + return {}; } - Geom::Point getAlignmentTarget2() const + std::optional getAlignmentTarget2() const { if (_alignment_target2.has_value()) return _alignment_target2.value(); else - g_warning("alignment target does not exit"); - return Geom::Point(); + return {}; } Geom::Coord getDistanceToAignTarget() const @@ -97,7 +103,12 @@ public: bool getConstrainedSnap() const {return _constrained_snap;} bool getSnapped() const {return _distance < Geom::infinity();} void setTarget(SnapTargetType const target) {_target = target;} + void setAlignmentTargetType(SnapTargetType const target) {_alignment_target_type = target;} SnapTargetType getTarget() const {return _target;} + SnapTargetType getAlignmentTargetType() const + { + return _alignment_target_type.has_value() ? _alignment_target_type.value() : SNAPTARGET_UNDEFINED; + } void setTargetBBox(Geom::OptRect const target) {_target_bbox = target;} Geom::OptRect const getTargetBBox() const {return _target_bbox;} Geom::OptRect const getSourceBBox() const {return _source_bbox;} @@ -134,6 +145,7 @@ protected: SnapSourceType _source; // Describes what snapped long _source_num; // Sequence number of the source point that snapped, if that point is part of a set of points. (starting at zero if we might have a set of points; -1 if we only have a single point) SnapTargetType _target; // Describes to what we've snapped to + std::optional _alignment_target_type; // TODO: this is only used in case of both alignment and distribution snap bool _at_intersection; // If true, the snapped point is at an intersection bool _constrained_snap; // If true, then the snapped point was found when looking for a constrained snap bool _fully_constrained; // When snapping for example to a node, then the snap will be "fully constrained". -- GitLab From 190942150910806cad1694599ed169a374b6f1bd Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Sat, 12 Jun 2021 12:12:28 +0530 Subject: [PATCH 29/66] Added correction in case the selection has multiple objects --- src/display/control/snap-indicator.cpp | 20 ++- src/distribution-snapper.cpp | 200 ++++++++++++++----------- src/distribution-snapper.h | 19 +++ 3 files changed, 142 insertions(+), 97 deletions(-) diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index 6ec45f4121..2c9b0c69cd 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -322,7 +322,12 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap ctrl3->set_pickable(false); _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl3, 0)); - } else { + } + + _snaptarget_is_presnap = pre_snap; + + if (!is_alignment && !is_distribution) { + // Display snap indicator at snap target ctrl = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CROSS); ctrl->set_size(11); ctrl->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); @@ -330,13 +335,8 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap _snaptarget = _desktop->add_temporary_canvasitem(ctrl, timeout_val*1000.0); ctrl->set_pickable(false); - } - - _snaptarget_is_presnap = pre_snap; - - // Display the tooltip, which reveals the type of snap source and the type of snap target - if (!is_alignment && !is_distribution) { + // Display the tooltip, which reveals the type of snap source and the type of snap target Glib::ustring tooltip_str; if ( (p.getSource() != SNAPSOURCE_GRID_PITCH) && (p.getTarget() != SNAPTARGET_UNDEFINED) ) { tooltip_str = source_name + _(" to ") + target_name; @@ -712,6 +712,12 @@ void SnapIndicator::make_distribution_indicators(std::vector const & } } + auto box = new Inkscape::CanvasItemRect(_desktop->getCanvasTemp(), source_bbox); + box->set_stroke(color); + box->set_dashed(true); + box->set_pickable(false); // Is false by default. + box->set_z_position(0); + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(box, 0)); } } //namespace Display diff --git a/src/distribution-snapper.cpp b/src/distribution-snapper.cpp index 1246481aaf..fe3ff4a240 100644 --- a/src/distribution-snapper.cpp +++ b/src/distribution-snapper.cpp @@ -282,78 +282,84 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is else consider_y = false; // consider vertical snapping if moving horizontally } - _collectBBoxes(bbox_to_snap, p.getSourceNum() <= 0); + _collectBBoxes(bbox_to_snap, p.getSourceNum() <= 0); - Geom::Coord dist; + Geom::Coord dist; - if (p.getSourceType() != SNAPSOURCE_BBOX_MIDPOINT) - return; + if (p.getSourceType() != SNAPSOURCE_BBOX_MIDPOINT) + return; - // in between snap - Geom::Point pointR = Geom::Point(Geom::infinity(), Geom::infinity()); - if (_bboxes_right->size() > 0) - pointR = _bboxes_right->begin()->min(); - - Geom::Point pointL = Geom::Point(Geom::infinity(), Geom::infinity()); - if (_bboxes_left->size() > 0) - pointL = _bboxes_left->begin()->max(); - - Geom::Point pointU = Geom::Point(Geom::infinity(), Geom::infinity()); - if (_bboxes_up->size() > 0) - pointU = _bboxes_up->begin()->max(); - - Geom::Point pointD = Geom::Point(Geom::infinity(), Geom::infinity()); - if (_bboxes_down->size() > 0) - pointD = _bboxes_down->begin()->min(); - - Geom::Coord equal_dist; - - // horizontally in between - auto x = Geom::Point((pointR + pointL)/2).x(); - dist = abs(x - bbox_to_snap->midpoint().x()); - if (consider_x && dist < getSnapperTolerance()) { - std::vector bboxes = {*_bboxes_left->begin(), *_bboxes_right->begin()}; - Geom::Point target = Geom::Point(x, bbox_to_snap->midpoint().y()); - - // translate the source bbox to the snap position - Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); - Geom::Rect bbox = *bbox_to_snap * translation; - equal_dist = bbox.min().x() - pointL.x(); - auto s = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_X, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - //std::cout<<"X snap to"<midpoint().y())<size() > 0) + pointR = _bboxes_right->begin()->min(); + + Geom::Point pointL = Geom::Point(Geom::infinity(), Geom::infinity()); + if (_bboxes_left->size() > 0) + pointL = _bboxes_left->begin()->max(); + + Geom::Point pointU = Geom::Point(Geom::infinity(), Geom::infinity()); + if (_bboxes_up->size() > 0) + pointU = _bboxes_up->begin()->max(); + + Geom::Point pointD = Geom::Point(Geom::infinity(), Geom::infinity()); + if (_bboxes_down->size() > 0) + pointD = _bboxes_down->begin()->min(); + + Geom::Coord equal_dist; + + // horizontally in between + auto x = Geom::Point((pointR + pointL)/2).x(); + dist = abs(x - bbox_to_snap->midpoint().x()); + if (consider_x && dist < getSnapperTolerance()) { + std::vector bboxes = {*_bboxes_left->begin(), *_bboxes_right->begin()}; + Geom::Point target = Geom::Point(x, bbox_to_snap->midpoint().y()); + // translate the source bbox to the snap position + Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); + Geom::Rect bbox = *bbox_to_snap * translation; + + _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); + + equal_dist = bbox.min().x() - pointL.x(); + auto s = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_X, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + //std::cout<<"X snap to"<midpoint().y())<min().y() - pointU.y(); - dist = abs(y - bbox_to_snap->midpoint().y()); - if (consider_y && dist < getSnapperTolerance()) { - std::vector bboxes = {*_bboxes_up->begin(), *_bboxes_down->begin()}; - Geom::Point target = Geom::Point(bbox_to_snap->midpoint().x(), y); - - // translate the source bbox to the snap position - Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); - Geom::Rect bbox = *bbox_to_snap * translation; - equal_dist = bbox.min().y() - pointU.y(); - auto s = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_Y, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - //std::cout<<"Y snap to"<<<min().y() - pointU.y(); + dist = abs(y - bbox_to_snap->midpoint().y()); + if (consider_y && dist < getSnapperTolerance()) { + std::vector bboxes = {*_bboxes_up->begin(), *_bboxes_down->begin()}; + Geom::Point target = Geom::Point(bbox_to_snap->midpoint().x(), y); + // translate the source bbox to the snap position + Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); + Geom::Rect bbox = *bbox_to_snap * translation; + + _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); + + equal_dist = bbox.min().y() - pointU.y(); + auto s = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_Y, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + //std::cout<<"Y snap to"<<<size() > 1) { - int num = findRightSnaps(_bboxes_right->begin(), _bboxes_right->end(), equal_dist); - if (num > 0) { - Geom::Coord offset = - bbox_to_snap->max().x() + _bboxes_right->begin()->min().x() - equal_dist; - Geom::Point target = bbox_to_snap->midpoint() + Geom::Point(offset, 0); + // right snaps + if (consider_x && _bboxes_right->size() > 1) { + int num = findRightSnaps(_bboxes_right->begin(), _bboxes_right->end(), equal_dist); + if (num > 0) { + Geom::Coord offset = - bbox_to_snap->max().x() + _bboxes_right->begin()->min().x() - equal_dist; + Geom::Point target = bbox_to_snap->midpoint() + Geom::Point(offset, 0); if (abs(offset) < getSnapperTolerance()) { std::vector bboxes(_bboxes_right->begin(), _bboxes_right->begin() + num + 1); - // translate the source bbox to the snap position Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); Geom::Rect bbox = *bbox_to_snap * translation; + + _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); + auto s = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_RIGHT, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); isr.points.push_back(s); @@ -365,22 +371,24 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is //std::cout<<"equal_dist "<size() > 1 ) { - int num = findLeftSnaps(_bboxes_left->begin(), _bboxes_left->end(), equal_dist); - if (num > 0) { - Geom::Coord offset = bbox_to_snap->min().x() - _bboxes_left->begin()->max().x() - equal_dist; - Geom::Point target = bbox_to_snap->midpoint() - Geom::Point(offset, 0); + // left snaps + if (consider_x && _bboxes_left->size() > 1 ) { + int num = findLeftSnaps(_bboxes_left->begin(), _bboxes_left->end(), equal_dist); + if (num > 0) { + Geom::Coord offset = bbox_to_snap->min().x() - _bboxes_left->begin()->max().x() - equal_dist; + Geom::Point target = bbox_to_snap->midpoint() - Geom::Point(offset, 0); if (abs(offset) < getSnapperTolerance()) { std::vector bboxes(_bboxes_left->begin(), _bboxes_left->begin() + num + 1); - // translate the source bbox to the snap position Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); Geom::Rect bbox = *bbox_to_snap * translation; + + _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); + auto s = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_LEFT, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); isr.points.push_back(s); @@ -391,22 +399,24 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is //std::cout<<"offset "<size() > 1 ) { - int num = findUpSnaps(_bboxes_up->begin(), _bboxes_up->end(), equal_dist); - if (num > 0) { - Geom::Coord offset = bbox_to_snap->min().y() - _bboxes_up->begin()->max().y() - equal_dist; - Geom::Point target = bbox_to_snap->midpoint() - Geom::Point(0, offset); + // up snaps + if (consider_y && _bboxes_up->size() > 1 ) { + int num = findUpSnaps(_bboxes_up->begin(), _bboxes_up->end(), equal_dist); + if (num > 0) { + Geom::Coord offset = bbox_to_snap->min().y() - _bboxes_up->begin()->max().y() - equal_dist; + Geom::Point target = bbox_to_snap->midpoint() - Geom::Point(0, offset); if (abs(offset) < getSnapperTolerance()) { std::vector bboxes(_bboxes_up->begin(), _bboxes_up->begin() + num + 1); - // translate the source bbox to the snap position Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); Geom::Rect bbox = *bbox_to_snap * translation; + + _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); + auto s = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_UP, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); isr.points.push_back(s); @@ -417,22 +427,24 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is //std::cout<<"offset "<size() > 1 ) { - int num = findDownSnaps(_bboxes_down->begin(), _bboxes_down->end(), equal_dist); - if (num > 0) { - Geom::Coord offset = - bbox_to_snap->max().y() + _bboxes_down->begin()->min().y() - equal_dist; - Geom::Point target = bbox_to_snap->midpoint() + Geom::Point(0, offset); + // down snaps + if (consider_y && _bboxes_down->size() > 1 ) { + int num = findDownSnaps(_bboxes_down->begin(), _bboxes_down->end(), equal_dist); + if (num > 0) { + Geom::Coord offset = - bbox_to_snap->max().y() + _bboxes_down->begin()->min().y() - equal_dist; + Geom::Point target = bbox_to_snap->midpoint() + Geom::Point(0, offset); if (abs(offset) < getSnapperTolerance()) { std::vector bboxes(_bboxes_down->begin(), _bboxes_down->begin() + num + 1); - // translate the source bbox to the snap position Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); Geom::Rect bbox = *bbox_to_snap * translation; + + _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); + auto s = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_DOWN, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); isr.points.push_back(s); @@ -443,8 +455,16 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is //std::cout<<"offset "<_desktop->selection->size() > 1) { + auto correction = bbox_to_snap.midpoint() - p; + target -= correction; + } } void Inkscape::DistributionSnapper::freeSnap(IntermSnapResults &isr, diff --git a/src/distribution-snapper.h b/src/distribution-snapper.h index fc9915f868..054f5bdc47 100644 --- a/src/distribution-snapper.h +++ b/src/distribution-snapper.h @@ -76,12 +76,31 @@ private: */ void _collectBBoxes(Geom::OptRect const &bbox_to_snap, bool const &first_point) const; + /** Finds and snaps to points that is equidistant from surrounding bboxes + * @param interm snap results + * @param source point to snap + * @param bounding box of the selecton to snap + * @param unselected nodes in case editing nodes (never used here, remove?) + * @param active snap constraint + * @param projection of the source point on the constraint (never used, remove?) + */ void _snapEquidistantPoints(IntermSnapResults &isr, SnapCandidatePoint const &p, Geom::OptRect const &bbox_to_snap, std::vector *unselected_nodes, SnapConstraint const &c = SnapConstraint(), Geom::Point const &p_proj_on_constraint = Geom::Point()) const; + + /** When the selection has more than one objects in it, the bounding box of + * the object that the selection is grabbed from (closest to the pointer) is + * snapped to the center of the overall bounding box of the selection. This + * function corrects the target point to be a point where the bounding box of + * that particular object must be snapped to. + * @param snap target point that need to be snapped to + * @param source point to snap (this bbox midpoint of the object closest to the mouse pointer) + * @param bounding box of the active selection to snap + */ + void _correctSelectionBBox(Geom::Point &target, Geom::Point const &p, Geom::Rect const &bbox_to_snap) const; }; // end of AlignmentSnapper class } // end of namespace Inkscape -- GitLab From 00de6f618bb09913bb842d2793b05fb81313c797 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Sun, 13 Jun 2021 17:23:46 +0530 Subject: [PATCH 30/66] Condensed sideways snap functions into one findSidewaysSnaps() distributions snappind now recognises overlapping objects added .cache to gitignore for coc-nvim clangd cache --- .gitignore | 1 + src/display/control/snap-indicator.cpp | 6 - src/distribution-snapper.cpp | 310 +++++++++++-------------- src/distribution-snapper.h | 26 +++ 4 files changed, 168 insertions(+), 175 deletions(-) diff --git a/.gitignore b/.gitignore index ffa792e292..07bd6c6a20 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ inkscape_devel_source.tar.bz2 *.kdev4 .uuid .clangd/ +.cache compile_commands.json # Snap packaging specific rules diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index 2c9b0c69cd..6114493ba4 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -712,12 +712,6 @@ void SnapIndicator::make_distribution_indicators(std::vector const & } } - auto box = new Inkscape::CanvasItemRect(_desktop->getCanvasTemp(), source_bbox); - box->set_stroke(color); - box->set_dashed(true); - box->set_pickable(false); // Is false by default. - box->set_z_position(0); - _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(box, 0)); } } //namespace Display diff --git a/src/distribution-snapper.cpp b/src/distribution-snapper.cpp index fe3ff4a240..2be35961c1 100644 --- a/src/distribution-snapper.cpp +++ b/src/distribution-snapper.cpp @@ -65,112 +65,61 @@ static int sortBoxesDown(Geom::Rect const &a, Geom::Rect const &b) return 0; } -static int findRightSnaps(std::vector::iterator it, std::vector::iterator end, Geom::Coord &dist, int level = 0) +Geom::Coord Inkscape::DistributionSnapper::distRight(Geom::Rect const &a, Geom::Rect const &b) { - if (level > 5) - return 5; - - //if (it == end) - //return level; - - if (std::next(it) == end) - return level; - - if (it->intersects(*std::next(it))) - return level; - - if (level == 0) { - dist = - it->max().x() + std::next(it)->min().x(); - return findRightSnaps(++it, end, dist, ++level); - } - - // 1e-5 for accuracy if we use equality (==), it never satisfies. - if (-dist - it->max().x() + std::next(it)->min().x() < 1e-5) { - return findRightSnaps(++it, end, dist, ++level); - } else { - return level; - } + return -a.max().x() + b.min().x(); } -static int findLeftSnaps(std::vector::iterator it, std::vector::iterator end, Geom::Coord &dist, int level = 0) +Geom::Coord Inkscape::DistributionSnapper::distLeft(Geom::Rect const &a, Geom::Rect const &b) { - if (level > 5) - return 5; - - //if (it == end) - //return level; - - if (std::next(it) == end) - return level; - - if ((it)->intersects(*std::next(it))) - return level; - - if (level == 0) { - dist = it->min().x() - std::next(it)->max().x(); - return findLeftSnaps(++it, end, dist, ++level); - } - - // 1e-5 for accuracy if we use equality (==), it never satisfies. - if (-dist + it->min().x() - std::next(it)->max().x() < 1e-5) { - return findLeftSnaps(++it, end, dist, ++level); - } else { - return level; - } + return a.min().x() - b.max().x(); } -static int findUpSnaps(std::vector::iterator it, std::vector::iterator end, Geom::Coord &dist, int level = 0) +Geom::Coord Inkscape::DistributionSnapper::distUp(Geom::Rect const &a, Geom::Rect const &b) { - if (level > 5) - return 5; - - //if (it == end) - //return level; - - if (std::next(it) == end) - return level; - - if ((std::next(it))->intersects(*it)) - return level; - - if (level == 0) { - dist = it->min().y() - std::next(it)->max().y(); - return findUpSnaps(++it, end, dist, ++level); - } - - // 1e-5 for accuracy if we use equality (==), it never satisfies. - if (dist - it->min().y() + std::next(it)->max().y() < 1e-5) { - return findUpSnaps(++it, end, dist, ++level); - } else { - return level; - } + return a.min().y() - b.max().y(); } -static int findDownSnaps(std::vector::iterator it, std::vector::iterator end, Geom::Coord &dist, int level = 0) +Geom::Coord Inkscape::DistributionSnapper::distDown(Geom::Rect const &a, Geom::Rect const &b) { - if (level > 5) - return 5; + return -a.max().y() + b.min().y(); +} - //if (it == end) - //return level; +bool Inkscape::DistributionSnapper::findSidewaysSnaps(Geom::Coord first_dist, + std::vector::iterator it, + std::vector::iterator end, + std::vector &vec, + Geom::Coord &dist, + Geom::Coord tol, + Geom::Coord(*distance_func)(Geom::Rect const&, Geom::Rect const&), + int level) const +{ + Geom::Rect curr_bbox = *it; - if (std::next(it) == end) - return level; + if (it == end) + return level != 0; - if ((std::next(it))->intersects(*it)) - return level; + // TODO: check if rect1.instersects(rect2) gives the same result at rect2.intersects(rect1) + while (it->intersects(*std::next(it)) || std::next(it)->intersects(*it)) { + curr_bbox.unionWith(Geom::OptRect(*++it)); + } if (level == 0) { - dist = - it->max().y() + std::next(it)->min().y(); - return findDownSnaps(++it, end, dist, ++level); + vec.clear(); + dist = distance_func(*it, *std::next(it)); + if (abs(first_dist - dist) > tol) { + return false; + } + vec.push_back(curr_bbox); + return findSidewaysSnaps(first_dist, ++it, end, vec, dist, tol, distance_func, ++level); } - // 1e-5 for accuracy if we use equality (==), it never satisfies. - if (dist + it->max().y() - std::next(it)->min().y() < 1e-5) { - return findDownSnaps(++it, end, dist, ++level); - } else { - return level; + vec.push_back(curr_bbox); + if (abs(distance_func(*it, *std::next(it)) - dist) < 1e-5) { + return findSidewaysSnaps(first_dist, ++it, end, vec, dist, tol, distance_func, ++level); } + + return true; } Inkscape::DistributionSnapper::DistributionSnapper(SnapManager *sm, Geom::Coord const d) @@ -347,114 +296,137 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is // right snaps if (consider_x && _bboxes_right->size() > 1) { - int num = findRightSnaps(_bboxes_right->begin(), _bboxes_right->end(), equal_dist); - if (num > 0) { - Geom::Coord offset = - bbox_to_snap->max().x() + _bboxes_right->begin()->min().x() - equal_dist; + std::vector vec; + auto first_dist = distRight(*bbox_to_snap, _bboxes_right->front()); + + if (findSidewaysSnaps(first_dist, + _bboxes_right->begin(), + _bboxes_right->end(), + vec, + equal_dist, + getSnapperTolerance(), + &DistributionSnapper::distRight)) { + + Geom::Coord offset = first_dist - equal_dist; Geom::Point target = bbox_to_snap->midpoint() + Geom::Point(offset, 0); - if (abs(offset) < getSnapperTolerance()) { - std::vector bboxes(_bboxes_right->begin(), _bboxes_right->begin() + num + 1); - // translate the source bbox to the snap position - Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); - Geom::Rect bbox = *bbox_to_snap * translation; - - _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - - auto s = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_RIGHT, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - isr.points.push_back(s); - - // Debug log - //std::cout<<"------"<midpoint()); + Geom::Rect bbox = *bbox_to_snap * translation; + + _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); + + auto s = SnappedPoint(target, vec, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_RIGHT, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + isr.points.push_back(s); + + // Debug log + //std::cout<<"------"<size() > 1 ) { - int num = findLeftSnaps(_bboxes_left->begin(), _bboxes_left->end(), equal_dist); - if (num > 0) { - Geom::Coord offset = bbox_to_snap->min().x() - _bboxes_left->begin()->max().x() - equal_dist; + std::vector vec; + auto first_dist = distLeft(*bbox_to_snap, _bboxes_left->front()); + + if (findSidewaysSnaps(first_dist, + _bboxes_left->begin(), + _bboxes_left->end(), + vec, + equal_dist, + getSnapperTolerance(), + &DistributionSnapper::distLeft)) { + + Geom::Coord offset = first_dist - equal_dist; Geom::Point target = bbox_to_snap->midpoint() - Geom::Point(offset, 0); - if (abs(offset) < getSnapperTolerance()) { - std::vector bboxes(_bboxes_left->begin(), _bboxes_left->begin() + num + 1); - // translate the source bbox to the snap position - Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); - Geom::Rect bbox = *bbox_to_snap * translation; + // translate the source bbox to the snap position + Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); + Geom::Rect bbox = *bbox_to_snap * translation; - _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); + _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - auto s = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_LEFT, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - isr.points.push_back(s); + auto s = SnappedPoint(target, vec, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_LEFT, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + isr.points.push_back(s); - // Debug log - //std::cout<<"------"<size() > 1 ) { - int num = findUpSnaps(_bboxes_up->begin(), _bboxes_up->end(), equal_dist); - if (num > 0) { - Geom::Coord offset = bbox_to_snap->min().y() - _bboxes_up->begin()->max().y() - equal_dist; - Geom::Point target = bbox_to_snap->midpoint() - Geom::Point(0, offset); - - if (abs(offset) < getSnapperTolerance()) { - std::vector bboxes(_bboxes_up->begin(), _bboxes_up->begin() + num + 1); - // translate the source bbox to the snap position - Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); - Geom::Rect bbox = *bbox_to_snap * translation; - - _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - - auto s = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_UP, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - isr.points.push_back(s); - - // Debug log - //std::cout<<"------"< vec; + auto first_dist = distUp(*bbox_to_snap, _bboxes_up->front()); + + if (findSidewaysSnaps(first_dist, + _bboxes_up->begin(), + _bboxes_up->end(), + vec, + equal_dist, + getSnapperTolerance(), + &DistributionSnapper::distUp)) { + + Geom::Coord offset = first_dist - equal_dist; + Geom::Point target = bbox_to_snap->midpoint() - Geom::Point(offset, 0); + + // translate the source bbox to the snap position + Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); + Geom::Rect bbox = *bbox_to_snap * translation; + + _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); + + auto s = SnappedPoint(target, vec, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_UP, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + isr.points.push_back(s); + + // Debug log + //std::cout<<"------"<size() > 1 ) { - int num = findDownSnaps(_bboxes_down->begin(), _bboxes_down->end(), equal_dist); - if (num > 0) { - Geom::Coord offset = - bbox_to_snap->max().y() + _bboxes_down->begin()->min().y() - equal_dist; + std::vector vec; + auto first_dist = distDown(*bbox_to_snap, _bboxes_down->front()); + + if (findSidewaysSnaps(first_dist, + _bboxes_down->begin(), + _bboxes_down->end(), + vec, + equal_dist, + getSnapperTolerance(), + &DistributionSnapper::distDown)) { + + Geom::Coord offset = first_dist - equal_dist; Geom::Point target = bbox_to_snap->midpoint() + Geom::Point(0, offset); - if (abs(offset) < getSnapperTolerance()) { - std::vector bboxes(_bboxes_down->begin(), _bboxes_down->begin() + num + 1); - // translate the source bbox to the snap position - Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); - Geom::Rect bbox = *bbox_to_snap * translation; + // translate the source bbox to the snap position + Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); + Geom::Rect bbox = *bbox_to_snap * translation; - _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); + _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - auto s = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_DOWN, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - isr.points.push_back(s); + auto s = SnappedPoint(target, vec, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_DOWN, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + isr.points.push_back(s); - // Debug log - //std::cout<<"------"<::iterator it, + std::vector::iterator end, + std::vector &vec, + Geom::Coord &dist, + Geom::Coord tol, + Geom::Coord(*distance_func)(Geom::Rect const&, Geom::Rect const&), + int level = 0) const; + + // distance functions for different orientations + static Geom::Coord distRight(Geom::Rect const &a, Geom::Rect const &b); + static Geom::Coord distLeft(Geom::Rect const &a, Geom::Rect const &b); + static Geom::Coord distUp(Geom::Rect const &a, Geom::Rect const &b); + static Geom::Coord distDown(Geom::Rect const &a, Geom::Rect const &b); }; // end of AlignmentSnapper class } // end of namespace Inkscape -- GitLab From 650535cdff08446ac34e88dded76a571ae0e43cf Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Sun, 13 Jun 2021 21:32:11 +0530 Subject: [PATCH 31/66] fix wrong offset in up snap --- src/distribution-snapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/distribution-snapper.cpp b/src/distribution-snapper.cpp index 2be35961c1..d5b3c731b9 100644 --- a/src/distribution-snapper.cpp +++ b/src/distribution-snapper.cpp @@ -376,7 +376,7 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is &DistributionSnapper::distUp)) { Geom::Coord offset = first_dist - equal_dist; - Geom::Point target = bbox_to_snap->midpoint() - Geom::Point(offset, 0); + Geom::Point target = bbox_to_snap->midpoint() - Geom::Point(0, offset); // translate the source bbox to the snap position Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); -- GitLab From 8b69449f8c70ed160682dd22a1e4faeb3fc85450 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Mon, 14 Jun 2021 11:30:06 +0530 Subject: [PATCH 32/66] In-between snaps now use data from sideways snap and snap to overlapping objects --- src/distribution-snapper.cpp | 190 +++++++++++++++-------------------- 1 file changed, 82 insertions(+), 108 deletions(-) diff --git a/src/distribution-snapper.cpp b/src/distribution-snapper.cpp index d5b3c731b9..3239106bfd 100644 --- a/src/distribution-snapper.cpp +++ b/src/distribution-snapper.cpp @@ -106,15 +106,24 @@ bool Inkscape::DistributionSnapper::findSidewaysSnaps(Geom::Coord first_dist, if (level == 0) { vec.clear(); + + // just add the first point to the vector and return if there are no more + // objects this is used later to find in-between snaps + vec.push_back(curr_bbox); + if (std::next(it) == end) + return false; + dist = distance_func(*it, *std::next(it)); if (abs(first_dist - dist) > tol) { return false; } - vec.push_back(curr_bbox); + return findSidewaysSnaps(first_dist, ++it, end, vec, dist, tol, distance_func, ++level); } vec.push_back(curr_bbox); + // TODO: investige how does this tollerance affect the number of equidistant + // objects that are found? if (abs(distance_func(*it, *std::next(it)) - dist) < 1e-5) { return findSidewaysSnaps(first_dist, ++it, end, vec, dist, tol, distance_func, ++level); } @@ -207,13 +216,6 @@ void Inkscape::DistributionSnapper::_collectBBoxes(Geom::OptRect const &bbox_to_ std::stable_sort(_bboxes_left->begin(), _bboxes_left->end(), sortBoxesLeft); std::stable_sort(_bboxes_up->begin(), _bboxes_up->end(), sortBoxesUp); std::stable_sort(_bboxes_down->begin(), _bboxes_down->end(), sortBoxesDown); - - // Debug log - //std::cout<<"----------"<size()<size()<size()<size()<size() > 0) - pointR = _bboxes_right->begin()->min(); - - Geom::Point pointL = Geom::Point(Geom::infinity(), Geom::infinity()); - if (_bboxes_left->size() > 0) - pointL = _bboxes_left->begin()->max(); - - Geom::Point pointU = Geom::Point(Geom::infinity(), Geom::infinity()); - if (_bboxes_up->size() > 0) - pointU = _bboxes_up->begin()->max(); - - Geom::Point pointD = Geom::Point(Geom::infinity(), Geom::infinity()); - if (_bboxes_down->size() > 0) - pointD = _bboxes_down->begin()->min(); - Geom::Coord equal_dist; - // horizontally in between - auto x = Geom::Point((pointR + pointL)/2).x(); - dist = abs(x - bbox_to_snap->midpoint().x()); - if (consider_x && dist < getSnapperTolerance()) { - std::vector bboxes = {*_bboxes_left->begin(), *_bboxes_right->begin()}; - Geom::Point target = Geom::Point(x, bbox_to_snap->midpoint().y()); - // translate the source bbox to the snap position - Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); - Geom::Rect bbox = *bbox_to_snap * translation; - - _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - - equal_dist = bbox.min().x() - pointL.x(); - auto s = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_X, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - //std::cout<<"X snap to"<midpoint().y())<min().y() - pointU.y(); - dist = abs(y - bbox_to_snap->midpoint().y()); - if (consider_y && dist < getSnapperTolerance()) { - std::vector bboxes = {*_bboxes_up->begin(), *_bboxes_down->begin()}; - Geom::Point target = Geom::Point(bbox_to_snap->midpoint().x(), y); - // translate the source bbox to the snap position - Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); - Geom::Rect bbox = *bbox_to_snap * translation; - - _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - - equal_dist = bbox.min().y() - pointU.y(); - auto s = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_Y, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - //std::cout<<"Y snap to"<<<size() > 1) { - std::vector vec; + std::vector vecRight; + if (consider_x && _bboxes_right->size() > 0) { auto first_dist = distRight(*bbox_to_snap, _bboxes_right->front()); if (findSidewaysSnaps(first_dist, _bboxes_right->begin(), _bboxes_right->end(), - vec, + vecRight, equal_dist, getSnapperTolerance(), &DistributionSnapper::distRight)) { @@ -315,28 +264,20 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - auto s = SnappedPoint(target, vec, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_RIGHT, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + auto s = SnappedPoint(target, vecRight, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_RIGHT, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); isr.points.push_back(s); - - // Debug log - //std::cout<<"------"<size() > 1 ) { - std::vector vec; + std::vector vecLeft; + if (consider_x && _bboxes_left->size() > 0) { auto first_dist = distLeft(*bbox_to_snap, _bboxes_left->front()); if (findSidewaysSnaps(first_dist, _bboxes_left->begin(), _bboxes_left->end(), - vec, + vecLeft, equal_dist, getSnapperTolerance(), &DistributionSnapper::distLeft)) { @@ -350,27 +291,20 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - auto s = SnappedPoint(target, vec, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_LEFT, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + auto s = SnappedPoint(target, vecLeft, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_LEFT, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); isr.points.push_back(s); - - // Debug log - //std::cout<<"------"<size() > 1 ) { - std::vector vec; + std::vector vecUp; + if (consider_y && _bboxes_up->size() > 0) { auto first_dist = distUp(*bbox_to_snap, _bboxes_up->front()); if (findSidewaysSnaps(first_dist, _bboxes_up->begin(), _bboxes_up->end(), - vec, + vecUp, equal_dist, getSnapperTolerance(), &DistributionSnapper::distUp)) { @@ -384,27 +318,20 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - auto s = SnappedPoint(target, vec, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_UP, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + auto s = SnappedPoint(target, vecUp, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_UP, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); isr.points.push_back(s); - - // Debug log - //std::cout<<"------"<size() > 1 ) { - std::vector vec; + std::vector vecDown; + if (consider_y && _bboxes_down->size() > 0) { auto first_dist = distDown(*bbox_to_snap, _bboxes_down->front()); if (findSidewaysSnaps(first_dist, _bboxes_down->begin(), _bboxes_down->end(), - vec, + vecDown, equal_dist, getSnapperTolerance(), &DistributionSnapper::distDown)) { @@ -418,17 +345,64 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - auto s = SnappedPoint(target, vec, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_DOWN, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + auto s = SnappedPoint(target, vecDown, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_DOWN, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); isr.points.push_back(s); - - // Debug log - //std::cout<<"------"< 0) + pointR = vecRight.front().min(); + + Geom::Point pointL = Geom::Point(Geom::infinity(), Geom::infinity()); + if (vecLeft.size() > 0) + pointL = vecLeft.front().max(); + + Geom::Point pointU = Geom::Point(Geom::infinity(), Geom::infinity()); + if (vecUp.size() > 0) + pointU = vecUp.front().max(); + + Geom::Point pointD = Geom::Point(Geom::infinity(), Geom::infinity()); + if (vecDown.size() > 0) + pointD = vecDown.front().min(); + + + // horizontally in between + auto x = Geom::Point((pointR + pointL)/2).x(); + offset = abs(x - bbox_to_snap->midpoint().x()); + if (consider_x && offset < getSnapperTolerance()) { + std::vector bboxes = {*_bboxes_left->begin(), *_bboxes_right->begin()}; + Geom::Point target = Geom::Point(x, bbox_to_snap->midpoint().y()); + // translate the source bbox to the snap position + Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); + Geom::Rect bbox = *bbox_to_snap * translation; + + _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); + + equal_dist = bbox.min().x() - pointL.x(); + auto s = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_X, offset, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + isr.points.push_back(s); + } + + // vertically in between + auto y = Geom::Point((pointU + pointD)/2).y(); + equal_dist = bbox_to_snap->min().y() - pointU.y(); + offset = abs(y - bbox_to_snap->midpoint().y()); + if (consider_y && offset < getSnapperTolerance()) { + std::vector bboxes = {*_bboxes_up->begin(), *_bboxes_down->begin()}; + Geom::Point target = Geom::Point(bbox_to_snap->midpoint().x(), y); + // translate the source bbox to the snap position + Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); + Geom::Rect bbox = *bbox_to_snap * translation; + + _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); + + equal_dist = bbox.min().y() - pointU.y(); + auto s = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_Y, offset, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + isr.points.push_back(s); + } + } void Inkscape::DistributionSnapper::_correctSelectionBBox(Geom::Point &target, Geom::Point const &p, Geom::Rect const &bbox_to_snap) const -- GitLab From 3755a755e3a2cac059d373842b02ab557e038b59 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Mon, 14 Jun 2021 21:02:52 +0530 Subject: [PATCH 33/66] added distance to alignment snap indicators --- src/display/control/snap-indicator.cpp | 97 ++++++++++++++------------ src/display/control/snap-indicator.h | 1 + src/distribution-snapper.h | 1 - 3 files changed, 55 insertions(+), 44 deletions(-) diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index 6114493ba4..80f28ce54f 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -276,30 +276,22 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap if (is_alignment) { auto color = pre_snap ? 0x7f7f7fff : get_guide_color(p.getAlignmentTargetType()); - auto line = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p.getPoint(), *p.getAlignmentTarget()); - line->set_stroke(color); - _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line, 0)); - + make_alignment_indicator(p.getPoint(), *p.getAlignmentTarget(), color, fontsize, scale); if (p.getAlignmentTargetType() == SNAPTARGET_ALIGNMENT_INTERSECTION) { - auto line2 = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p.getPoint(), *p.getAlignmentTarget2()); - line2->set_stroke(color); - _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line2, 0)); - - ctrl = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); - ctrl->set_size(7); - ctrl->set_stroke(color); - ctrl->set_fill(color); - ctrl->set_position(*p.getAlignmentTarget2()); - _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl, 0)); - ctrl->set_pickable(false); + make_alignment_indicator(p.getPoint(), *p.getAlignmentTarget2(), color, fontsize, scale); } + } - ctrl2 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); - ctrl2->set_size(7); - ctrl2->set_stroke(color); - ctrl2->set_fill(color); - ctrl2->set_position(p.getPoint()); + _snaptarget_is_presnap = pre_snap; + if (!is_alignment && !is_distribution) { + // Display snap indicator at snap target + ctrl = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CROSS); + ctrl->set_size(11); + ctrl->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); + ctrl->set_position(p.getPoint()); + + _snaptarget = _desktop->add_temporary_canvasitem(ctrl, timeout_val*1000.0); // The snap indicator will be deleted after some time-out, and sp_canvas_item_dispose // will be called. This will set canvas->current_item to NULL if the snap indicator was // the current item, after which any events will go to the root handler instead of any @@ -311,29 +303,6 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap // (https://bugs.launchpad.net/inkscape/+bug/522335/comments/8) // - dragging doesn't work without repicking // (https://bugs.launchpad.net/inkscape/+bug/1420301/comments/15) - ctrl2->set_pickable(false); - _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl2, 0)); - - ctrl3 = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); - ctrl3->set_size(7); - ctrl3->set_stroke(color); - ctrl3->set_fill(color); - ctrl3->set_position(*p.getAlignmentTarget()); - ctrl3->set_pickable(false); - _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl3, 0)); - - } - - _snaptarget_is_presnap = pre_snap; - - if (!is_alignment && !is_distribution) { - // Display snap indicator at snap target - ctrl = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CROSS); - ctrl->set_size(11); - ctrl->set_stroke( pre_snap ? 0x7f7f7fff : 0xff0000ff); - ctrl->set_position(p.getPoint()); - - _snaptarget = _desktop->add_temporary_canvasitem(ctrl, timeout_val*1000.0); ctrl->set_pickable(false); // Display the tooltip, which reveals the type of snap source and the type of snap target @@ -506,6 +475,48 @@ Geom::Coord get_x(Geom::Rect const &source, Geom::Rect const &target) return x; } +void SnapIndicator::make_alignment_indicator(Geom::Point const &p1, Geom::Point const &p2, guint32 color, double fontsize, double scale) +{ + auto dist = Geom::L2(p2 - p1); + double offset = 15/_desktop->current_zoom(); + auto direction = Geom::unit_vector(p1 - p2); + auto text_pos = (p1 + p2)/2; + Glib::ustring distance = std::to_string(int(scale * dist)); + auto text = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), text_pos, distance); + text->set_fontsize(fontsize); + text->set_fill(color); + _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(text, 0)); + text->set_background(0xffffff00); + + Inkscape::CanvasItemCurve *line; + + auto temp_point = text_pos + offset*direction; + line = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p1, temp_point); + line->set_stroke(color); + _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line, 0)); + + temp_point = text_pos - offset*direction; + line = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), temp_point, p2); + line->set_stroke(color); + _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line, 0)); + + auto ctrl = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); + ctrl->set_size(7); + ctrl->set_stroke(color); + ctrl->set_fill(color); + ctrl->set_position(p1); + ctrl->set_pickable(false); + _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl, 0)); + + ctrl = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); + ctrl->set_size(7); + ctrl->set_stroke(color); + ctrl->set_fill(color); + ctrl->set_position(p2); + ctrl->set_pickable(false); + _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl, 0)); +} + Inkscape::CanvasItemCurve* SnapIndicator::make_stub_line_v(Geom::Point const & p) { Geom::Coord length = 20; diff --git a/src/display/control/snap-indicator.h b/src/display/control/snap-indicator.h index bfaad8e0a1..b4be643172 100644 --- a/src/display/control/snap-indicator.h +++ b/src/display/control/snap-indicator.h @@ -60,6 +60,7 @@ private: SnapIndicator& operator=(const SnapIndicator&) = delete; void make_distribution_indicators(std::vector const &bboxes, Geom::Rect const &source_bbox, Geom::Coord equal_dist, SnapTargetType t, double fontsize, double scale); + void make_alignment_indicator(Geom::Point const &p1, Geom::Point const &p2, guint32 color, double fontsize, double scale); guint32 get_guide_color(SnapTargetType t); Inkscape::CanvasItemCurve* make_stub_line_h(Geom::Point const &p); Inkscape::CanvasItemCurve* make_stub_line_v(Geom::Point const &p); diff --git a/src/distribution-snapper.h b/src/distribution-snapper.h index 779e1d67db..bd2d7afc74 100644 --- a/src/distribution-snapper.h +++ b/src/distribution-snapper.h @@ -16,7 +16,6 @@ #include "snap-enums.h" #include "snapper.h" #include "snap-candidate.h" -#include "boost/graph/adjacency_list.hpp" class SPDesktop; class SPNamedView; -- GitLab From be2f0b2e5259e90875765ec1b67c0e8d661d5827 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Tue, 15 Jun 2021 09:06:47 +0530 Subject: [PATCH 34/66] added preference for showing distances --- src/display/control/snap-indicator.cpp | 79 ++++++++++++++++---------- src/ui/dialog/inkscape-preferences.cpp | 6 ++ src/ui/dialog/inkscape-preferences.h | 1 + 3 files changed, 55 insertions(+), 31 deletions(-) diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index 80f28ce54f..b87513dcd4 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -477,28 +477,38 @@ Geom::Coord get_x(Geom::Rect const &source, Geom::Rect const &target) void SnapIndicator::make_alignment_indicator(Geom::Point const &p1, Geom::Point const &p2, guint32 color, double fontsize, double scale) { - auto dist = Geom::L2(p2 - p1); - double offset = 15/_desktop->current_zoom(); - auto direction = Geom::unit_vector(p1 - p2); - auto text_pos = (p1 + p2)/2; - Glib::ustring distance = std::to_string(int(scale * dist)); - auto text = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), text_pos, distance); - text->set_fontsize(fontsize); - text->set_fill(color); - _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(text, 0)); - text->set_background(0xffffff00); + Preferences *prefs = Preferences::get(); + bool show_distance = prefs->getBool("/options/snapindicatordistance/value", false); Inkscape::CanvasItemCurve *line; - auto temp_point = text_pos + offset*direction; - line = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p1, temp_point); - line->set_stroke(color); - _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line, 0)); - - temp_point = text_pos - offset*direction; - line = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), temp_point, p2); - line->set_stroke(color); - _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line, 0)); + if (show_distance) { + auto dist = Geom::L2(p2 - p1); + double offset = 15/_desktop->current_zoom(); + auto direction = Geom::unit_vector(p1 - p2); + auto text_pos = (p1 + p2)/2; + Glib::ustring distance = std::to_string(int(scale * dist)); + + auto text = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), text_pos, distance); + text->set_fontsize(fontsize); + text->set_fill(color); + _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(text, 0)); + text->set_background(0xffffff00); + + auto temp_point = text_pos + offset*direction; + line = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p1, temp_point); + line->set_stroke(color); + _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line, 0)); + + temp_point = text_pos - offset*direction; + line = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), temp_point, p2); + line->set_stroke(color); + _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line, 0)); + } else { + line = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p1, p2); + line->set_stroke(color); + _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line, 0)); + } auto ctrl = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); ctrl->set_size(7); @@ -540,6 +550,9 @@ void SnapIndicator::make_distribution_indicators(std::vector const & double fontsize, double scale) { + Preferences *prefs = Preferences::get(); + bool show_distance = prefs->getBool("/options/snapindicatordistance/value", false); + guint32 color = 0xff5f1fff; guint32 text_fill = 0xffffffff; guint32 text_bg = 0xff5f1fff; //0x33337f7f @@ -599,12 +612,14 @@ void SnapIndicator::make_distribution_indicators(std::vector const & line2->set_width(2); _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line2, 0)); - Glib::ustring distance = std::to_string(int(scale * equal_dist)); - auto text = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), text_pos, distance); - text->set_fontsize(fontsize); - text->set_fill(text_fill); - text->set_background(text_bg); - _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(text, 0)); + if (show_distance) { + Glib::ustring distance = std::to_string(int(scale * equal_dist)); + auto text = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), text_pos, distance); + text->set_fontsize(fontsize); + text->set_fill(text_fill); + text->set_background(text_bg); + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(text, 0)); + } break; } @@ -669,12 +684,14 @@ void SnapIndicator::make_distribution_indicators(std::vector const & line1->set_width(2); _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line1, 0)); - Glib::ustring distance = std::to_string(int(equal_dist * scale)); - auto text = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), text_pos, distance); - text->set_fontsize(fontsize); - text->set_fill(text_fill); - text->set_background(text_bg); - _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(text, 0)); + if (show_distance) { + Glib::ustring distance = std::to_string(int(equal_dist * scale)); + auto text = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), text_pos, distance); + text->set_fontsize(fontsize); + text->set_fill(text_fill); + text->set_background(text_bg); + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(text, 0)); + } for (auto it = bboxes.begin(); it + 1 != bboxes.end(); it++) { switch (t) { diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp index 2c48f93dcc..6ad8a64fc2 100644 --- a/src/ui/dialog/inkscape-preferences.cpp +++ b/src/ui/dialog/inkscape-preferences.cpp @@ -2388,6 +2388,12 @@ void InkscapePreferences::initPageBehavior() _page_snapping.add_line( true, _("Delay (in seconds):"), _snap_delay, "", _("Postpone snapping as long as the mouse is moving, and then wait an additional fraction of a second. This additional delay is specified here. When set to zero or to a very small number, snapping will be immediate."), true); + _page_snapping.add_group_header( _("Intelligent Snapping")); + + _snap_indicator_distance.init( _("Show snap distance in case of alignment or distribution snap"), "/options/snapindicatordistance/value", true); + _page_snapping.add_line( true, "", _snap_indicator_distance, "", + _("Show snap distance in case of alignment or distribution snap")); + this->AddPage(_page_snapping, _("Snapping"), iter_behavior, PREFS_PAGE_BEHAVIOR_SNAPPING); // Steps options diff --git a/src/ui/dialog/inkscape-preferences.h b/src/ui/dialog/inkscape-preferences.h index a00dcae0a3..e19208a68a 100644 --- a/src/ui/dialog/inkscape-preferences.h +++ b/src/ui/dialog/inkscape-preferences.h @@ -216,6 +216,7 @@ protected: UI::Widget::PrefCheckButton _snap_indicator; UI::Widget::PrefCheckButton _snap_closest_only; UI::Widget::PrefCheckButton _snap_mouse_pointer; + UI::Widget::PrefCheckButton _snap_indicator_distance; UI::Widget::PrefCombo _steps_rot_snap; UI::Widget::PrefCheckButton _steps_rot_relative; -- GitLab From 53594e4ec3951feedfd50d4c5120a55db28a7d2f Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Tue, 15 Jun 2021 09:07:36 +0530 Subject: [PATCH 35/66] fix positioning of distribution guides --- src/display/control/snap-indicator.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index b87513dcd4..33b8380a0b 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -451,9 +451,7 @@ Geom::Coord get_y(Geom::Rect const &source, Geom::Rect const &target) { Geom::Coord y; - if (abs(source.midpoint().y() - target.midpoint().y()) < 1e-5) - y = target.midpoint().y(); - else if (source.midpoint().y() > target.midpoint().y()) + if (source.midpoint().y() > target.midpoint().y()) y = target.max().y(); else y = target.min().y(); @@ -465,9 +463,7 @@ Geom::Coord get_x(Geom::Rect const &source, Geom::Rect const &target) { Geom::Coord x; - if (abs(source.midpoint().x() - target.midpoint().x()) < 1e-5) - x = target.midpoint().x(); - else if (source.midpoint().x() > target.midpoint().x()) + if (source.midpoint().x() > target.midpoint().x()) x = target.max().x(); else x = target.min().x(); @@ -587,7 +583,7 @@ void SnapIndicator::make_distribution_indicators(std::vector const & p2 = Geom::Point(x, source_bbox.min().y()); p3 = Geom::Point(x, source_bbox.max().y()); p4 = Geom::Point(x, bboxes.back().min().y()); - text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(-3*fontsize, 0)); + text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(-2*fontsize, 0)); point1 = make_stub_line_h(p1); point2 = make_stub_line_h(p2); -- GitLab From e1050c1b40ff677550495c899694f5d39fdff950 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Tue, 15 Jun 2021 10:52:04 +0530 Subject: [PATCH 36/66] added new attributes to attributes-test.cpp --- src/display/control/snap-indicator.cpp | 9 +++------ testfiles/src/attributes-test.cpp | 5 +++++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index 33b8380a0b..9b9620a87a 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -262,12 +262,6 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap // Besides, negatives values would ....? } - // Display the snap indicator (i.e. the cross) - - Inkscape::CanvasItemCtrl *ctrl; - Inkscape::CanvasItemCtrl *ctrl2; - Inkscape::CanvasItemCtrl *ctrl3; - double fontsize = prefs->getDouble("/tools/measure/fontsize", 10.0); if (is_distribution) { @@ -283,6 +277,9 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap } _snaptarget_is_presnap = pre_snap; + + // Display the snap indicator (i.e. the cross) + Inkscape::CanvasItemCtrl *ctrl; if (!is_alignment && !is_distribution) { // Display snap indicator at snap target diff --git a/testfiles/src/attributes-test.cpp b/testfiles/src/attributes-test.cpp index f3e44aa3d7..dc0ad1d9e8 100644 --- a/testfiles/src/attributes-test.cpp +++ b/testfiles/src/attributes-test.cpp @@ -432,6 +432,9 @@ std::vector getKnownAttrs() AttributeInfo("inkscape:radius", true), AttributeInfo("inkscape:randomized", true), AttributeInfo("inkscape:rounded", true), + AttributeInfo("inkscape:snap-alignment", true), + AttributeInfo("inkscape:snap-alignment-self", true), + AttributeInfo("inkscape:snap-distribution", true), AttributeInfo("inkscape:snap-bbox", true), AttributeInfo("inkscape:snap-bbox-edge-midpoints", true), AttributeInfo("inkscape:snap-bbox-midpoints", true), @@ -511,6 +514,8 @@ std::vector getKnownAttrs() AttributeInfo("gridtolerance", true), AttributeInfo("guidetolerance", true), AttributeInfo("objecttolerance", true), + AttributeInfo("alignmenttolerance", true), + AttributeInfo("distributiontolerance", true), /* AttributeInfo("gridoriginx", true), AttributeInfo("gridoriginy", true), AttributeInfo("gridspacingx", true), -- GitLab From f97241ba6875537792b6039b69f6f8cf9da23d09 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Wed, 16 Jun 2021 11:23:47 +0530 Subject: [PATCH 37/66] use std::function in place of c-style function pointer --- src/distribution-snapper.cpp | 2 +- src/distribution-snapper.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/distribution-snapper.cpp b/src/distribution-snapper.cpp index 3239106bfd..f25039b309 100644 --- a/src/distribution-snapper.cpp +++ b/src/distribution-snapper.cpp @@ -91,7 +91,7 @@ bool Inkscape::DistributionSnapper::findSidewaysSnaps(Geom::Coord first_dist, std::vector &vec, Geom::Coord &dist, Geom::Coord tol, - Geom::Coord(*distance_func)(Geom::Rect const&, Geom::Rect const&), + std::function const & distance_func, int level) const { Geom::Rect curr_bbox = *it; diff --git a/src/distribution-snapper.h b/src/distribution-snapper.h index bd2d7afc74..7d8deb9d01 100644 --- a/src/distribution-snapper.h +++ b/src/distribution-snapper.h @@ -118,7 +118,7 @@ private: std::vector &vec, Geom::Coord &dist, Geom::Coord tol, - Geom::Coord(*distance_func)(Geom::Rect const&, Geom::Rect const&), + std::function const & distance_func, int level = 0) const; // distance functions for different orientations -- GitLab From 60e45bd35527ebbe328cc4331661b373a69d30cb Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Wed, 16 Jun 2021 13:33:04 +0530 Subject: [PATCH 38/66] fix distritribution snapping to ghost bounding boxes use curr_bbox to correct snapping of overlapping objects --- src/distribution-snapper.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/distribution-snapper.cpp b/src/distribution-snapper.cpp index f25039b309..61b8ccfe0e 100644 --- a/src/distribution-snapper.cpp +++ b/src/distribution-snapper.cpp @@ -100,20 +100,20 @@ bool Inkscape::DistributionSnapper::findSidewaysSnaps(Geom::Coord first_dist, return level != 0; // TODO: check if rect1.instersects(rect2) gives the same result at rect2.intersects(rect1) - while (it->intersects(*std::next(it)) || std::next(it)->intersects(*it)) { + while (std::next(it) != end && (it->intersects(*std::next(it)) || std::next(it)->intersects(*it))) { curr_bbox.unionWith(Geom::OptRect(*++it)); } - if (level == 0) { - vec.clear(); + vec.push_back(curr_bbox); - // just add the first point to the vector and return if there are no more + if (level == 0) { + // just add the first bbox to the vector and return if there are no more // objects this is used later to find in-between snaps - vec.push_back(curr_bbox); - if (std::next(it) == end) + if (it + 1 == end) { return false; + } - dist = distance_func(*it, *std::next(it)); + dist = distance_func(curr_bbox, *std::next(it)); if (abs(first_dist - dist) > tol) { return false; } @@ -121,10 +121,9 @@ bool Inkscape::DistributionSnapper::findSidewaysSnaps(Geom::Coord first_dist, return findSidewaysSnaps(first_dist, ++it, end, vec, dist, tol, distance_func, ++level); } - vec.push_back(curr_bbox); // TODO: investige how does this tollerance affect the number of equidistant // objects that are found? - if (abs(distance_func(*it, *std::next(it)) - dist) < 1e-5) { + if (abs(distance_func(curr_bbox, *std::next(it)) - dist) < 1e-5) { return findSidewaysSnaps(first_dist, ++it, end, vec, dist, tol, distance_func, ++level); } @@ -157,8 +156,8 @@ Inkscape::DistributionSnapper::~DistributionSnapper() void Inkscape::DistributionSnapper::_collectBBoxes(Geom::OptRect const &bbox_to_snap, bool const &first_point) const { - if (!first_point) - return; + //if (!first_point) + //return; _bboxes_right->clear(); _bboxes_left->clear(); -- GitLab From e6c0c228c280e47c51c7edc9e079f821587c5cec Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Wed, 16 Jun 2021 13:35:08 +0530 Subject: [PATCH 39/66] set unset value for 'snapindicatordistance' to true in SnapIndicator this should fix default false value on new install when preference is unset. The default value set in preferences is true and so it should be set to true in SnapIndicator also --- src/display/control/snap-indicator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index 9b9620a87a..5bcbb335a3 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -471,7 +471,7 @@ Geom::Coord get_x(Geom::Rect const &source, Geom::Rect const &target) void SnapIndicator::make_alignment_indicator(Geom::Point const &p1, Geom::Point const &p2, guint32 color, double fontsize, double scale) { Preferences *prefs = Preferences::get(); - bool show_distance = prefs->getBool("/options/snapindicatordistance/value", false); + bool show_distance = prefs->getBool("/options/snapindicatordistance/value", true); Inkscape::CanvasItemCurve *line; -- GitLab From e1be7f5abb2978e937c4b8b55d090587da0b8c16 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Fri, 18 Jun 2021 11:40:25 +0530 Subject: [PATCH 40/66] fix unit of distance was in px, now it uses mm --- src/display/control/snap-indicator.cpp | 27 +++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index 5bcbb335a3..8f7bda15e6 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -20,6 +20,7 @@ #include "desktop.h" #include "enums.h" #include "preferences.h" +#include "util/units.h" #include "canvas-item-ctrl.h" @@ -29,6 +30,8 @@ #include "ui/tools/measure-tool.h" +#define ALIGNMENT_GUIDE_MEASURE_OFFSET 15 + namespace Inkscape { namespace Display { @@ -477,10 +480,18 @@ void SnapIndicator::make_alignment_indicator(Geom::Point const &p1, Geom::Point if (show_distance) { auto dist = Geom::L2(p2 - p1); - double offset = 15/_desktop->current_zoom(); + double offset = ALIGNMENT_GUIDE_MEASURE_OFFSET/_desktop->current_zoom(); auto direction = Geom::unit_vector(p1 - p2); auto text_pos = (p1 + p2)/2; - Glib::ustring distance = std::to_string(int(scale * dist)); + + Glib::ustring unit_name = prefs->getString("/tools/measure/unit"); + if (!unit_name.compare("")) { + unit_name = DEFAULT_UNIT_NAME; + } + + dist = Inkscape::Util::Quantity::convert(dist, "px", unit_name); + + Glib::ustring distance = std::to_string(int(scale*dist)); auto text = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), text_pos, distance); text->set_fontsize(fontsize); @@ -606,6 +617,11 @@ void SnapIndicator::make_distribution_indicators(std::vector const & _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line2, 0)); if (show_distance) { + Glib::ustring unit_name = prefs->getString("/tools/measure/unit"); + if (!unit_name.compare("")) { + unit_name = DEFAULT_UNIT_NAME; + } + equal_dist = Inkscape::Util::Quantity::convert(equal_dist, "px", unit_name); Glib::ustring distance = std::to_string(int(scale * equal_dist)); auto text = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), text_pos, distance); text->set_fontsize(fontsize); @@ -678,7 +694,12 @@ void SnapIndicator::make_distribution_indicators(std::vector const & _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line1, 0)); if (show_distance) { - Glib::ustring distance = std::to_string(int(equal_dist * scale)); + Glib::ustring unit_name = prefs->getString("/tools/measure/unit"); + if (!unit_name.compare("")) { + unit_name = DEFAULT_UNIT_NAME; + } + equal_dist = Inkscape::Util::Quantity::convert(equal_dist, "px", unit_name); + Glib::ustring distance = std::to_string(int(scale * equal_dist)); auto text = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), text_pos, distance); text->set_fontsize(fontsize); text->set_fill(text_fill); -- GitLab From ffa925cba64500ea77d155818aaedc649e7cb08d Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Fri, 18 Jun 2021 12:13:21 +0530 Subject: [PATCH 41/66] use document display unit and Glib::ustring::format instead of std::tostring --- src/display/control/snap-indicator.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index 8f7bda15e6..a2697ea7c8 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -14,6 +14,7 @@ #include #include +#include #include "snap-indicator.h" @@ -21,6 +22,7 @@ #include "enums.h" #include "preferences.h" #include "util/units.h" +#include "document.h" #include "canvas-item-ctrl.h" @@ -484,14 +486,14 @@ void SnapIndicator::make_alignment_indicator(Geom::Point const &p1, Geom::Point auto direction = Geom::unit_vector(p1 - p2); auto text_pos = (p1 + p2)/2; - Glib::ustring unit_name = prefs->getString("/tools/measure/unit"); + Glib::ustring unit_name = _desktop->doc()->getDisplayUnit()->abbr.c_str(); if (!unit_name.compare("")) { unit_name = DEFAULT_UNIT_NAME; } dist = Inkscape::Util::Quantity::convert(dist, "px", unit_name); - Glib::ustring distance = std::to_string(int(scale*dist)); + Glib::ustring distance = Glib::ustring::format(std::fixed, std::setprecision(1), std::noshowpoint, scale*dist); auto text = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), text_pos, distance); text->set_fontsize(fontsize); @@ -617,12 +619,12 @@ void SnapIndicator::make_distribution_indicators(std::vector const & _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line2, 0)); if (show_distance) { - Glib::ustring unit_name = prefs->getString("/tools/measure/unit"); + Glib::ustring unit_name = _desktop->doc()->getDisplayUnit()->abbr.c_str(); if (!unit_name.compare("")) { unit_name = DEFAULT_UNIT_NAME; } equal_dist = Inkscape::Util::Quantity::convert(equal_dist, "px", unit_name); - Glib::ustring distance = std::to_string(int(scale * equal_dist)); + Glib::ustring distance = Glib::ustring::format(std::fixed, std::setprecision(1), std::noshowpoint, scale*equal_dist); auto text = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), text_pos, distance); text->set_fontsize(fontsize); text->set_fill(text_fill); @@ -694,12 +696,12 @@ void SnapIndicator::make_distribution_indicators(std::vector const & _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line1, 0)); if (show_distance) { - Glib::ustring unit_name = prefs->getString("/tools/measure/unit"); + Glib::ustring unit_name = _desktop->doc()->getDisplayUnit()->abbr.c_str(); if (!unit_name.compare("")) { unit_name = DEFAULT_UNIT_NAME; } equal_dist = Inkscape::Util::Quantity::convert(equal_dist, "px", unit_name); - Glib::ustring distance = std::to_string(int(scale * equal_dist)); + Glib::ustring distance = Glib::ustring::format(std::fixed, std::setprecision(1), std::noshowpoint, scale*equal_dist); auto text = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), text_pos, distance); text->set_fontsize(fontsize); text->set_fill(text_fill); -- GitLab From c99829a595b8ce4f3e9094a44e180091baa4de77 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Sat, 19 Jun 2021 17:51:16 +0530 Subject: [PATCH 42/66] similar interface for horizontal and vertical snap this makes it easier for snap-indicator class to draw the indicators as it just has to iterate through a vector of bboxes this needs to be extended for in between snaps as well --- src/display/control/snap-indicator.cpp | 126 ++++++------------------- src/distribution-snapper.cpp | 71 ++++++++++---- 2 files changed, 86 insertions(+), 111 deletions(-) diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index a2697ea7c8..8bc7df533d 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -453,10 +453,12 @@ Geom::Coord get_y(Geom::Rect const &source, Geom::Rect const &target) { Geom::Coord y; - if (source.midpoint().y() > target.midpoint().y()) + if (source.max().y() < target.midpoint().y()) + y = target.min().y(); + else if(source.min().y() > target.midpoint().y()) y = target.max().y(); else - y = target.min().y(); + y = target.midpoint().y(); return y; } @@ -465,10 +467,12 @@ Geom::Coord get_x(Geom::Rect const &source, Geom::Rect const &target) { Geom::Coord x; - if (source.midpoint().x() > target.midpoint().x()) + if (source.max().x() < target.midpoint().x()) + x = target.min().x(); + else if(source.min().x() > target.midpoint().x()) x = target.max().x(); else - x = target.min().x(); + x = target.midpoint().x(); return x; } @@ -564,6 +568,13 @@ void SnapIndicator::make_distribution_indicators(std::vector const & guint32 text_bg = 0xff5f1fff; //0x33337f7f Geom::Point text_pos; + Glib::ustring unit_name = _desktop->doc()->getDisplayUnit()->abbr.c_str(); + if (!unit_name.compare("")) { + unit_name = DEFAULT_UNIT_NAME; + } + equal_dist = Inkscape::Util::Quantity::convert(equal_dist, "px", unit_name); + Glib::ustring distance = Glib::ustring::format(std::fixed, std::setprecision(1), std::noshowpoint, scale*equal_dist); + switch (t) { case SNAPTARGET_DISTRIBUTION_Y: case SNAPTARGET_DISTRIBUTION_X: { @@ -619,12 +630,6 @@ void SnapIndicator::make_distribution_indicators(std::vector const & _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line2, 0)); if (show_distance) { - Glib::ustring unit_name = _desktop->doc()->getDisplayUnit()->abbr.c_str(); - if (!unit_name.compare("")) { - unit_name = DEFAULT_UNIT_NAME; - } - equal_dist = Inkscape::Util::Quantity::convert(equal_dist, "px", unit_name); - Glib::ustring distance = Glib::ustring::format(std::fixed, std::setprecision(1), std::noshowpoint, scale*equal_dist); auto text = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), text_pos, distance); text->set_fontsize(fontsize); text->set_fill(text_fill); @@ -641,103 +646,27 @@ void SnapIndicator::make_distribution_indicators(std::vector const & Geom::Coord x, y; Geom::Point p1, p2; Inkscape::CanvasItemCurve *point1, *point2; - switch (t) { - case SNAPTARGET_DISTRIBUTION_RIGHT: - y = get_y(source_bbox, bboxes.front()); - - p1 = Geom::Point(source_bbox.max().x(), y); - p2 = Geom::Point(bboxes.front().min().x(), y); - text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(0, -2*fontsize)); - - point1 = make_stub_line_v(p1); - point2 = make_stub_line_v(p2); - break; - - case SNAPTARGET_DISTRIBUTION_LEFT: - y = get_y(source_bbox, bboxes.front()); - - p1 = Geom::Point(source_bbox.min().x(), y); - p2 = Geom::Point(bboxes.front().max().x(), y); - text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(0, -2*fontsize)); - - point1 = make_stub_line_v(p1); - point2 = make_stub_line_v(p2); - break; - - case SNAPTARGET_DISTRIBUTION_UP: - x = get_x(source_bbox, bboxes.front()); - - p1 = Geom::Point(x, source_bbox.min().y()); - p2 = Geom::Point(x, bboxes.front().max().y()); - text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(-2*fontsize, 0)); - - point1 = make_stub_line_h(p1); - point2 = make_stub_line_h(p2); - break; - - case SNAPTARGET_DISTRIBUTION_DOWN: - x = get_x(source_bbox, bboxes.front()); - - p1 = Geom::Point(x, source_bbox.max().y()); - p2 = Geom::Point(x, bboxes.front().min().y()); - text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(-2*fontsize, 0)); - - point1 = make_stub_line_h(p1); - point2 = make_stub_line_h(p2); - break; - } - - _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point1, 0)); - _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point2, 0)); - - auto line1 = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p1, p2); - line1->set_stroke(color); - line1->set_width(2); - _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line1, 0)); - - if (show_distance) { - Glib::ustring unit_name = _desktop->doc()->getDisplayUnit()->abbr.c_str(); - if (!unit_name.compare("")) { - unit_name = DEFAULT_UNIT_NAME; - } - equal_dist = Inkscape::Util::Quantity::convert(equal_dist, "px", unit_name); - Glib::ustring distance = Glib::ustring::format(std::fixed, std::setprecision(1), std::noshowpoint, scale*equal_dist); - auto text = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), text_pos, distance); - text->set_fontsize(fontsize); - text->set_fill(text_fill); - text->set_background(text_bg); - _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(text, 0)); - } for (auto it = bboxes.begin(); it + 1 != bboxes.end(); it++) { switch (t) { case SNAPTARGET_DISTRIBUTION_RIGHT: + case SNAPTARGET_DISTRIBUTION_LEFT: + y = get_y(*it,*std::next(it)); p1 = Geom::Point(it->max().x(), y); p2 = Geom::Point(std::next(it)->min().x(), y); + text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(0, -2*fontsize)); point1 = make_stub_line_v(p1); point2 = make_stub_line_v(p2); - break; - case SNAPTARGET_DISTRIBUTION_LEFT: - p1 = Geom::Point(it->min().x(), y); - p2 = Geom::Point(std::next(it)->max().x(), y); - - point1 = make_stub_line_v(p1); - point2 = make_stub_line_v(p2); - break; - - case SNAPTARGET_DISTRIBUTION_UP: - p1 = Geom::Point(x, it->min().y()); - p2 = Geom::Point(x, std::next(it)->max().y()); - - point1 = make_stub_line_h(p1); - point2 = make_stub_line_h(p2); break; case SNAPTARGET_DISTRIBUTION_DOWN: + case SNAPTARGET_DISTRIBUTION_UP: + x = get_x(*it,*std::next(it)); p1 = Geom::Point(x, it->max().y()); p2 = Geom::Point(x, std::next(it)->min().y()); + text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(-2*fontsize, 0)); point1 = make_stub_line_h(p1); point2 = make_stub_line_h(p2); @@ -747,14 +676,21 @@ void SnapIndicator::make_distribution_indicators(std::vector const & _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point1, 0)); _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point2, 0)); - line1 = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p1, p2); + auto line1 = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p1, p2); line1->set_stroke(color); line1->set_width(2); _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line1, 0)); + + if (show_distance) { + auto text = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), text_pos, distance); + text->set_fontsize(fontsize); + text->set_fill(text_fill); + text->set_background(text_bg); + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(text, 0)); + } } break; - } - + } } } diff --git a/src/distribution-snapper.cpp b/src/distribution-snapper.cpp index 61b8ccfe0e..3f88d730db 100644 --- a/src/distribution-snapper.cpp +++ b/src/distribution-snapper.cpp @@ -122,8 +122,8 @@ bool Inkscape::DistributionSnapper::findSidewaysSnaps(Geom::Coord first_dist, } // TODO: investige how does this tollerance affect the number of equidistant - // objects that are found? - if (abs(distance_func(curr_bbox, *std::next(it)) - dist) < 1e-5) { + // objects that are found? also does multiplying with level help (error propagation) + if (abs(distance_func(curr_bbox, *std::next(it)) - dist) < level*1e-5) { return findSidewaysSnaps(first_dist, ++it, end, vec, dist, tol, distance_func, ++level); } @@ -242,6 +242,10 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is Geom::Coord equal_dist; + SnappedPoint sr, sl, sx, su, sd, sy; + Geom::Coord dist_r, dist_l, dist_u, dist_d; + bool snap_r = false, snap_l = false, snap_u = false, snap_d = false, snap_x = false, snap_y = false; + // right snaps std::vector vecRight; if (consider_x && _bboxes_right->size() > 0) { @@ -260,11 +264,13 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); Geom::Rect bbox = *bbox_to_snap * translation; + vecRight.insert(vecRight.begin(), bbox); _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - auto s = SnappedPoint(target, vecRight, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_RIGHT, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - isr.points.push_back(s); + dist_r = abs(offset); + sr = SnappedPoint(target, vecRight, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_RIGHT, dist_r, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + snap_r = true; } } @@ -287,11 +293,14 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is // translate the source bbox to the snap position Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); Geom::Rect bbox = *bbox_to_snap * translation; + std::reverse(vecLeft.begin(), vecLeft.end()); + vecLeft.push_back(bbox); _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - auto s = SnappedPoint(target, vecLeft, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_LEFT, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - isr.points.push_back(s); + dist_l = abs(offset); + sl = SnappedPoint(target, vecLeft, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_LEFT, dist_l, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + snap_l = true; } } @@ -314,11 +323,14 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is // translate the source bbox to the snap position Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); Geom::Rect bbox = *bbox_to_snap * translation; + std::reverse(vecUp.begin(), vecUp.end()); + vecUp.push_back(bbox); _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - auto s = SnappedPoint(target, vecUp, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_UP, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - isr.points.push_back(s); + dist_u = abs(offset); + su = SnappedPoint(target, vecUp, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_UP, dist_u, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + snap_u = true; } } @@ -341,11 +353,13 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is // translate the source bbox to the snap position Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); Geom::Rect bbox = *bbox_to_snap * translation; + vecDown.insert(vecDown.begin(), bbox); _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - auto s = SnappedPoint(target, vecDown, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_DOWN, abs(offset), getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - isr.points.push_back(s); + dist_d = abs(offset); + sd = SnappedPoint(target, vecDown, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_DOWN, dist_d, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + snap_d = true; } } @@ -371,7 +385,7 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is auto x = Geom::Point((pointR + pointL)/2).x(); offset = abs(x - bbox_to_snap->midpoint().x()); if (consider_x && offset < getSnapperTolerance()) { - std::vector bboxes = {*_bboxes_left->begin(), *_bboxes_right->begin()}; + std::vector bboxes = {vecLeft.front(), vecRight.front()}; Geom::Point target = Geom::Point(x, bbox_to_snap->midpoint().y()); // translate the source bbox to the snap position Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); @@ -380,8 +394,8 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); equal_dist = bbox.min().x() - pointL.x(); - auto s = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_X, offset, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - isr.points.push_back(s); + sx = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_X, offset, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + snap_x = true; } // vertically in between @@ -389,7 +403,7 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is equal_dist = bbox_to_snap->min().y() - pointU.y(); offset = abs(y - bbox_to_snap->midpoint().y()); if (consider_y && offset < getSnapperTolerance()) { - std::vector bboxes = {*_bboxes_up->begin(), *_bboxes_down->begin()}; + std::vector bboxes = {vecUp.front(), vecDown.front()}; Geom::Point target = Geom::Point(bbox_to_snap->midpoint().x(), y); // translate the source bbox to the snap position Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); @@ -398,10 +412,35 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); equal_dist = bbox.min().y() - pointU.y(); - auto s = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_Y, offset, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - isr.points.push_back(s); + sy = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_Y, offset, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + snap_y = true; + } + + if (snap_x) { + isr.points.push_back(sx); + std::cout<<"center"< Date: Sun, 20 Jun 2021 16:36:59 +0530 Subject: [PATCH 43/66] Improved Distribution snapping Distribution snapping is now only classified in two directions X and Y this simplifies drawing snap indicators. This commit also introduces two way snaps i.e. snaps can happen in both right and left direction at the same time. Like wise for vertical direction Fixme: sometimes there are problems with precision and the snap is not detected --- src/display/control/snap-indicator.cpp | 65 +------ src/distribution-snapper.cpp | 244 ++++++++++++++++--------- 2 files changed, 157 insertions(+), 152 deletions(-) diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index 8bc7df533d..869d64f754 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -577,68 +577,7 @@ void SnapIndicator::make_distribution_indicators(std::vector const & switch (t) { case SNAPTARGET_DISTRIBUTION_Y: - case SNAPTARGET_DISTRIBUTION_X: { - Geom::Point p1, p2, p3, p4; - Inkscape::CanvasItemCurve *point1, *point2, *point3, *point4; - switch (t) { - case SNAPTARGET_DISTRIBUTION_X: { - Geom::Coord y = get_y(source_bbox, bboxes.front()); - - p1 = Geom::Point(bboxes.front().max().x(), y); - p2 = Geom::Point(source_bbox.min().x(), y); - p3 = Geom::Point(source_bbox.max().x(), y); - p4 = Geom::Point(bboxes.back().min().x(), y); - text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(0, -2*fontsize)); - - point1 = make_stub_line_v(p1); - point2 = make_stub_line_v(p2); - point3 = make_stub_line_v(p3); - point4 = make_stub_line_v(p4); - break; - } - - case SNAPTARGET_DISTRIBUTION_Y: { - Geom::Coord x = get_x(source_bbox, bboxes.front()); - - p1 = Geom::Point(x, bboxes.front().max().y()); - p2 = Geom::Point(x, source_bbox.min().y()); - p3 = Geom::Point(x, source_bbox.max().y()); - p4 = Geom::Point(x, bboxes.back().min().y()); - text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(-2*fontsize, 0)); - - point1 = make_stub_line_h(p1); - point2 = make_stub_line_h(p2); - point3 = make_stub_line_h(p3); - point4 = make_stub_line_h(p4); - break; - } - } - - _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point1, 0)); - _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point2, 0)); - _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point3, 0)); - _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point4, 0)); - - auto line = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p1, p2); - line->set_stroke(color); - line->set_width(2); - _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line, 0)); - - auto line2 = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p3, p4); - line2->set_stroke(color); - line2->set_width(2); - _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line2, 0)); - - if (show_distance) { - auto text = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), text_pos, distance); - text->set_fontsize(fontsize); - text->set_fill(text_fill); - text->set_background(text_bg); - _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(text, 0)); - } - break; - } - + case SNAPTARGET_DISTRIBUTION_X: case SNAPTARGET_DISTRIBUTION_RIGHT: case SNAPTARGET_DISTRIBUTION_LEFT: case SNAPTARGET_DISTRIBUTION_UP: @@ -651,6 +590,7 @@ void SnapIndicator::make_distribution_indicators(std::vector const & switch (t) { case SNAPTARGET_DISTRIBUTION_RIGHT: case SNAPTARGET_DISTRIBUTION_LEFT: + case SNAPTARGET_DISTRIBUTION_X: y = get_y(*it,*std::next(it)); p1 = Geom::Point(it->max().x(), y); p2 = Geom::Point(std::next(it)->min().x(), y); @@ -663,6 +603,7 @@ void SnapIndicator::make_distribution_indicators(std::vector const & case SNAPTARGET_DISTRIBUTION_DOWN: case SNAPTARGET_DISTRIBUTION_UP: + case SNAPTARGET_DISTRIBUTION_Y: x = get_x(*it,*std::next(it)); p1 = Geom::Point(x, it->max().y()); p2 = Geom::Point(x, std::next(it)->min().y()); diff --git a/src/distribution-snapper.cpp b/src/distribution-snapper.cpp index 3f88d730db..e0b4eb8ea2 100644 --- a/src/distribution-snapper.cpp +++ b/src/distribution-snapper.cpp @@ -243,11 +243,14 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is Geom::Coord equal_dist; SnappedPoint sr, sl, sx, su, sd, sy; - Geom::Coord dist_r, dist_l, dist_u, dist_d; - bool snap_r = false, snap_l = false, snap_u = false, snap_d = false, snap_x = false, snap_y = false; + Geom::Coord dist_x, dist_y; + bool snap_x = false, snap_y = false; - // right snaps + // 1. look right + // if there is a snap then add right bboxes and look left, if there is a snap to the left then + // add those bboxes too std::vector vecRight; + std::vector vecLeft; if (consider_x && _bboxes_right->size() > 0) { auto first_dist = distRight(*bbox_to_snap, _bboxes_right->front()); @@ -265,20 +268,44 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); Geom::Rect bbox = *bbox_to_snap * translation; vecRight.insert(vecRight.begin(), bbox); - + _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - dist_r = abs(offset); - sr = SnappedPoint(target, vecRight, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_RIGHT, dist_r, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - snap_r = true; + if (_bboxes_left->size() > 0) { + first_dist = distLeft(bbox, _bboxes_left->front()); + Geom::Coord left_dist; + vecLeft.clear(); + if (findSidewaysSnaps(first_dist, + _bboxes_left->begin(), + _bboxes_left->end(), + vecLeft, + left_dist, + getSnapperTolerance(), + &DistributionSnapper::distLeft)) { + + if (abs(left_dist - equal_dist) < 1e-5){ + std::reverse(vecLeft.begin(), vecLeft.end()); + vecRight.insert(vecRight.begin(), vecLeft.begin(), vecLeft.end()); + } + + } else if (abs(first_dist - equal_dist) < 1e-5) { + vecRight.insert(vecRight.begin(), vecLeft.front()); + } + } + + dist_x = abs(offset); + sx = SnappedPoint(target, vecRight, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_RIGHT, dist_x, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + snap_x = true; } } - // left snaps - std::vector vecLeft; - if (consider_x && _bboxes_left->size() > 0) { + // 2. if no snap to right, look left + // if there is a snap then add left bboxes and right left, if there is a snap to the right then + // add those bboxes too + if (consider_x && !snap_x && _bboxes_left->size() > 0) { auto first_dist = distLeft(*bbox_to_snap, _bboxes_left->front()); + vecLeft.clear(); if (findSidewaysSnaps(first_dist, _bboxes_left->begin(), _bboxes_left->end(), @@ -298,14 +325,57 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - dist_l = abs(offset); - sl = SnappedPoint(target, vecLeft, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_LEFT, dist_l, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - snap_l = true; + if (_bboxes_right->size() > 0) { + first_dist = distRight(bbox, _bboxes_right->front()); + Geom::Coord right_dist; + vecRight.clear(); + if (findSidewaysSnaps(first_dist, + _bboxes_right->begin(), + _bboxes_right->end(), + vecRight, + right_dist, + getSnapperTolerance(), + &DistributionSnapper::distRight)) { + + if (abs(right_dist - equal_dist) < 1e-5){ + vecLeft.insert(vecLeft.end(), vecRight.begin(), vecRight.end()); + } + + } else if (abs(first_dist - equal_dist) < 1e-5) { + vecLeft.push_back(vecRight.front()); + } + } + + dist_x = abs(offset); + sx = SnappedPoint(target, vecLeft, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_LEFT, dist_x, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + snap_x = true; } } - // up snaps + // 3. if no snap to right or left just add the center snap + if (consider_x && !snap_x && vecRight.size() > 0 && vecLeft.size() > 0) { + auto x = Geom::Point((vecRight.front().min() + vecLeft.front().max())/2).x(); + offset = abs(x - bbox_to_snap->midpoint().x()); + if (offset < getSnapperTolerance()) { + Geom::Point target = Geom::Point(x, bbox_to_snap->midpoint().y()); + // translate the source bbox to the snap position + Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); + Geom::Rect bbox = *bbox_to_snap * translation; + std::vector bboxes = {vecLeft.front(), bbox, vecRight.front()}; + + _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); + + equal_dist = bbox.min().x() - vecLeft.front().max().x(); + sx = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_X, offset, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + snap_x = true; + } + } + + // 1. look Up + // if there is a snap then add top bboxes and look down, if there is a snap at the bottom then + // add those bboxes too std::vector vecUp; + std::vector vecDown; if (consider_y && _bboxes_up->size() > 0) { auto first_dist = distUp(*bbox_to_snap, _bboxes_up->front()); @@ -328,17 +398,40 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - dist_u = abs(offset); - su = SnappedPoint(target, vecUp, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_UP, dist_u, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - snap_u = true; + if (_bboxes_down->size() > 0) { + first_dist = distDown(bbox, _bboxes_down->front()); + Geom::Coord down_dist; + vecDown.clear(); + if (findSidewaysSnaps(first_dist, + _bboxes_down->begin(), + _bboxes_down->end(), + vecDown, + down_dist, + getSnapperTolerance(), + &DistributionSnapper::distDown)) { + + if (abs(down_dist - equal_dist) < 1e-4){ + vecUp.insert(vecUp.end(), vecDown.begin(), vecDown.end()); + } + + } else if (abs(first_dist - equal_dist) < 1e-4) { + vecUp.insert(vecUp.end(), vecDown.front()); + } + } + + dist_y = abs(offset); + sy = SnappedPoint(target, vecUp, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_UP, dist_y, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + snap_y = true; } } - // down snaps - std::vector vecDown; - if (consider_y && _bboxes_down->size() > 0) { + // 2. if no snaps on top, look Down + // if there is a snap then add bottom bboxes and look Up, if there is a snap above then + // add those bboxes too + if (consider_y && !snap_y && _bboxes_down->size() > 0) { auto first_dist = distDown(*bbox_to_snap, _bboxes_down->front()); + vecDown.clear(); if (findSidewaysSnaps(first_dist, _bboxes_down->begin(), _bboxes_down->end(), @@ -357,90 +450,61 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - dist_d = abs(offset); - sd = SnappedPoint(target, vecDown, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_DOWN, dist_d, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - snap_d = true; + if (_bboxes_up->size() > 0) { + first_dist = distUp(bbox, _bboxes_up->front()); + Geom::Coord up_dist; + vecUp.clear(); + + if (findSidewaysSnaps(first_dist, + _bboxes_up->begin(), + _bboxes_up->end(), + vecUp, + up_dist, + getSnapperTolerance(), + &DistributionSnapper::distUp)) { + + if (abs(up_dist - equal_dist) < 1e-5){ + std::reverse(vecUp.begin(), vecUp.end()); + vecDown.insert(vecDown.begin(), vecUp.begin(), vecUp.end()); + } + } else if (abs(first_dist - equal_dist) < 1e-5) { + vecDown.insert(vecDown.begin(), vecUp.front()); + } + } + + dist_y = abs(offset); + sy = SnappedPoint(target, vecDown, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_DOWN, dist_y, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + snap_y = true; } } + + // 3. if no snap to right or left just add the center snap + if (consider_y && !snap_y && vecUp.size() > 0 && vecDown.size() > 0) { + auto y = Geom::Point((vecUp.front().max() + vecDown.front().min())/2).y(); + offset = abs(y - bbox_to_snap->midpoint().y()); + if (consider_y && offset < getSnapperTolerance()) { + Geom::Point target = Geom::Point(bbox_to_snap->midpoint().x(), y); + // translate the source bbox to the snap position + Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); + Geom::Rect bbox = *bbox_to_snap * translation; + std::vector bboxes = {vecUp.front(), bbox, vecDown.front()}; - // in between snap - Geom::Point pointR = Geom::Point(Geom::infinity(), Geom::infinity()); - if (vecRight.size() > 0) - pointR = vecRight.front().min(); - - Geom::Point pointL = Geom::Point(Geom::infinity(), Geom::infinity()); - if (vecLeft.size() > 0) - pointL = vecLeft.front().max(); - - Geom::Point pointU = Geom::Point(Geom::infinity(), Geom::infinity()); - if (vecUp.size() > 0) - pointU = vecUp.front().max(); - - Geom::Point pointD = Geom::Point(Geom::infinity(), Geom::infinity()); - if (vecDown.size() > 0) - pointD = vecDown.front().min(); - - - // horizontally in between - auto x = Geom::Point((pointR + pointL)/2).x(); - offset = abs(x - bbox_to_snap->midpoint().x()); - if (consider_x && offset < getSnapperTolerance()) { - std::vector bboxes = {vecLeft.front(), vecRight.front()}; - Geom::Point target = Geom::Point(x, bbox_to_snap->midpoint().y()); - // translate the source bbox to the snap position - Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); - Geom::Rect bbox = *bbox_to_snap * translation; - - _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - - equal_dist = bbox.min().x() - pointL.x(); - sx = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_X, offset, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - snap_x = true; - } + _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - // vertically in between - auto y = Geom::Point((pointU + pointD)/2).y(); - equal_dist = bbox_to_snap->min().y() - pointU.y(); - offset = abs(y - bbox_to_snap->midpoint().y()); - if (consider_y && offset < getSnapperTolerance()) { - std::vector bboxes = {vecUp.front(), vecDown.front()}; - Geom::Point target = Geom::Point(bbox_to_snap->midpoint().x(), y); - // translate the source bbox to the snap position - Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); - Geom::Rect bbox = *bbox_to_snap * translation; - - _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - - equal_dist = bbox.min().y() - pointU.y(); - sy = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_Y, offset, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - snap_y = true; + equal_dist = bbox.min().y() - vecUp.front().max().y(); + sy = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_Y, offset, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + snap_y = true; + } } if (snap_x) { isr.points.push_back(sx); - std::cout<<"center"< Date: Mon, 21 Jun 2021 17:41:52 +0530 Subject: [PATCH 44/66] Bidirectional distribution snaps --- src/alignment-snapper.cpp | 10 ++-- src/display/control/snap-indicator.cpp | 80 ++++++++++++++++++++++---- src/display/control/snap-indicator.h | 2 +- src/distribution-snapper.cpp | 13 +++++ src/snap-enums.h | 1 + src/snapped-point.cpp | 37 ++++++++---- src/snapped-point.h | 8 ++- 7 files changed, 122 insertions(+), 29 deletions(-) diff --git a/src/alignment-snapper.cpp b/src/alignment-snapper.cpp index a36443822e..130d320f8e 100644 --- a/src/alignment-snapper.cpp +++ b/src/alignment-snapper.cpp @@ -126,14 +126,14 @@ void Inkscape::AlignmentSnapper::_snapBBoxPoints(IntermSnapResults &isr, //bool strict_snapping = _snapmanager->snapprefs.getStrictSnapping(); for (const auto & k : *_points_to_snap_to) { - // TODO: add strict snpping checks from ObjectSnapper::_allowSourceToSnapToTarget(...) + // TODO: add strict snapping checks from ObjectSnapper::_allowSourceToSnapToTarget(...) if (true) { Geom::Point target_pt = k.getPoint(); - // (unconstrained) distace from HORIZONTAL guide + // (unconstrained) distance from HORIZONTAL guide Geom::Point point_on_x(p.getPoint().x(), target_pt.y()); Geom::Coord distX = Geom::L2(point_on_x - p.getPoint()); - // (unconstrained) distace from VERTICAL guide + // (unconstrained) distance from VERTICAL guide Geom::Point point_on_y(target_pt.x(), p.getPoint().y()); Geom::Coord distY = Geom::L2(point_on_y - p.getPoint()); @@ -145,7 +145,7 @@ void Inkscape::AlignmentSnapper::_snapBBoxPoints(IntermSnapResults &isr, } bool is_target_node = k.getTargetType() & SNAPTARGET_NODE_CATEGORY; - if (consider_x && distX < getSnapperTolerance() && Geom::L2(target_pt - point_on_x) < sx.getDistanceToAignTarget()) { + if (consider_x && distX < getSnapperTolerance() && Geom::L2(target_pt - point_on_x) < sx.getDistanceToAlignTarget()) { sx = SnappedPoint(point_on_x, k.getPoint(), source2alignment(p.getSourceType()), @@ -160,7 +160,7 @@ void Inkscape::AlignmentSnapper::_snapBBoxPoints(IntermSnapResults &isr, success_x = true; } - if (consider_y && distY < getSnapperTolerance() && Geom::L2(target_pt - point_on_y) < sy.getDistanceToAignTarget()) { + if (consider_y && distY < getSnapperTolerance() && Geom::L2(target_pt - point_on_y) < sy.getDistanceToAlignTarget()) { sy = SnappedPoint(point_on_y, k.getPoint(), source2alignment(p.getSourceType()), diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index 869d64f754..70afc90678 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -270,7 +270,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap double fontsize = prefs->getDouble("/tools/measure/fontsize", 10.0); if (is_distribution) { - make_distribution_indicators(p.getBBoxes(), *p.getSourceBBox(), p.getDistributionDistance(), p.getTarget(), fontsize, scale); + make_distribution_indicators(p, fontsize, scale); } if (is_alignment) { @@ -553,10 +553,7 @@ Inkscape::CanvasItemCurve* SnapIndicator::make_stub_line_h(Geom::Point const & p return line; } -void SnapIndicator::make_distribution_indicators(std::vector const &bboxes, - Geom::Rect const &source_bbox, - Geom::Coord equal_dist, - SnapTargetType t, +void SnapIndicator::make_distribution_indicators(SnappedPoint const &p, double fontsize, double scale) { @@ -572,10 +569,10 @@ void SnapIndicator::make_distribution_indicators(std::vector const & if (!unit_name.compare("")) { unit_name = DEFAULT_UNIT_NAME; } - equal_dist = Inkscape::Util::Quantity::convert(equal_dist, "px", unit_name); + auto equal_dist = Inkscape::Util::Quantity::convert(p.getDistributionDistance(), "px", unit_name); Glib::ustring distance = Glib::ustring::format(std::fixed, std::setprecision(1), std::noshowpoint, scale*equal_dist); - switch (t) { + switch (p.getTarget()) { case SNAPTARGET_DISTRIBUTION_Y: case SNAPTARGET_DISTRIBUTION_X: case SNAPTARGET_DISTRIBUTION_RIGHT: @@ -586,8 +583,8 @@ void SnapIndicator::make_distribution_indicators(std::vector const & Geom::Point p1, p2; Inkscape::CanvasItemCurve *point1, *point2; - for (auto it = bboxes.begin(); it + 1 != bboxes.end(); it++) { - switch (t) { + for (auto it = p.getBBoxes().begin(); it + 1 != p.getBBoxes().end(); it++) { + switch (p.getTarget()) { case SNAPTARGET_DISTRIBUTION_RIGHT: case SNAPTARGET_DISTRIBUTION_LEFT: case SNAPTARGET_DISTRIBUTION_X: @@ -598,7 +595,6 @@ void SnapIndicator::make_distribution_indicators(std::vector const & point1 = make_stub_line_v(p1); point2 = make_stub_line_v(p2); - break; case SNAPTARGET_DISTRIBUTION_DOWN: @@ -630,8 +626,70 @@ void SnapIndicator::make_distribution_indicators(std::vector const & _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(text, 0)); } } + break; + } + case SNAPTARGET_DISTRIBUTION_XY: { + Geom::Coord x, y; + Geom::Point p1, p2; + Inkscape::CanvasItemCurve *point1, *point2; + + auto equal_dist2 = Inkscape::Util::Quantity::convert(p.getDistributionDistance2(), "px", unit_name); + Glib::ustring distance2 = Glib::ustring::format(std::fixed, std::setprecision(1), std::noshowpoint, scale*equal_dist2); + + for (auto it = p.getBBoxes().begin(); it + 1 != p.getBBoxes().end(); it++) { + y = get_y(*it,*std::next(it)); + p1 = Geom::Point(it->max().x(), y); + p2 = Geom::Point(std::next(it)->min().x(), y); + text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(0, -2*fontsize)); + + point1 = make_stub_line_v(p1); + point2 = make_stub_line_v(p2); + + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point1, 0)); + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point2, 0)); + + auto line1 = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p1, p2); + line1->set_stroke(color); + line1->set_width(2); + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line1, 0)); + + if (show_distance) { + auto text = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), text_pos, distance); + text->set_fontsize(fontsize); + text->set_fill(text_fill); + text->set_background(text_bg); + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(text, 0)); + } + } + + for (auto it = p.getBBoxes2().begin(); it + 1 != p.getBBoxes2().end(); it++) { + x = get_x(*it,*std::next(it)); + p1 = Geom::Point(x, it->max().y()); + p2 = Geom::Point(x, std::next(it)->min().y()); + text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(-2*fontsize, 0)); + + point1 = make_stub_line_h(p1); + point2 = make_stub_line_h(p2); + + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point1, 0)); + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(point2, 0)); + + auto line1 = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p1, p2); + line1->set_stroke(color); + line1->set_width(2); + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line1, 0)); + + if (show_distance) { + auto text = new Inkscape::CanvasItemText(_desktop->getCanvasTemp(), text_pos, distance2); + text->set_fontsize(fontsize); + text->set_fill(text_fill); + text->set_background(text_bg); + _distribution_snap_indicators.push_back(_desktop->add_temporary_canvasitem(text, 0)); + } + } + break; - } + } } } diff --git a/src/display/control/snap-indicator.h b/src/display/control/snap-indicator.h index b4be643172..ec12c1ce62 100644 --- a/src/display/control/snap-indicator.h +++ b/src/display/control/snap-indicator.h @@ -59,7 +59,7 @@ private: SnapIndicator(const SnapIndicator&) = delete; SnapIndicator& operator=(const SnapIndicator&) = delete; - void make_distribution_indicators(std::vector const &bboxes, Geom::Rect const &source_bbox, Geom::Coord equal_dist, SnapTargetType t, double fontsize, double scale); + void make_distribution_indicators(SnappedPoint const &p, double fontsize, double scale); void make_alignment_indicator(Geom::Point const &p1, Geom::Point const &p2, guint32 color, double fontsize, double scale); guint32 get_guide_color(SnapTargetType t); Inkscape::CanvasItemCurve* make_stub_line_h(Geom::Point const &p); diff --git a/src/distribution-snapper.cpp b/src/distribution-snapper.cpp index e0b4eb8ea2..13f56738d8 100644 --- a/src/distribution-snapper.cpp +++ b/src/distribution-snapper.cpp @@ -497,6 +497,19 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is } } + if (snap_x && snap_y) { + Geom::Point target = Geom::Point(sx.getPoint().x(), sy.getPoint().y()); + Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); + Geom::Rect bbox = *bbox_to_snap * translation; + std::vector bboxes_x = sx.getBBoxes(); + std::vector bboxes_y = sy.getBBoxes(); + + _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); + auto si = SnappedPoint(target, bboxes_x, bboxes_y, bbox, sx.getDistributionDistance(), sy.getDistributionDistance(), p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_XY, offset, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + isr.points.push_back(si); + return; + } + if (snap_x) { isr.points.push_back(sx); } diff --git a/src/snap-enums.h b/src/snap-enums.h index e69875d748..199fc49186 100644 --- a/src/snap-enums.h +++ b/src/snap-enums.h @@ -128,6 +128,7 @@ enum SnapTargetType { SNAPTARGET_DISTRIBUTION_LEFT, SNAPTARGET_DISTRIBUTION_UP, SNAPTARGET_DISTRIBUTION_DOWN, + SNAPTARGET_DISTRIBUTION_XY, //------------------------------------------------------------------- SNAPTARGET_MAX_ENUM_VALUE diff --git a/src/snapped-point.cpp b/src/snapped-point.cpp index 07c505f033..2e258d568c 100644 --- a/src/snapped-point.cpp +++ b/src/snapped-point.cpp @@ -88,8 +88,6 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, Geom::Point const &ap Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, std::vector const &bboxes, Geom::Rect const &source_bbox, Geom::Coord equal_dist, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained) : _point(p), - //_alignment_target(Geom::Point(0,0)), - //_alignment_target2(Geom::Point(0,0)), _equal_distance(equal_dist), _distribution_bboxes(std::move(bboxes)), _source_bbox(source_bbox), @@ -111,10 +109,33 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, std::vector const &bboxes, std::vector const &bboxes2, Geom::Rect const &source_bbox, Geom::Coord equal_dist, Geom::Coord equal_dist2, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained) : + _point(p), + _equal_distance(equal_dist), + _equal_distance2(equal_dist2), + _distribution_bboxes(std::move(bboxes)), + _distribution_bboxes2(std::move(bboxes2)), + _source_bbox(source_bbox), + _tangent(Geom::Point(0,0)), + _source(source), + _source_num(source_num), + _target(target), + _at_intersection (false), + _constrained_snap (constrained_snap), + _fully_constrained (fully_constrained), + _distance(d), + _tolerance(std::max(t,1.0)),// tolerance should never be smaller than 1 px, as it is used for normalization in isOtherSnapBetter. We don't want a division by zero. + _always_snap(a), + _second_distance (Geom::infinity()), + _second_tolerance (1), + _second_always_snap (false), + //_target_bbox(std::move(target_bbox)), + _pointer_distance (Geom::infinity()) +{ +} + Inkscape::SnappedPoint::SnappedPoint(Inkscape::SnapCandidatePoint const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained) : _point (p.getPoint()), - //_alignment_target(Geom::Point(0,0)), - //_alignment_target2(Geom::Point(0,0)), _equal_distance(Geom::infinity()), _tangent (Geom::Point(0,0)), _source (p.getSourceType()), @@ -136,8 +157,6 @@ Inkscape::SnappedPoint::SnappedPoint(Inkscape::SnapCandidatePoint const &p, Snap Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &at_intersection, bool const &constrained_snap, bool const &fully_constrained, Geom::Coord const &d2, Geom::Coord const &t2, bool const &a2) : _point(p), - //_alignment_target(Geom::Point(0,0)), - //_alignment_target2(Geom::Point(0,0)), _equal_distance(Geom::infinity()), _tangent (Geom::Point(0,0)), _source(source), @@ -161,8 +180,6 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const Inkscape::SnappedPoint::SnappedPoint(): _point (Geom::Point(0,0)), - //_alignment_target(Geom::Point(0,0)), - //_alignment_target2(Geom::Point(0,0)), _equal_distance(Geom::infinity()), _tangent (Geom::Point(0,0)), _source (SNAPSOURCE_UNDEFINED), @@ -184,8 +201,6 @@ Inkscape::SnappedPoint::SnappedPoint(): Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p): _point (p), - //_alignment_target(Geom::Point(0,0)), - //_alignment_target2(Geom::Point(0,0)), _equal_distance(Geom::infinity()), _tangent (Geom::Point(0,0)), _source (SNAPSOURCE_UNDEFINED), @@ -241,7 +256,7 @@ bool getClosestSP(std::list const &list, Inkscape::Snapp } else if (alignment) { if (!aligned_success || (*i).getSnapDistance() <= aligned.getSnapDistance()) { if ((*i).getSnapDistance() == aligned.getSnapDistance()) { - if ((*i).getDistanceToAignTarget() < aligned.getDistanceToAignTarget()) { + if ((*i).getDistanceToAlignTarget() < aligned.getDistanceToAlignTarget()) { aligned = *i; aligned_success = true; } diff --git a/src/snapped-point.h b/src/snapped-point.h index 5515c90dd3..20b37dbd35 100644 --- a/src/snapped-point.h +++ b/src/snapped-point.h @@ -36,6 +36,7 @@ public: SnappedPoint(Geom::Point const &p, Geom::Point const &ap, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained, Geom::OptRect target_bbox); SnappedPoint(Geom::Point const &p, Geom::Point const &ap, Geom::Point const &ap2, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained, Geom::OptRect target_bbox); SnappedPoint(Geom::Point const &p, std::vector const &bboxes, Geom::Rect const &source_bbox, Geom::Coord equal_dist, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained); + SnappedPoint(Geom::Point const &p, std::vector const &bboxes,std::vector const &bboxes2, Geom::Rect const &source_bbox, Geom::Coord equal_dist, Geom::Coord equal_dist2, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained); SnappedPoint(SnapCandidatePoint const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &constrained_snap, bool const &fully_constrained); ~SnappedPoint(); @@ -51,6 +52,7 @@ public: void setPointerDistance(Geom::Coord const d) {_pointer_distance = d;} std::vector const &getBBoxes() const {return _distribution_bboxes;} + std::vector const &getBBoxes2() const {return _distribution_bboxes2;} /* This is the preferred method to find out which point we have snapped * to, because it only returns a point if snapping has actually occurred @@ -93,7 +95,7 @@ public: return {}; } - Geom::Coord getDistanceToAignTarget() const + Geom::Coord getDistanceToAlignTarget() const { return _alignment_target.has_value() ? Geom::L2(_point - _alignment_target.value()) : Geom::infinity(); } @@ -113,6 +115,7 @@ public: Geom::OptRect const getTargetBBox() const {return _target_bbox;} Geom::OptRect const getSourceBBox() const {return _source_bbox;} Geom::Coord getDistributionDistance() const {return _equal_distance;} + Geom::Coord getDistributionDistance2() const {return _equal_distance2;} void setSource(SnapSourceType const source) {_source = source;} SnapSourceType getSource() const {return _source;} long getSourceNum() const {return _source_num;} @@ -142,6 +145,7 @@ protected: std::optional _alignment_target; // Target point for alignment snapping std::optional _alignment_target2; // Target point when alignment guides intersect std::vector _distribution_bboxes; // A list of bounding boxes in case of distribution snapping + std::vector _distribution_bboxes2; // Target point when there is a bidirectional distribution snap SnapSourceType _source; // Describes what snapped long _source_num; // Sequence number of the source point that snapped, if that point is part of a set of points. (starting at zero if we might have a set of points; -1 if we only have a single point) SnapTargetType _target; // Describes to what we've snapped to @@ -167,6 +171,8 @@ protected: Geom::Coord _second_tolerance; /* The equal distance between objects in screen pixels (depends on zoom) in case of distribution snapping*/ Geom::Coord _equal_distance; + /* The equal distance between objects in screen pixels (depends on zoom) in case of bidirectional distribution snapping*/ + Geom::Coord _equal_distance2; /* If true then "Always snap" is on */ bool _second_always_snap; /* The bounding box we've snapped to (when applicable); will be used by the snapindicator */ -- GitLab From 72031a5ab9c050902a9aae59687bd85a8a15fdc9 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Mon, 21 Jun 2021 20:02:54 +0530 Subject: [PATCH 45/66] convert switch-case in snap-indicator.cpp to unordered_map --- src/display/control/snap-indicator.cpp | 176 +------------------------ src/display/control/snap-indicator.h | 63 +++++++++ src/snap.cpp | 4 +- 3 files changed, 72 insertions(+), 171 deletions(-) diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index 70afc90678..2fa26b2279 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -86,176 +86,14 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap Glib::ustring source_name = _("UNDEFINED"); if (!is_alignment && !is_distribution) { - // TRANSLATORS: undefined target for snapping - switch (p.getTarget()) { - case SNAPTARGET_UNDEFINED: - target_name = _("UNDEFINED"); - g_warning("Snap target has not been specified"); - break; - case SNAPTARGET_GRID: - target_name = _("grid line"); - break; - case SNAPTARGET_GRID_INTERSECTION: - target_name = _("grid intersection"); - break; - case SNAPTARGET_GRID_PERPENDICULAR: - target_name = _("grid line (perpendicular)"); - break; - case SNAPTARGET_GUIDE: - target_name = _("guide"); - break; - case SNAPTARGET_GUIDE_INTERSECTION: - target_name = _("guide intersection"); - break; - case SNAPTARGET_GUIDE_ORIGIN: - target_name = _("guide origin"); - break; - case SNAPTARGET_GUIDE_PERPENDICULAR: - target_name = _("guide (perpendicular)"); - break; - case SNAPTARGET_GRID_GUIDE_INTERSECTION: - target_name = _("grid-guide intersection"); - break; - case SNAPTARGET_NODE_CUSP: - target_name = _("cusp node"); - break; - case SNAPTARGET_NODE_SMOOTH: - target_name = _("smooth node"); - break; - case SNAPTARGET_PATH: - target_name = _("path"); - break; - case SNAPTARGET_PATH_PERPENDICULAR: - target_name = _("path (perpendicular)"); - break; - case SNAPTARGET_PATH_TANGENTIAL: - target_name = _("path (tangential)"); - break; - case SNAPTARGET_PATH_INTERSECTION: - target_name = _("path intersection"); - break; - case SNAPTARGET_PATH_GUIDE_INTERSECTION: - target_name = _("guide-path intersection"); - break; - case SNAPTARGET_PATH_CLIP: - target_name = _("clip-path"); - break; - case SNAPTARGET_PATH_MASK: - target_name = _("mask-path"); - break; - case SNAPTARGET_BBOX_CORNER: - target_name = _("bounding box corner"); - break; - case SNAPTARGET_BBOX_EDGE: - target_name = _("bounding box side"); - break; - case SNAPTARGET_PAGE_BORDER: - target_name = _("page border"); - break; - case SNAPTARGET_LINE_MIDPOINT: - target_name = _("line midpoint"); - break; - case SNAPTARGET_OBJECT_MIDPOINT: - target_name = _("object midpoint"); - break; - case SNAPTARGET_ROTATION_CENTER: - target_name = _("object rotation center"); - break; - case SNAPTARGET_BBOX_EDGE_MIDPOINT: - target_name = _("bounding box side midpoint"); - break; - case SNAPTARGET_BBOX_MIDPOINT: - target_name = _("bounding box midpoint"); - break; - case SNAPTARGET_PAGE_CORNER: - target_name = _("page corner"); - break; - case SNAPTARGET_ELLIPSE_QUADRANT_POINT: - target_name = _("quadrant point"); - break; - case SNAPTARGET_RECT_CORNER: - case SNAPTARGET_IMG_CORNER: - target_name = _("corner"); - break; - case SNAPTARGET_TEXT_ANCHOR: - target_name = _("text anchor"); - break; - case SNAPTARGET_TEXT_BASELINE: - target_name = _("text baseline"); - break; - case SNAPTARGET_CONSTRAINED_ANGLE: - target_name = _("constrained angle"); - break; - case SNAPTARGET_CONSTRAINT: - target_name = _("constraint"); - break; - default: - g_warning("Snap target not in SnapTargetType enum"); - break; - } + if (target2string.find(p.getTarget()) == target2string.end()) + g_warning("Target type %i not present in target2string", p.getTarget()); - switch (p.getSource()) { - case SNAPSOURCE_UNDEFINED: - source_name = _("UNDEFINED"); - g_warning("Snap source has not been specified"); - break; - case SNAPSOURCE_BBOX_CORNER: - source_name = _("Bounding box corner"); - break; - case SNAPSOURCE_BBOX_MIDPOINT: - source_name = _("Bounding box midpoint"); - break; - case SNAPSOURCE_BBOX_EDGE_MIDPOINT: - source_name = _("Bounding box side midpoint"); - break; - case SNAPSOURCE_NODE_SMOOTH: - source_name = _("Smooth node"); - break; - case SNAPSOURCE_NODE_CUSP: - source_name = _("Cusp node"); - break; - case SNAPSOURCE_LINE_MIDPOINT: - source_name = _("Line midpoint"); - break; - case SNAPSOURCE_OBJECT_MIDPOINT: - source_name = _("Object midpoint"); - break; - case SNAPSOURCE_ROTATION_CENTER: - source_name = _("Object rotation center"); - break; - case SNAPSOURCE_NODE_HANDLE: - case SNAPSOURCE_OTHER_HANDLE: - source_name = _("Handle"); - break; - case SNAPSOURCE_PATH_INTERSECTION: - source_name = _("Path intersection"); - break; - case SNAPSOURCE_GUIDE: - source_name = _("Guide"); - break; - case SNAPSOURCE_GUIDE_ORIGIN: - source_name = _("Guide origin"); - break; - case SNAPSOURCE_CONVEX_HULL_CORNER: - source_name = _("Convex hull corner"); - break; - case SNAPSOURCE_ELLIPSE_QUADRANT_POINT: - source_name = _("Quadrant point"); - break; - case SNAPSOURCE_RECT_CORNER: - case SNAPSOURCE_IMG_CORNER: - source_name = _("Corner"); - break; - case SNAPSOURCE_TEXT_ANCHOR: - source_name = _("Text anchor"); - break; - case SNAPSOURCE_GRID_PITCH: - source_name = _("Multiple of grid spacing"); - break; - default: - g_warning("Snap source not in SnapSourceType enum"); - break; - } + if (source2string.find(p.getSource()) == source2string.end()) + g_warning("Source type %i not present in target2string", p.getSource()); + + target_name = target2string[p.getTarget()]; + source_name = source2string[p.getSource()]; } //std::cout << "Snapped " << source_name << " to " << target_name << std::endl; diff --git a/src/display/control/snap-indicator.h b/src/display/control/snap-indicator.h index ec12c1ce62..271c6a9cb2 100644 --- a/src/display/control/snap-indicator.h +++ b/src/display/control/snap-indicator.h @@ -17,10 +17,13 @@ * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ +#include "snap-enums.h" #include "snapped-point.h" #include "display/control/canvas-item-curve.h" #include +#include +#include class SPDesktop; @@ -64,6 +67,66 @@ private: guint32 get_guide_color(SnapTargetType t); Inkscape::CanvasItemCurve* make_stub_line_h(Geom::Point const &p); Inkscape::CanvasItemCurve* make_stub_line_v(Geom::Point const &p); + + std::unordered_map source2string = { + {SNAPSOURCE_UNDEFINED, _("UNDEFINED")}, + {SNAPSOURCE_BBOX_CORNER, _("Bounding box corner")}, + {SNAPSOURCE_BBOX_MIDPOINT, _("Bounding box midpoint")}, + {SNAPSOURCE_BBOX_EDGE_MIDPOINT, _("Bounding box side midpoint")}, + {SNAPSOURCE_NODE_SMOOTH, _("Smooth node")}, + {SNAPSOURCE_NODE_CUSP, _("Cusp node")}, + {SNAPSOURCE_LINE_MIDPOINT, _("Line midpoint")}, + {SNAPSOURCE_PATH_INTERSECTION, _("Path intersection")}, + {SNAPSOURCE_RECT_CORNER, _("Corner")}, + {SNAPSOURCE_CONVEX_HULL_CORNER, _("Convex hull corner")}, + {SNAPSOURCE_ELLIPSE_QUADRANT_POINT, _("Quadrant point")}, + {SNAPSOURCE_NODE_HANDLE, _("Handle")}, + {SNAPSOURCE_GUIDE, _("Guide")}, + {SNAPSOURCE_GUIDE_ORIGIN, _("Guide origin")}, + {SNAPSOURCE_ROTATION_CENTER, _("Object rotation center")}, + {SNAPSOURCE_OBJECT_MIDPOINT, _("Object midpoint")}, + {SNAPSOURCE_IMG_CORNER, _("Corner")}, + {SNAPSOURCE_TEXT_ANCHOR, _("Text anchor")}, + {SNAPSOURCE_OTHER_HANDLE, _("Handle")}, + {SNAPSOURCE_GRID_PITCH, _("Multiple of grid spacing")}, + }; + + std::unordered_map target2string = { + {SNAPTARGET_UNDEFINED, _("UNDEFINED")}, + {SNAPTARGET_BBOX_CORNER, _("bounding box corner")}, + {SNAPTARGET_BBOX_EDGE, _("bounding box side")}, + {SNAPTARGET_BBOX_EDGE_MIDPOINT, _("bounding box side midpoint")}, + {SNAPTARGET_BBOX_MIDPOINT, _("bounding box midpoint")}, + {SNAPTARGET_NODE_SMOOTH, _("smooth node")}, + {SNAPTARGET_NODE_CUSP, _("cusp node")}, + {SNAPTARGET_LINE_MIDPOINT, _("line midpoint")}, + {SNAPTARGET_PATH, _("path")}, + {SNAPTARGET_PATH_PERPENDICULAR, _("path (perpendicular)")}, + {SNAPTARGET_PATH_TANGENTIAL, _("path (tangential)")}, + {SNAPTARGET_PATH_INTERSECTION, _("path intersection")}, + {SNAPTARGET_PATH_GUIDE_INTERSECTION, _("guide-path intersection")}, + {SNAPTARGET_PATH_CLIP, _("clip-path")}, + {SNAPTARGET_PATH_MASK, _("mask-path")}, + {SNAPTARGET_ELLIPSE_QUADRANT_POINT, _("quadrant point")}, + {SNAPTARGET_RECT_CORNER, _("corner")}, + {SNAPTARGET_GRID, _("grid line")}, + {SNAPTARGET_GRID_INTERSECTION, _("grid intersection")}, + {SNAPTARGET_GRID_PERPENDICULAR, _("grid line (perpendicular)")}, + {SNAPTARGET_GUIDE, _("guide")}, + {SNAPTARGET_GUIDE_INTERSECTION, _("guide intersection")}, + {SNAPTARGET_GUIDE_ORIGIN, _("guide origin")}, + {SNAPTARGET_GUIDE_PERPENDICULAR, _("guide (perpendicular)")}, + {SNAPTARGET_GRID_GUIDE_INTERSECTION, _("grid-guide intersection")}, + {SNAPTARGET_PAGE_BORDER, _("page border")}, + {SNAPTARGET_PAGE_CORNER, _("page corner")}, + {SNAPTARGET_OBJECT_MIDPOINT, _("object midpoint")}, + {SNAPTARGET_IMG_CORNER, _("corner")}, + {SNAPTARGET_ROTATION_CENTER, _("object rotation center")}, + {SNAPTARGET_TEXT_ANCHOR, _("text anchor")}, + {SNAPTARGET_TEXT_BASELINE, _("text baseline")}, + {SNAPTARGET_CONSTRAINED_ANGLE, _("constrained angle")}, + {SNAPTARGET_CONSTRAINT, _("constraint")}, + }; }; } //namespace Display diff --git a/src/snap.cpp b/src/snap.cpp index 084e1aef40..13e8940a15 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -829,7 +829,8 @@ void SnapManager::_findCandidates(SPObject* parent, { SPDesktop const *dt = getDesktop(); if (dt == nullptr) { - g_warning("desktop == NULL, so we cannot snap; please inform the developers of this bug"); + g_error("desktop == NULL, so we cannot snap; please inform the developers of this bug"); + return; // Apparently the setup() method from the SnapManager class hasn't been called before trying to snap. } @@ -842,7 +843,6 @@ void SnapManager::_findCandidates(SPObject* parent, bbox_to_snap_incl.expandBy(object.getSnapperTolerance()); // see? for (auto& o: parent->children) { - g_assert(dt != nullptr); SPItem *item = dynamic_cast(&o); if (item && !(dt->itemIsHidden(item) && !clip_or_mask)) { // Fix LPE boolops selfsnaping -- GitLab From 9ccafb02a563550729e5837da956d04ce38960c3 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Tue, 22 Jun 2021 19:43:31 +0530 Subject: [PATCH 46/66] separate compare utility function --- src/distribution-snapper.cpp | 24 ++++++++++++++++-------- src/snapped-point.cpp | 2 ++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/distribution-snapper.cpp b/src/distribution-snapper.cpp index 13f56738d8..a991a0a42d 100644 --- a/src/distribution-snapper.cpp +++ b/src/distribution-snapper.cpp @@ -37,6 +37,14 @@ #include "style.h" #include "svg/svg.h" +#define DISTRIBUTION_SNAPPING_EPSILON 0.00005f + +static bool compare_double(double x, double y, double epsilon = DISTRIBUTION_SNAPPING_EPSILON){ + if(abs(x - y) < epsilon) + return true; + return false; +} + static int sortBoxesRight(Geom::Rect const &a, Geom::Rect const &b) { if (a.midpoint().x() < b.midpoint().x()) @@ -114,7 +122,7 @@ bool Inkscape::DistributionSnapper::findSidewaysSnaps(Geom::Coord first_dist, } dist = distance_func(curr_bbox, *std::next(it)); - if (abs(first_dist - dist) > tol) { + if (compare_double(first_dist, dist)) { return false; } @@ -123,7 +131,7 @@ bool Inkscape::DistributionSnapper::findSidewaysSnaps(Geom::Coord first_dist, // TODO: investige how does this tollerance affect the number of equidistant // objects that are found? also does multiplying with level help (error propagation) - if (abs(distance_func(curr_bbox, *std::next(it)) - dist) < level*1e-5) { + if (compare_double(distance_func(curr_bbox, *std::next(it)), dist), DISTRIBUTION_SNAPPING_EPSILON) { return findSidewaysSnaps(first_dist, ++it, end, vec, dist, tol, distance_func, ++level); } @@ -283,12 +291,12 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is getSnapperTolerance(), &DistributionSnapper::distLeft)) { - if (abs(left_dist - equal_dist) < 1e-5){ + if (compare_double(left_dist, equal_dist)){ std::reverse(vecLeft.begin(), vecLeft.end()); vecRight.insert(vecRight.begin(), vecLeft.begin(), vecLeft.end()); } - } else if (abs(first_dist - equal_dist) < 1e-5) { + } else if (compare_double(first_dist, equal_dist)) { vecRight.insert(vecRight.begin(), vecLeft.front()); } } @@ -337,11 +345,11 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is getSnapperTolerance(), &DistributionSnapper::distRight)) { - if (abs(right_dist - equal_dist) < 1e-5){ + if (compare_double(right_dist, equal_dist)){ vecLeft.insert(vecLeft.end(), vecRight.begin(), vecRight.end()); } - } else if (abs(first_dist - equal_dist) < 1e-5) { + } else if (compare_double(first_dist, equal_dist)) { vecLeft.push_back(vecRight.front()); } } @@ -463,11 +471,11 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is getSnapperTolerance(), &DistributionSnapper::distUp)) { - if (abs(up_dist - equal_dist) < 1e-5){ + if (compare_double(up_dist, equal_dist)){ std::reverse(vecUp.begin(), vecUp.end()); vecDown.insert(vecDown.begin(), vecUp.begin(), vecUp.end()); } - } else if (abs(first_dist - equal_dist) < 1e-5) { + } else if (compare_double(first_dist, equal_dist)) { vecDown.insert(vecDown.begin(), vecUp.front()); } } diff --git a/src/snapped-point.cpp b/src/snapped-point.cpp index 2e258d568c..040df81ce7 100644 --- a/src/snapped-point.cpp +++ b/src/snapped-point.cpp @@ -290,6 +290,8 @@ bool getClosestSP(std::list const &list, Inkscape::Snapp case Inkscape::SNAPTARGET_DISTRIBUTION_DOWN: result.setPoint({aligned.getPoint().x() ,result.getPoint().y()}); break; + case Inkscape::SNAPTARGET_DISTRIBUTION_XY: + break; default: g_warning("getClosestSP(): unknown distribution snap target %i", result.getTarget()); break; -- GitLab From 5ff197d58cdef01381bb601d946aa976c6df5f8b Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Tue, 22 Jun 2021 21:02:45 +0530 Subject: [PATCH 47/66] Fixed misuse of compare-double --- src/distribution-snapper.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/distribution-snapper.cpp b/src/distribution-snapper.cpp index a991a0a42d..d081ab7446 100644 --- a/src/distribution-snapper.cpp +++ b/src/distribution-snapper.cpp @@ -37,7 +37,7 @@ #include "style.h" #include "svg/svg.h" -#define DISTRIBUTION_SNAPPING_EPSILON 0.00005f +#define DISTRIBUTION_SNAPPING_EPSILON 0.5e-4f static bool compare_double(double x, double y, double epsilon = DISTRIBUTION_SNAPPING_EPSILON){ if(abs(x - y) < epsilon) @@ -122,7 +122,7 @@ bool Inkscape::DistributionSnapper::findSidewaysSnaps(Geom::Coord first_dist, } dist = distance_func(curr_bbox, *std::next(it)); - if (compare_double(first_dist, dist)) { + if (abs(first_dist - dist) > tol) { return false; } @@ -131,7 +131,7 @@ bool Inkscape::DistributionSnapper::findSidewaysSnaps(Geom::Coord first_dist, // TODO: investige how does this tollerance affect the number of equidistant // objects that are found? also does multiplying with level help (error propagation) - if (compare_double(distance_func(curr_bbox, *std::next(it)), dist), DISTRIBUTION_SNAPPING_EPSILON) { + if (compare_double(distance_func(curr_bbox, *std::next(it)), dist, level * DISTRIBUTION_SNAPPING_EPSILON)) { return findSidewaysSnaps(first_dist, ++it, end, vec, dist, tol, distance_func, ++level); } -- GitLab From cc1350df1caf81e92a3a66debc763c67d481b305 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Thu, 24 Jun 2021 16:16:19 +0530 Subject: [PATCH 48/66] Fixed code formatting and added local variables to new files --- src/alignment-snapper.cpp | 11 + src/alignment-snapper.h | 11 + src/distribution-snapper.cpp | 709 +++++++++++++++++------------------ src/distribution-snapper.h | 11 + 4 files changed, 367 insertions(+), 375 deletions(-) diff --git a/src/alignment-snapper.cpp b/src/alignment-snapper.cpp index 130d320f8e..05377294c0 100644 --- a/src/alignment-snapper.cpp +++ b/src/alignment-snapper.cpp @@ -297,5 +297,16 @@ Inkscape::SnapSourceType Inkscape::AlignmentSnapper::source2alignment(SnapSource } } +/* + 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 : + diff --git a/src/alignment-snapper.h b/src/alignment-snapper.h index f8e9875f8a..c7a3c27c76 100644 --- a/src/alignment-snapper.h +++ b/src/alignment-snapper.h @@ -82,3 +82,14 @@ private: } // end of 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:textwidth=99 : diff --git a/src/distribution-snapper.cpp b/src/distribution-snapper.cpp index d081ab7446..da75ceaaff 100644 --- a/src/distribution-snapper.cpp +++ b/src/distribution-snapper.cpp @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /** \file - * Snapping equidistant objects + * Snapping equidistant objects * * Authors: * Parth Pant @@ -37,105 +37,107 @@ #include "style.h" #include "svg/svg.h" -#define DISTRIBUTION_SNAPPING_EPSILON 0.5e-4f +#define DISTRIBUTION_SNAPPING_EPSILON 0.5e-4f -static bool compare_double(double x, double y, double epsilon = DISTRIBUTION_SNAPPING_EPSILON){ - if(abs(x - y) < epsilon) - return true; - return false; +static bool compare_double(double x, double y, double epsilon = DISTRIBUTION_SNAPPING_EPSILON) +{ + if (abs(x - y) < epsilon) + return true; + return false; } static int sortBoxesRight(Geom::Rect const &a, Geom::Rect const &b) { - if (a.midpoint().x() < b.midpoint().x()) - return 1; - return 0; + if (a.midpoint().x() < b.midpoint().x()) + return 1; + return 0; } static int sortBoxesLeft(Geom::Rect const &a, Geom::Rect const &b) { - if (a.midpoint().x() > b.midpoint().x()) - return 1; - return 0; + if (a.midpoint().x() > b.midpoint().x()) + return 1; + return 0; } static int sortBoxesUp(Geom::Rect const &a, Geom::Rect const &b) { - if (a.midpoint().y() > b.midpoint().y()) - return 1; - return 0; + if (a.midpoint().y() > b.midpoint().y()) + return 1; + return 0; } static int sortBoxesDown(Geom::Rect const &a, Geom::Rect const &b) { - if (a.midpoint().y() < b.midpoint().y()) - return 1; - return 0; + if (a.midpoint().y() < b.midpoint().y()) + return 1; + return 0; } Geom::Coord Inkscape::DistributionSnapper::distRight(Geom::Rect const &a, Geom::Rect const &b) { - return -a.max().x() + b.min().x(); + return -a.max().x() + b.min().x(); } Geom::Coord Inkscape::DistributionSnapper::distLeft(Geom::Rect const &a, Geom::Rect const &b) { - return a.min().x() - b.max().x(); + return a.min().x() - b.max().x(); } Geom::Coord Inkscape::DistributionSnapper::distUp(Geom::Rect const &a, Geom::Rect const &b) { - return a.min().y() - b.max().y(); + return a.min().y() - b.max().y(); } Geom::Coord Inkscape::DistributionSnapper::distDown(Geom::Rect const &a, Geom::Rect const &b) { - return -a.max().y() + b.min().y(); + return -a.max().y() + b.min().y(); } -bool Inkscape::DistributionSnapper::findSidewaysSnaps(Geom::Coord first_dist, - std::vector::iterator it, - std::vector::iterator end, - std::vector &vec, - Geom::Coord &dist, - Geom::Coord tol, - std::function const & distance_func, - int level) const +bool Inkscape::DistributionSnapper::findSidewaysSnaps( + Geom::Coord first_dist, + std::vector::iterator it, + std::vector::iterator end, + std::vector &vec, + Geom::Coord &dist, Geom::Coord tol, + std::function const &distance_func, + int level) const { - Geom::Rect curr_bbox = *it; + Geom::Rect curr_bbox = *it; - if (it == end) - return level != 0; + if (it == end) + return level != 0; - // TODO: check if rect1.instersects(rect2) gives the same result at rect2.intersects(rect1) - while (std::next(it) != end && (it->intersects(*std::next(it)) || std::next(it)->intersects(*it))) { - curr_bbox.unionWith(Geom::OptRect(*++it)); - } + // TODO: check if rect1.instersects(rect2) gives the same result at rect2.intersects(rect1) + while (std::next(it) != end && it->intersects(*std::next(it))) { + curr_bbox.unionWith(Geom::OptRect(*++it)); + } - vec.push_back(curr_bbox); + vec.push_back(curr_bbox); - if (level == 0) { - // just add the first bbox to the vector and return if there are no more - // objects this is used later to find in-between snaps - if (it + 1 == end) { - return false; - } + if (level == 0) { + // just add the first bbox to the vector and return if there are no more + // objects this is used later to find in-between snaps + if (it + 1 == end) { + return false; + } - dist = distance_func(curr_bbox, *std::next(it)); - if (abs(first_dist - dist) > tol) { - return false; - } + dist = distance_func(curr_bbox, *std::next(it)); + if (abs(first_dist - dist) > tol) { + return false; + } - return findSidewaysSnaps(first_dist, ++it, end, vec, dist, tol, distance_func, ++level); - } + return findSidewaysSnaps(first_dist, ++it, end, vec, dist, tol, distance_func, ++level); + } - // TODO: investige how does this tollerance affect the number of equidistant - // objects that are found? also does multiplying with level help (error propagation) - if (compare_double(distance_func(curr_bbox, *std::next(it)), dist, level * DISTRIBUTION_SNAPPING_EPSILON)) { - return findSidewaysSnaps(first_dist, ++it, end, vec, dist, tol, distance_func, ++level); - } + // TODO: investige how does this tollerance affect the number of equidistant + // objects that are found? also does multiplying with level help (error propagation) + if (compare_double(distance_func(curr_bbox, *std::next(it)), dist, level * DISTRIBUTION_SNAPPING_EPSILON)) { + return findSidewaysSnaps(first_dist, ++it, end, vec, dist, tol, distance_func, ++level); + } - return true; + return true; } Inkscape::DistributionSnapper::DistributionSnapper(SnapManager *sm, Geom::Coord const d) @@ -164,8 +166,8 @@ Inkscape::DistributionSnapper::~DistributionSnapper() void Inkscape::DistributionSnapper::_collectBBoxes(Geom::OptRect const &bbox_to_snap, bool const &first_point) const { - //if (!first_point) - //return; + // if (!first_point) + // return; _bboxes_right->clear(); _bboxes_left->clear(); @@ -176,12 +178,11 @@ void Inkscape::DistributionSnapper::_collectBBoxes(Geom::OptRect const &bbox_to_ Preferences *prefs = Preferences::get(); bool prefs_bbox = prefs->getBool("/tools/bounding_box"); - bbox_type = !prefs_bbox ? - SPItem::VISUAL_BBOX : SPItem::GEOMETRIC_BBOX; + bbox_type = !prefs_bbox ? SPItem::VISUAL_BBOX : SPItem::GEOMETRIC_BBOX; // collect bounding boxes of other objects - for (const auto & candidate : *(_snapmanager->align_snapper_candidates)) { - SPItem *root_item = candidate.item; + for (const auto &candidate : *(_snapmanager->align_snapper_candidates)) { + SPItem *root_item = candidate.item; // get the root item in case we have a duplicate at hand SPUse *use = dynamic_cast(candidate.item); @@ -194,7 +195,7 @@ void Inkscape::DistributionSnapper::_collectBBoxes(Geom::OptRect const &bbox_to_ if (!candidate.clip_or_mask) { Geom::OptRect b = root_item->desktopBounds(bbox_type); if (!b.intersects(bbox_to_snap)) { - auto diff_vec = b->midpoint() - bbox_to_snap->midpoint(); + auto diff_vec = b->midpoint() - bbox_to_snap->midpoint(); Geom::Rect Xbounds = *bbox_to_snap; Xbounds.expandBy(_snapmanager->_desktop->get_display_area().maxExtent(), 0); @@ -226,330 +227,276 @@ void Inkscape::DistributionSnapper::_collectBBoxes(Geom::OptRect const &bbox_to_ } void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &isr, - SnapCandidatePoint const &p, - Geom::OptRect const &bbox_to_snap, - std::vector *unselected_nodes, - SnapConstraint const &c, - Geom::Point const &p_proj_on_constraint) const + SnapCandidatePoint const &p, + Geom::OptRect const &bbox_to_snap, + std::vector *unselected_nodes, + SnapConstraint const &c, + Geom::Point const &p_proj_on_constraint) const { - bool consider_x = true; - bool consider_y = true; - if (!c.isUndefined() && c.isLinear()) { - if (c.getDirection().x() == 0) - consider_x = false; // consider horizontl snapping if moving vertically - else - consider_y = false; // consider vertical snapping if moving horizontally - } - - _collectBBoxes(bbox_to_snap, p.getSourceNum() <= 0); - - Geom::Coord offset; - - if (p.getSourceType() != SNAPSOURCE_BBOX_MIDPOINT) - return; - - Geom::Coord equal_dist; - - SnappedPoint sr, sl, sx, su, sd, sy; - Geom::Coord dist_x, dist_y; - bool snap_x = false, snap_y = false; - - // 1. look right - // if there is a snap then add right bboxes and look left, if there is a snap to the left then - // add those bboxes too - std::vector vecRight; - std::vector vecLeft; - if (consider_x && _bboxes_right->size() > 0) { - auto first_dist = distRight(*bbox_to_snap, _bboxes_right->front()); - - if (findSidewaysSnaps(first_dist, - _bboxes_right->begin(), - _bboxes_right->end(), - vecRight, - equal_dist, - getSnapperTolerance(), - &DistributionSnapper::distRight)) { - - Geom::Coord offset = first_dist - equal_dist; - Geom::Point target = bbox_to_snap->midpoint() + Geom::Point(offset, 0); - - Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); - Geom::Rect bbox = *bbox_to_snap * translation; - vecRight.insert(vecRight.begin(), bbox); - - _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - - if (_bboxes_left->size() > 0) { - first_dist = distLeft(bbox, _bboxes_left->front()); - Geom::Coord left_dist; - vecLeft.clear(); - if (findSidewaysSnaps(first_dist, - _bboxes_left->begin(), - _bboxes_left->end(), - vecLeft, - left_dist, - getSnapperTolerance(), - &DistributionSnapper::distLeft)) { - - if (compare_double(left_dist, equal_dist)){ - std::reverse(vecLeft.begin(), vecLeft.end()); - vecRight.insert(vecRight.begin(), vecLeft.begin(), vecLeft.end()); - } + bool consider_x = true; + bool consider_y = true; + if (!c.isUndefined() && c.isLinear()) { + if (c.getDirection().x() == 0) + consider_x = false; // consider horizontl snapping if moving vertically + else + consider_y = false; // consider vertical snapping if moving horizontally + } - } else if (compare_double(first_dist, equal_dist)) { - vecRight.insert(vecRight.begin(), vecLeft.front()); - } - } - - dist_x = abs(offset); - sx = SnappedPoint(target, vecRight, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_RIGHT, dist_x, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - snap_x = true; - } - } - - // 2. if no snap to right, look left - // if there is a snap then add left bboxes and right left, if there is a snap to the right then - // add those bboxes too - if (consider_x && !snap_x && _bboxes_left->size() > 0) { - auto first_dist = distLeft(*bbox_to_snap, _bboxes_left->front()); - - vecLeft.clear(); - if (findSidewaysSnaps(first_dist, - _bboxes_left->begin(), - _bboxes_left->end(), - vecLeft, - equal_dist, - getSnapperTolerance(), - &DistributionSnapper::distLeft)) { - - Geom::Coord offset = first_dist - equal_dist; - Geom::Point target = bbox_to_snap->midpoint() - Geom::Point(offset, 0); - - // translate the source bbox to the snap position - Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); - Geom::Rect bbox = *bbox_to_snap * translation; - std::reverse(vecLeft.begin(), vecLeft.end()); - vecLeft.push_back(bbox); - - _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - - if (_bboxes_right->size() > 0) { - first_dist = distRight(bbox, _bboxes_right->front()); - Geom::Coord right_dist; - vecRight.clear(); - if (findSidewaysSnaps(first_dist, - _bboxes_right->begin(), - _bboxes_right->end(), - vecRight, - right_dist, - getSnapperTolerance(), - &DistributionSnapper::distRight)) { - - if (compare_double(right_dist, equal_dist)){ - vecLeft.insert(vecLeft.end(), vecRight.begin(), vecRight.end()); - } + _collectBBoxes(bbox_to_snap, p.getSourceNum() <= 0); + + Geom::Coord offset; - } else if (compare_double(first_dist, equal_dist)) { - vecLeft.push_back(vecRight.front()); + if (p.getSourceType() != SNAPSOURCE_BBOX_MIDPOINT) + return; + + Geom::Coord equal_dist; + + SnappedPoint sr, sl, sx, su, sd, sy; + Geom::Coord dist_x, dist_y; + bool snap_x = false, snap_y = false; + + // 1. look right + // if there is a snap then add right bboxes and look left, if there is a snap to the left then + // add those bboxes too + std::vector vecRight; + std::vector vecLeft; + if (consider_x && _bboxes_right->size() > 0) { + auto first_dist = distRight(*bbox_to_snap, _bboxes_right->front()); + + if (findSidewaysSnaps(first_dist, _bboxes_right->begin(), _bboxes_right->end(), vecRight, equal_dist, getSnapperTolerance(), &DistributionSnapper::distRight)) { + Geom::Coord offset = first_dist - equal_dist; + Geom::Point target = bbox_to_snap->midpoint() + Geom::Point(offset, 0); + + Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); + Geom::Rect bbox = *bbox_to_snap * translation; + vecRight.insert(vecRight.begin(), bbox); + + _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); + + if (_bboxes_left->size() > 0) { + first_dist = distLeft(bbox, _bboxes_left->front()); + Geom::Coord left_dist; + vecLeft.clear(); + if (findSidewaysSnaps(first_dist, _bboxes_left->begin(), _bboxes_left->end(), vecLeft, left_dist, getSnapperTolerance(), &DistributionSnapper::distLeft)) { + if (compare_double(left_dist, equal_dist)) { + std::reverse(vecLeft.begin(), vecLeft.end()); + vecRight.insert(vecRight.begin(), vecLeft.begin(), vecLeft.end()); + } + + } else if (compare_double(first_dist, equal_dist)) { + vecRight.insert(vecRight.begin(), vecLeft.front()); + } } - } - - dist_x = abs(offset); - sx = SnappedPoint(target, vecLeft, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_LEFT, dist_x, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - snap_x = true; - } - } - - // 3. if no snap to right or left just add the center snap - if (consider_x && !snap_x && vecRight.size() > 0 && vecLeft.size() > 0) { - auto x = Geom::Point((vecRight.front().min() + vecLeft.front().max())/2).x(); - offset = abs(x - bbox_to_snap->midpoint().x()); - if (offset < getSnapperTolerance()) { - Geom::Point target = Geom::Point(x, bbox_to_snap->midpoint().y()); - // translate the source bbox to the snap position - Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); - Geom::Rect bbox = *bbox_to_snap * translation; - std::vector bboxes = {vecLeft.front(), bbox, vecRight.front()}; - - _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - - equal_dist = bbox.min().x() - vecLeft.front().max().x(); - sx = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_X, offset, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - snap_x = true; - } - } - - // 1. look Up - // if there is a snap then add top bboxes and look down, if there is a snap at the bottom then - // add those bboxes too - std::vector vecUp; - std::vector vecDown; - if (consider_y && _bboxes_up->size() > 0) { - auto first_dist = distUp(*bbox_to_snap, _bboxes_up->front()); - - if (findSidewaysSnaps(first_dist, - _bboxes_up->begin(), - _bboxes_up->end(), - vecUp, - equal_dist, - getSnapperTolerance(), - &DistributionSnapper::distUp)) { - - Geom::Coord offset = first_dist - equal_dist; - Geom::Point target = bbox_to_snap->midpoint() - Geom::Point(0, offset); - - // translate the source bbox to the snap position - Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); - Geom::Rect bbox = *bbox_to_snap * translation; - std::reverse(vecUp.begin(), vecUp.end()); - vecUp.push_back(bbox); - - _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - - if (_bboxes_down->size() > 0) { - first_dist = distDown(bbox, _bboxes_down->front()); - Geom::Coord down_dist; - vecDown.clear(); - if (findSidewaysSnaps(first_dist, - _bboxes_down->begin(), - _bboxes_down->end(), - vecDown, - down_dist, - getSnapperTolerance(), - &DistributionSnapper::distDown)) { - - if (abs(down_dist - equal_dist) < 1e-4){ - vecUp.insert(vecUp.end(), vecDown.begin(), vecDown.end()); + + dist_x = abs(offset); + sx = SnappedPoint(target, vecRight, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_RIGHT, dist_x, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + snap_x = true; + } + } + + // 2. if no snap to right, look left + // if there is a snap then add left bboxes and right left, if there is a snap to the right then + // add those bboxes too + if (consider_x && !snap_x && _bboxes_left->size() > 0) { + auto first_dist = distLeft(*bbox_to_snap, _bboxes_left->front()); + + vecLeft.clear(); + if (findSidewaysSnaps(first_dist, _bboxes_left->begin(), _bboxes_left->end(), vecLeft, equal_dist, getSnapperTolerance(), &DistributionSnapper::distLeft)) { + Geom::Coord offset = first_dist - equal_dist; + Geom::Point target = bbox_to_snap->midpoint() - Geom::Point(offset, 0); + + // translate the source bbox to the snap position + Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); + Geom::Rect bbox = *bbox_to_snap * translation; + std::reverse(vecLeft.begin(), vecLeft.end()); + vecLeft.push_back(bbox); + + _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); + + if (_bboxes_right->size() > 0) { + first_dist = distRight(bbox, _bboxes_right->front()); + Geom::Coord right_dist; + vecRight.clear(); + if (findSidewaysSnaps(first_dist, _bboxes_right->begin(), _bboxes_right->end(), vecRight, right_dist, getSnapperTolerance(), &DistributionSnapper::distRight)) { + if (compare_double(right_dist, equal_dist)) { + vecLeft.insert(vecLeft.end(), vecRight.begin(), vecRight.end()); + } + + } else if (compare_double(first_dist, equal_dist)) { + vecLeft.push_back(vecRight.front()); } + } - } else if (abs(first_dist - equal_dist) < 1e-4) { - vecUp.insert(vecUp.end(), vecDown.front()); + dist_x = abs(offset); + sx = SnappedPoint(target, vecLeft, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_LEFT, dist_x, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + snap_x = true; + } + } + + // 3. if no snap to right or left just add the center snap + if (consider_x && !snap_x && vecRight.size() > 0 && vecLeft.size() > 0) { + auto x = Geom::Point((vecRight.front().min() + vecLeft.front().max()) / 2).x(); + offset = abs(x - bbox_to_snap->midpoint().x()); + if (offset < getSnapperTolerance()) { + Geom::Point target = Geom::Point(x, bbox_to_snap->midpoint().y()); + // translate the source bbox to the snap position + Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); + Geom::Rect bbox = *bbox_to_snap * translation; + std::vector bboxes = {vecLeft.front(), bbox, vecRight.front()}; + + _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); + + equal_dist = bbox.min().x() - vecLeft.front().max().x(); + sx = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_X, offset, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + snap_x = true; + } + } + + // 1. look Up + // if there is a snap then add top bboxes and look down, if there is a snap at the bottom then + // add those bboxes too + std::vector vecUp; + std::vector vecDown; + if (consider_y && _bboxes_up->size() > 0) { + auto first_dist = distUp(*bbox_to_snap, _bboxes_up->front()); + + if (findSidewaysSnaps(first_dist, _bboxes_up->begin(), _bboxes_up->end(), vecUp, equal_dist, getSnapperTolerance(), &DistributionSnapper::distUp)) { + Geom::Coord offset = first_dist - equal_dist; + Geom::Point target = bbox_to_snap->midpoint() - Geom::Point(0, offset); + + // translate the source bbox to the snap position + Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); + Geom::Rect bbox = *bbox_to_snap * translation; + std::reverse(vecUp.begin(), vecUp.end()); + vecUp.push_back(bbox); + + _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); + + if (_bboxes_down->size() > 0) { + first_dist = distDown(bbox, _bboxes_down->front()); + Geom::Coord down_dist; + vecDown.clear(); + if (findSidewaysSnaps(first_dist, _bboxes_down->begin(), _bboxes_down->end(), vecDown, down_dist, + getSnapperTolerance(), &DistributionSnapper::distDown)) { + if (abs(down_dist - equal_dist) < 1e-4) { + vecUp.insert(vecUp.end(), vecDown.begin(), vecDown.end()); + } + + } else if (abs(first_dist - equal_dist) < 1e-4) { + vecUp.insert(vecUp.end(), vecDown.front()); + } } - } - - dist_y = abs(offset); - sy = SnappedPoint(target, vecUp, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_UP, dist_y, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - snap_y = true; - } - } - - // 2. if no snaps on top, look Down - // if there is a snap then add bottom bboxes and look Up, if there is a snap above then - // add those bboxes too - if (consider_y && !snap_y && _bboxes_down->size() > 0) { - auto first_dist = distDown(*bbox_to_snap, _bboxes_down->front()); - - vecDown.clear(); - if (findSidewaysSnaps(first_dist, - _bboxes_down->begin(), - _bboxes_down->end(), - vecDown, - equal_dist, - getSnapperTolerance(), - &DistributionSnapper::distDown)) { - - Geom::Coord offset = first_dist - equal_dist; - Geom::Point target = bbox_to_snap->midpoint() + Geom::Point(0, offset); - - // translate the source bbox to the snap position - Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); - Geom::Rect bbox = *bbox_to_snap * translation; - vecDown.insert(vecDown.begin(), bbox); - - _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - - if (_bboxes_up->size() > 0) { - first_dist = distUp(bbox, _bboxes_up->front()); - Geom::Coord up_dist; - vecUp.clear(); - - if (findSidewaysSnaps(first_dist, - _bboxes_up->begin(), - _bboxes_up->end(), - vecUp, - up_dist, - getSnapperTolerance(), - &DistributionSnapper::distUp)) { - - if (compare_double(up_dist, equal_dist)){ - std::reverse(vecUp.begin(), vecUp.end()); - vecDown.insert(vecDown.begin(), vecUp.begin(), vecUp.end()); - } - } else if (compare_double(first_dist, equal_dist)) { - vecDown.insert(vecDown.begin(), vecUp.front()); + + dist_y = abs(offset); + sy = SnappedPoint(target, vecUp, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_UP, dist_y, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + snap_y = true; + } + } + + // 2. if no snaps on top, look Down + // if there is a snap then add bottom bboxes and look Up, if there is a snap above then + // add those bboxes too + if (consider_y && !snap_y && _bboxes_down->size() > 0) { + auto first_dist = distDown(*bbox_to_snap, _bboxes_down->front()); + + vecDown.clear(); + if (findSidewaysSnaps(first_dist, _bboxes_down->begin(), _bboxes_down->end(), vecDown, equal_dist, getSnapperTolerance(), &DistributionSnapper::distDown)) { + Geom::Coord offset = first_dist - equal_dist; + Geom::Point target = bbox_to_snap->midpoint() + Geom::Point(0, offset); + + // translate the source bbox to the snap position + Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); + Geom::Rect bbox = *bbox_to_snap * translation; + vecDown.insert(vecDown.begin(), bbox); + + _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); + + if (_bboxes_up->size() > 0) { + first_dist = distUp(bbox, _bboxes_up->front()); + Geom::Coord up_dist; + vecUp.clear(); + + if (findSidewaysSnaps(first_dist, _bboxes_up->begin(), _bboxes_up->end(), vecUp, up_dist, getSnapperTolerance(), &DistributionSnapper::distUp)) { + if (compare_double(up_dist, equal_dist)) { + std::reverse(vecUp.begin(), vecUp.end()); + vecDown.insert(vecDown.begin(), vecUp.begin(), vecUp.end()); + } + } else if (compare_double(first_dist, equal_dist)) { + vecDown.insert(vecDown.begin(), vecUp.front()); + } } - } - - dist_y = abs(offset); - sy = SnappedPoint(target, vecDown, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_DOWN, dist_y, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - snap_y = true; - } - } - - // 3. if no snap to right or left just add the center snap - if (consider_y && !snap_y && vecUp.size() > 0 && vecDown.size() > 0) { - auto y = Geom::Point((vecUp.front().max() + vecDown.front().min())/2).y(); - offset = abs(y - bbox_to_snap->midpoint().y()); - if (consider_y && offset < getSnapperTolerance()) { - Geom::Point target = Geom::Point(bbox_to_snap->midpoint().x(), y); - // translate the source bbox to the snap position - Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); - Geom::Rect bbox = *bbox_to_snap * translation; - std::vector bboxes = {vecUp.front(), bbox, vecDown.front()}; - - _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - - equal_dist = bbox.min().y() - vecUp.front().max().y(); - sy = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_Y, offset, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - snap_y = true; - } - } - - if (snap_x && snap_y) { - Geom::Point target = Geom::Point(sx.getPoint().x(), sy.getPoint().y()); - Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); - Geom::Rect bbox = *bbox_to_snap * translation; - std::vector bboxes_x = sx.getBBoxes(); - std::vector bboxes_y = sy.getBBoxes(); - - _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); - auto si = SnappedPoint(target, bboxes_x, bboxes_y, bbox, sx.getDistributionDistance(), sy.getDistributionDistance(), p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_XY, offset, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); - isr.points.push_back(si); - return; - } - - if (snap_x) { - isr.points.push_back(sx); - } - - if (snap_y) { - isr.points.push_back(sy); - } + dist_y = abs(offset); + sy = SnappedPoint(target, vecDown, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_DOWN, dist_y, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + snap_y = true; + } + } + + // 3. if no snap to right or left just add the center snap + if (consider_y && !snap_y && vecUp.size() > 0 && vecDown.size() > 0) { + auto y = Geom::Point((vecUp.front().max() + vecDown.front().min()) / 2).y(); + offset = abs(y - bbox_to_snap->midpoint().y()); + if (consider_y && offset < getSnapperTolerance()) { + Geom::Point target = Geom::Point(bbox_to_snap->midpoint().x(), y); + // translate the source bbox to the snap position + Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); + Geom::Rect bbox = *bbox_to_snap * translation; + std::vector bboxes = {vecUp.front(), bbox, vecDown.front()}; + + _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); + + equal_dist = bbox.min().y() - vecUp.front().max().y(); + sy = SnappedPoint(target, bboxes, bbox, equal_dist, p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_Y, offset, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + snap_y = true; + } + } + + if (snap_x && snap_y) { + Geom::Point target = Geom::Point(sx.getPoint().x(), sy.getPoint().y()); + Geom::Affine translation = Geom::Translate(target - bbox_to_snap->midpoint()); + Geom::Rect bbox = *bbox_to_snap * translation; + std::vector bboxes_x = sx.getBBoxes(); + std::vector bboxes_y = sy.getBBoxes(); + + _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); + auto si = SnappedPoint(target, bboxes_x, bboxes_y, bbox, sx.getDistributionDistance(), sy.getDistributionDistance(), p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_XY, offset, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); + isr.points.push_back(si); + return; + } + + if (snap_x) { + isr.points.push_back(sx); + } + + if (snap_y) { + isr.points.push_back(sy); + } } -void Inkscape::DistributionSnapper::_correctSelectionBBox(Geom::Point &target, Geom::Point const &p, Geom::Rect const &bbox_to_snap) const +void Inkscape::DistributionSnapper::_correctSelectionBBox(Geom::Point &target, + Geom::Point const &p, + Geom::Rect const &bbox_to_snap) const { - if (_snapmanager->_desktop->selection->size() > 1) { - auto correction = bbox_to_snap.midpoint() - p; - target -= correction; - } + if (_snapmanager->_desktop->selection->size() > 1) { + auto correction = bbox_to_snap.midpoint() - p; + target -= correction; + } } void Inkscape::DistributionSnapper::freeSnap(IntermSnapResults &isr, - Inkscape::SnapCandidatePoint const &p, - Geom::OptRect const &bbox_to_snap, - std::vector const *it, - std::vector *unselected_nodes) const + Inkscape::SnapCandidatePoint const &p, + Geom::OptRect const &bbox_to_snap, + std::vector const *it, + std::vector *unselected_nodes) const { if (bbox_to_snap.empty()) return; if (!(p.getSourceType() & SNAPSOURCE_BBOX_CATEGORY)) { - return; + return; } - // toggle checks + // toggle checks if (!_snap_enabled || !_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_DISTRIBUTION_CATEGORY)) return; @@ -557,19 +504,19 @@ void Inkscape::DistributionSnapper::freeSnap(IntermSnapResults &isr, } void Inkscape::DistributionSnapper::constrainedSnap(IntermSnapResults &isr, - Inkscape::SnapCandidatePoint const &p, - Geom::OptRect const &bbox_to_snap, - SnapConstraint const &c, - std::vector const *it, - std::vector *unselected_nodes) const + Inkscape::SnapCandidatePoint const &p, + Geom::OptRect const &bbox_to_snap, + SnapConstraint const &c, + std::vector const *it, + std::vector *unselected_nodes) const { if (bbox_to_snap.empty()) return; - + // project the mouse pointer onto the constraint. Only the projected point will be considered for snapping Geom::Point pp = c.projection(p.getPoint()); - - // toggle checks + + // toggle checks if (!_snap_enabled || !_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_DISTRIBUTION_CATEGORY)) return; @@ -583,12 +530,24 @@ bool Inkscape::DistributionSnapper::ThisSnapperMightSnap() const bool Inkscape::DistributionSnapper::getSnapperAlwaysSnap() const { - return _snapmanager->snapprefs.getDistributionTolerance() == 10000; //TODO: Replace this threshold of 10000 by a constant; see also tolerance-slider.cpp + // TODO: Replace this threshold of 10000 by a constant; see also tolerance-slider.cpp + return _snapmanager->snapprefs.getDistributionTolerance() == 10000; } Geom::Coord Inkscape::DistributionSnapper::getSnapperTolerance() const { SPDesktop const *dt = _snapmanager->getDesktop(); - double const zoom = dt ? dt->current_zoom() : 1; + double const zoom = dt ? dt->current_zoom() : 1; return _snapmanager->snapprefs.getDistributionTolerance() / zoom; } + +/* + 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 : diff --git a/src/distribution-snapper.h b/src/distribution-snapper.h index 7d8deb9d01..0e094509c2 100644 --- a/src/distribution-snapper.h +++ b/src/distribution-snapper.h @@ -131,3 +131,14 @@ private: } // end of 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:textwidth=99 : -- GitLab From f5e0687266fb0f8c6bd963719faef1549623213e Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Fri, 25 Jun 2021 22:47:43 +0530 Subject: [PATCH 49/66] passing source bbox instead of first_distance --- src/distribution-snapper.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/distribution-snapper.cpp b/src/distribution-snapper.cpp index da75ceaaff..23529e0432 100644 --- a/src/distribution-snapper.cpp +++ b/src/distribution-snapper.cpp @@ -95,13 +95,13 @@ Geom::Coord Inkscape::DistributionSnapper::distDown(Geom::Rect const &a, Geom::R } bool Inkscape::DistributionSnapper::findSidewaysSnaps( - Geom::Coord first_dist, + Geom::Rect const &source_bbox, std::vector::iterator it, std::vector::iterator end, std::vector &vec, - Geom::Coord &dist, Geom::Coord tol, - std::function const &distance_func, + Geom::Coord &dist, + Geom::Coord tol, + std::function const &distance_func, int level) const { Geom::Rect curr_bbox = *it; @@ -124,17 +124,17 @@ bool Inkscape::DistributionSnapper::findSidewaysSnaps( } dist = distance_func(curr_bbox, *std::next(it)); - if (abs(first_dist - dist) > tol) { + if (abs(distance_func(source_bbox, curr_bbox) - dist) > tol) { return false; } - return findSidewaysSnaps(first_dist, ++it, end, vec, dist, tol, distance_func, ++level); + return findSidewaysSnaps(source_bbox, ++it, end, vec, dist, tol, distance_func, ++level); } // TODO: investige how does this tollerance affect the number of equidistant // objects that are found? also does multiplying with level help (error propagation) if (compare_double(distance_func(curr_bbox, *std::next(it)), dist, level * DISTRIBUTION_SNAPPING_EPSILON)) { - return findSidewaysSnaps(first_dist, ++it, end, vec, dist, tol, distance_func, ++level); + return findSidewaysSnaps(source_bbox, ++it, end, vec, dist, tol, distance_func, ++level); } return true; @@ -237,7 +237,7 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is bool consider_y = true; if (!c.isUndefined() && c.isLinear()) { if (c.getDirection().x() == 0) - consider_x = false; // consider horizontl snapping if moving vertically + consider_x = false; // consider horizontal snapping if moving vertically else consider_y = false; // consider vertical snapping if moving horizontally } @@ -263,7 +263,7 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is if (consider_x && _bboxes_right->size() > 0) { auto first_dist = distRight(*bbox_to_snap, _bboxes_right->front()); - if (findSidewaysSnaps(first_dist, _bboxes_right->begin(), _bboxes_right->end(), vecRight, equal_dist, getSnapperTolerance(), &DistributionSnapper::distRight)) { + if (findSidewaysSnaps(*bbox_to_snap, _bboxes_right->begin(), _bboxes_right->end(), vecRight, equal_dist, getSnapperTolerance(), &DistributionSnapper::distRight)) { Geom::Coord offset = first_dist - equal_dist; Geom::Point target = bbox_to_snap->midpoint() + Geom::Point(offset, 0); @@ -277,7 +277,7 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is first_dist = distLeft(bbox, _bboxes_left->front()); Geom::Coord left_dist; vecLeft.clear(); - if (findSidewaysSnaps(first_dist, _bboxes_left->begin(), _bboxes_left->end(), vecLeft, left_dist, getSnapperTolerance(), &DistributionSnapper::distLeft)) { + if (findSidewaysSnaps(*bbox_to_snap, _bboxes_left->begin(), _bboxes_left->end(), vecLeft, left_dist, getSnapperTolerance(), &DistributionSnapper::distLeft)) { if (compare_double(left_dist, equal_dist)) { std::reverse(vecLeft.begin(), vecLeft.end()); vecRight.insert(vecRight.begin(), vecLeft.begin(), vecLeft.end()); @@ -301,7 +301,7 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is auto first_dist = distLeft(*bbox_to_snap, _bboxes_left->front()); vecLeft.clear(); - if (findSidewaysSnaps(first_dist, _bboxes_left->begin(), _bboxes_left->end(), vecLeft, equal_dist, getSnapperTolerance(), &DistributionSnapper::distLeft)) { + if (findSidewaysSnaps(*bbox_to_snap, _bboxes_left->begin(), _bboxes_left->end(), vecLeft, equal_dist, getSnapperTolerance(), &DistributionSnapper::distLeft)) { Geom::Coord offset = first_dist - equal_dist; Geom::Point target = bbox_to_snap->midpoint() - Geom::Point(offset, 0); @@ -317,7 +317,7 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is first_dist = distRight(bbox, _bboxes_right->front()); Geom::Coord right_dist; vecRight.clear(); - if (findSidewaysSnaps(first_dist, _bboxes_right->begin(), _bboxes_right->end(), vecRight, right_dist, getSnapperTolerance(), &DistributionSnapper::distRight)) { + if (findSidewaysSnaps(*bbox_to_snap, _bboxes_right->begin(), _bboxes_right->end(), vecRight, right_dist, getSnapperTolerance(), &DistributionSnapper::distRight)) { if (compare_double(right_dist, equal_dist)) { vecLeft.insert(vecLeft.end(), vecRight.begin(), vecRight.end()); } @@ -360,7 +360,7 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is if (consider_y && _bboxes_up->size() > 0) { auto first_dist = distUp(*bbox_to_snap, _bboxes_up->front()); - if (findSidewaysSnaps(first_dist, _bboxes_up->begin(), _bboxes_up->end(), vecUp, equal_dist, getSnapperTolerance(), &DistributionSnapper::distUp)) { + if (findSidewaysSnaps(*bbox_to_snap, _bboxes_up->begin(), _bboxes_up->end(), vecUp, equal_dist, getSnapperTolerance(), &DistributionSnapper::distUp)) { Geom::Coord offset = first_dist - equal_dist; Geom::Point target = bbox_to_snap->midpoint() - Geom::Point(0, offset); @@ -376,7 +376,7 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is first_dist = distDown(bbox, _bboxes_down->front()); Geom::Coord down_dist; vecDown.clear(); - if (findSidewaysSnaps(first_dist, _bboxes_down->begin(), _bboxes_down->end(), vecDown, down_dist, + if (findSidewaysSnaps(*bbox_to_snap, _bboxes_down->begin(), _bboxes_down->end(), vecDown, down_dist, getSnapperTolerance(), &DistributionSnapper::distDown)) { if (abs(down_dist - equal_dist) < 1e-4) { vecUp.insert(vecUp.end(), vecDown.begin(), vecDown.end()); @@ -400,7 +400,7 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is auto first_dist = distDown(*bbox_to_snap, _bboxes_down->front()); vecDown.clear(); - if (findSidewaysSnaps(first_dist, _bboxes_down->begin(), _bboxes_down->end(), vecDown, equal_dist, getSnapperTolerance(), &DistributionSnapper::distDown)) { + if (findSidewaysSnaps(*bbox_to_snap, _bboxes_down->begin(), _bboxes_down->end(), vecDown, equal_dist, getSnapperTolerance(), &DistributionSnapper::distDown)) { Geom::Coord offset = first_dist - equal_dist; Geom::Point target = bbox_to_snap->midpoint() + Geom::Point(0, offset); @@ -416,7 +416,7 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is Geom::Coord up_dist; vecUp.clear(); - if (findSidewaysSnaps(first_dist, _bboxes_up->begin(), _bboxes_up->end(), vecUp, up_dist, getSnapperTolerance(), &DistributionSnapper::distUp)) { + if (findSidewaysSnaps(*bbox_to_snap, _bboxes_up->begin(), _bboxes_up->end(), vecUp, up_dist, getSnapperTolerance(), &DistributionSnapper::distUp)) { if (compare_double(up_dist, equal_dist)) { std::reverse(vecUp.begin(), vecUp.end()); vecDown.insert(vecDown.begin(), vecUp.begin(), vecUp.end()); -- GitLab From 4c50b2e420bd22784ac053cb3889cbfdd97c8124 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Sun, 27 Jun 2021 14:49:47 +0530 Subject: [PATCH 50/66] Better recursive snapping Bug: overlapping objects are only considered when level == 0 --- src/distribution-snapper.cpp | 221 ++++++++++++++++++++++++++++------- src/distribution-snapper.h | 9 +- 2 files changed, 185 insertions(+), 45 deletions(-) diff --git a/src/distribution-snapper.cpp b/src/distribution-snapper.cpp index 23529e0432..77ae1ca636 100644 --- a/src/distribution-snapper.cpp +++ b/src/distribution-snapper.cpp @@ -33,7 +33,6 @@ #include "object/sp-use.h" #include "path/path-util.h" // curve_for_item #include "preferences.h" -#include "snap-enums.h" #include "style.h" #include "svg/svg.h" @@ -94,7 +93,7 @@ Geom::Coord Inkscape::DistributionSnapper::distDown(Geom::Rect const &a, Geom::R return -a.max().y() + b.min().y(); } -bool Inkscape::DistributionSnapper::findSidewaysSnaps( +bool Inkscape::DistributionSnapper::_findSidewaysSnaps( Geom::Rect const &source_bbox, std::vector::iterator it, std::vector::iterator end, @@ -104,40 +103,74 @@ bool Inkscape::DistributionSnapper::findSidewaysSnaps( std::function const &distance_func, int level) const { - Geom::Rect curr_bbox = *it; - - if (it == end) - return level != 0; - - // TODO: check if rect1.instersects(rect2) gives the same result at rect2.intersects(rect1) - while (std::next(it) != end && it->intersects(*std::next(it))) { - curr_bbox.unionWith(Geom::OptRect(*++it)); - } - - vec.push_back(curr_bbox); + std::vector::iterator next_bbox = it; + std::vector::iterator _next_bbox = it; if (level == 0) { - // just add the first bbox to the vector and return if there are no more - // objects this is used later to find in-between snaps - if (it + 1 == end) { - return false; + int max_length = 0; + + // check each consecutive box for a snap + while (std::next(next_bbox) != end) { + auto first_dist = distance_func(source_bbox, *next_bbox); + level = 0; + + // temporary result for this particular item + auto result = new std::vector; + if (_findSidewaysSnaps(*next_bbox, ++it, end, *result, first_dist, tol, distance_func, ++level)) { + if (result->size() > max_length) { + // if this item has the most number of items equidistant form each other + // then make this the final result + max_length = result->size(); + vec = *result; + dist = first_dist; + } else { + // delete the result + result->clear(); + delete result; + } + } else { + // delete the result + result->clear(); + delete result; + } + + ++next_bbox; } - dist = distance_func(curr_bbox, *std::next(it)); - if (abs(distance_func(source_bbox, curr_bbox) - dist) > tol) { + // if there is no snap, just add the first item and return false + // this is useful to find in-between snaps (see _snapEquidistantPoints()) + if (max_length == 0) { + vec.push_back(*_next_bbox); return false; } - - return findSidewaysSnaps(source_bbox, ++it, end, vec, dist, tol, distance_func, ++level); + return true; } - // TODO: investige how does this tollerance affect the number of equidistant - // objects that are found? also does multiplying with level help (error propagation) - if (compare_double(distance_func(curr_bbox, *std::next(it)), dist, level * DISTRIBUTION_SNAPPING_EPSILON)) { - return findSidewaysSnaps(source_bbox, ++it, end, vec, dist, tol, distance_func, ++level); + // if not the zeroth level + if (level != 1) + vec.push_back(source_bbox); + + if (it == end) + return true; + + while (next_bbox != end) { + Geom::Coord next_dist = distance_func(source_bbox, *next_bbox); + + if (level == 1 && compare_double(dist, next_dist, tol)){ + // if this is the first level, check if the snap is within tolerance + // we cancel here if the possible snap in not whithing tolerance, saves us some time! + dist = next_dist; + vec.push_back(source_bbox); + return _findSidewaysSnaps(*next_bbox, ++it, end, vec, dist, tol, distance_func, ++level); + } else if (compare_double(dist, next_dist)) { + return _findSidewaysSnaps(*next_bbox, ++it, end, vec, dist, tol, distance_func, ++level); + } + + ++next_bbox; } - return true; + // once reach the end, return false if level == 1, as there is just one(or more in case of overlap) item to that side. + return level != 1; } Inkscape::DistributionSnapper::DistributionSnapper(SnapManager *sm, Geom::Coord const d) @@ -166,8 +199,8 @@ Inkscape::DistributionSnapper::~DistributionSnapper() void Inkscape::DistributionSnapper::_collectBBoxes(Geom::OptRect const &bbox_to_snap, bool const &first_point) const { - // if (!first_point) - // return; + if (!first_point) + return; _bboxes_right->clear(); _bboxes_left->clear(); @@ -224,6 +257,110 @@ void Inkscape::DistributionSnapper::_collectBBoxes(Geom::OptRect const &bbox_to_ std::stable_sort(_bboxes_left->begin(), _bboxes_left->end(), sortBoxesLeft); std::stable_sort(_bboxes_up->begin(), _bboxes_up->end(), sortBoxesUp); std::stable_sort(_bboxes_down->begin(), _bboxes_down->end(), sortBoxesDown); + + _addBBoxForIntersectingBoxes(); +} + +void Inkscape::DistributionSnapper::_addBBoxForIntersectingBoxes() const { + if (_bboxes_right->size() > 0) { + for (auto it = _bboxes_right->begin(); std::next(it) != _bboxes_right->end(); it++) { + Geom::Rect comb(*it); + int num = 0; + auto start = it; + auto insertPos = it; + + while (std::next(it) != _bboxes_right->end() && it->intersects(*std::next(it))) { + comb.unionWith(*std::next(it)); + if (comb.midpoint().x() > it->midpoint().x()) { + insertPos = std::next(it); + } else { + ++num; + } + ++it; + } + + if (it != start) { + it = _bboxes_right->insert(insertPos, comb); + } + + it += num; + } + } + + if (_bboxes_left->size() > 0) { + for (auto it = _bboxes_left->begin(); std::next(it) != _bboxes_left->end(); it++) { + Geom::Rect comb(*it); + int num = 0; + auto start = it; + auto insertPos = it; + + while (std::next(it) != _bboxes_left->end() && it->intersects(*std::next(it))) { + comb.unionWith(*std::next(it)); + if (comb.midpoint().x() < it->midpoint().x()) { + insertPos = std::next(it); + } else { + ++num; + } + ++it; + } + + if (it != start) { + it = _bboxes_left->insert(insertPos, comb); + } + + it += num; + } + } + + if (_bboxes_up->size() > 0) { + for (auto it = _bboxes_up->begin(); std::next(it) != _bboxes_up->end(); it++) { + Geom::Rect comb(*it); + int num = 0; + auto start = it; + auto insertPos = it; + + while (std::next(it) != _bboxes_up->end() && it->intersects(*std::next(it))) { + comb.unionWith(*std::next(it)); + if (comb.midpoint().y() > it->midpoint().y()) { + insertPos = std::next(it); + } else { + ++num; + } + ++it; + } + + if (it != start) { + it = _bboxes_up->insert(insertPos, comb); + } + + it += num; + } + } + + if (_bboxes_down->size() > 0) { + for (auto it = _bboxes_down->begin(); std::next(it) != _bboxes_down->end(); it++) { + Geom::Rect comb(*it); + int num = 0; + auto start = it; + auto insertPos = it; + + while (std::next(it) != _bboxes_down->end() && it->intersects(*std::next(it))) { + comb.unionWith(*std::next(it)); + if (comb.midpoint().y() < it->midpoint().y()) { + insertPos = std::next(it); + } else { + ++num; + } + ++it; + } + + if (it != start) { + it = _bboxes_down->insert(insertPos, comb); + } + + it += num; + } + } } void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &isr, @@ -261,9 +398,8 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is std::vector vecRight; std::vector vecLeft; if (consider_x && _bboxes_right->size() > 0) { - auto first_dist = distRight(*bbox_to_snap, _bboxes_right->front()); - - if (findSidewaysSnaps(*bbox_to_snap, _bboxes_right->begin(), _bboxes_right->end(), vecRight, equal_dist, getSnapperTolerance(), &DistributionSnapper::distRight)) { + if (_findSidewaysSnaps(*bbox_to_snap, _bboxes_right->begin(), _bboxes_right->end(), vecRight, equal_dist, getSnapperTolerance(), &DistributionSnapper::distRight)) { + auto first_dist = distRight(*bbox_to_snap, vecRight.front()); Geom::Coord offset = first_dist - equal_dist; Geom::Point target = bbox_to_snap->midpoint() + Geom::Point(offset, 0); @@ -277,7 +413,7 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is first_dist = distLeft(bbox, _bboxes_left->front()); Geom::Coord left_dist; vecLeft.clear(); - if (findSidewaysSnaps(*bbox_to_snap, _bboxes_left->begin(), _bboxes_left->end(), vecLeft, left_dist, getSnapperTolerance(), &DistributionSnapper::distLeft)) { + if (_findSidewaysSnaps(*bbox_to_snap, _bboxes_left->begin(), _bboxes_left->end(), vecLeft, left_dist, getSnapperTolerance(), &DistributionSnapper::distLeft)) { if (compare_double(left_dist, equal_dist)) { std::reverse(vecLeft.begin(), vecLeft.end()); vecRight.insert(vecRight.begin(), vecLeft.begin(), vecLeft.end()); @@ -298,10 +434,9 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is // if there is a snap then add left bboxes and right left, if there is a snap to the right then // add those bboxes too if (consider_x && !snap_x && _bboxes_left->size() > 0) { - auto first_dist = distLeft(*bbox_to_snap, _bboxes_left->front()); - vecLeft.clear(); - if (findSidewaysSnaps(*bbox_to_snap, _bboxes_left->begin(), _bboxes_left->end(), vecLeft, equal_dist, getSnapperTolerance(), &DistributionSnapper::distLeft)) { + if (_findSidewaysSnaps(*bbox_to_snap, _bboxes_left->begin(), _bboxes_left->end(), vecLeft, equal_dist, getSnapperTolerance(), &DistributionSnapper::distLeft)) { + auto first_dist = distLeft(*bbox_to_snap, vecLeft.front()); Geom::Coord offset = first_dist - equal_dist; Geom::Point target = bbox_to_snap->midpoint() - Geom::Point(offset, 0); @@ -317,7 +452,7 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is first_dist = distRight(bbox, _bboxes_right->front()); Geom::Coord right_dist; vecRight.clear(); - if (findSidewaysSnaps(*bbox_to_snap, _bboxes_right->begin(), _bboxes_right->end(), vecRight, right_dist, getSnapperTolerance(), &DistributionSnapper::distRight)) { + if (_findSidewaysSnaps(*bbox_to_snap, _bboxes_right->begin(), _bboxes_right->end(), vecRight, right_dist, getSnapperTolerance(), &DistributionSnapper::distRight)) { if (compare_double(right_dist, equal_dist)) { vecLeft.insert(vecLeft.end(), vecRight.begin(), vecRight.end()); } @@ -358,9 +493,8 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is std::vector vecUp; std::vector vecDown; if (consider_y && _bboxes_up->size() > 0) { - auto first_dist = distUp(*bbox_to_snap, _bboxes_up->front()); - - if (findSidewaysSnaps(*bbox_to_snap, _bboxes_up->begin(), _bboxes_up->end(), vecUp, equal_dist, getSnapperTolerance(), &DistributionSnapper::distUp)) { + if (_findSidewaysSnaps(*bbox_to_snap, _bboxes_up->begin(), _bboxes_up->end(), vecUp, equal_dist, getSnapperTolerance(), &DistributionSnapper::distUp)) { + auto first_dist = distUp(*bbox_to_snap, vecUp.front()); Geom::Coord offset = first_dist - equal_dist; Geom::Point target = bbox_to_snap->midpoint() - Geom::Point(0, offset); @@ -376,7 +510,7 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is first_dist = distDown(bbox, _bboxes_down->front()); Geom::Coord down_dist; vecDown.clear(); - if (findSidewaysSnaps(*bbox_to_snap, _bboxes_down->begin(), _bboxes_down->end(), vecDown, down_dist, + if (_findSidewaysSnaps(*bbox_to_snap, _bboxes_down->begin(), _bboxes_down->end(), vecDown, down_dist, getSnapperTolerance(), &DistributionSnapper::distDown)) { if (abs(down_dist - equal_dist) < 1e-4) { vecUp.insert(vecUp.end(), vecDown.begin(), vecDown.end()); @@ -397,10 +531,9 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is // if there is a snap then add bottom bboxes and look Up, if there is a snap above then // add those bboxes too if (consider_y && !snap_y && _bboxes_down->size() > 0) { - auto first_dist = distDown(*bbox_to_snap, _bboxes_down->front()); - vecDown.clear(); - if (findSidewaysSnaps(*bbox_to_snap, _bboxes_down->begin(), _bboxes_down->end(), vecDown, equal_dist, getSnapperTolerance(), &DistributionSnapper::distDown)) { + if (_findSidewaysSnaps(*bbox_to_snap, _bboxes_down->begin(), _bboxes_down->end(), vecDown, equal_dist, getSnapperTolerance(), &DistributionSnapper::distDown)) { + auto first_dist = distDown(*bbox_to_snap, vecDown.front()); Geom::Coord offset = first_dist - equal_dist; Geom::Point target = bbox_to_snap->midpoint() + Geom::Point(0, offset); @@ -416,7 +549,7 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is Geom::Coord up_dist; vecUp.clear(); - if (findSidewaysSnaps(*bbox_to_snap, _bboxes_up->begin(), _bboxes_up->end(), vecUp, up_dist, getSnapperTolerance(), &DistributionSnapper::distUp)) { + if (_findSidewaysSnaps(*bbox_to_snap, _bboxes_up->begin(), _bboxes_up->end(), vecUp, up_dist, getSnapperTolerance(), &DistributionSnapper::distUp)) { if (compare_double(up_dist, equal_dist)) { std::reverse(vecUp.begin(), vecUp.end()); vecDown.insert(vecDown.begin(), vecUp.begin(), vecUp.end()); diff --git a/src/distribution-snapper.h b/src/distribution-snapper.h index 0e094509c2..f5ce46cf11 100644 --- a/src/distribution-snapper.h +++ b/src/distribution-snapper.h @@ -112,7 +112,7 @@ private: * @param a function pointer to the distance function * @param level of recursion - do not pass this while calling the function */ - bool findSidewaysSnaps(Geom::Coord first_dist, + bool _findSidewaysSnaps(Geom::Rect const &source_bbox, std::vector::iterator it, std::vector::iterator end, std::vector &vec, @@ -121,6 +121,13 @@ private: std::function const & distance_func, int level = 0) const; + /** This functions adds overlapping bounding boxes to the list of bounding boxes. + * The new bounding boxes are added such that the final list is still sorted. + * This extra step is needed so that the overall union of any overlapping bounding + * boxes is also considered during distribution snapping. + */ + void _addBBoxForIntersectingBoxes() const; + // distance functions for different orientations static Geom::Coord distRight(Geom::Rect const &a, Geom::Rect const &b); static Geom::Coord distLeft(Geom::Rect const &a, Geom::Rect const &b); -- GitLab From 78ebba7b07a4aae15d5f6f2b5e6bd70b0b9fab75 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Sun, 27 Jun 2021 20:42:29 +0530 Subject: [PATCH 51/66] recursively search for snaps on each level --- src/distribution-snapper.cpp | 54 +++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/src/distribution-snapper.cpp b/src/distribution-snapper.cpp index 77ae1ca636..e86b3c5043 100644 --- a/src/distribution-snapper.cpp +++ b/src/distribution-snapper.cpp @@ -110,6 +110,7 @@ bool Inkscape::DistributionSnapper::_findSidewaysSnaps( int max_length = 0; // check each consecutive box for a snap + Geom::Rect optimum_start; while (std::next(next_bbox) != end) { auto first_dist = distance_func(source_bbox, *next_bbox); level = 0; @@ -120,20 +121,16 @@ bool Inkscape::DistributionSnapper::_findSidewaysSnaps( if (result->size() > max_length) { // if this item has the most number of items equidistant form each other // then make this the final result + optimum_start = *next_bbox; max_length = result->size(); vec = *result; dist = first_dist; - } else { - // delete the result - result->clear(); - delete result; } - } else { - // delete the result - result->clear(); - delete result; } + result->clear(); + delete result; + ++next_bbox; } @@ -142,8 +139,11 @@ bool Inkscape::DistributionSnapper::_findSidewaysSnaps( if (max_length == 0) { vec.push_back(*_next_bbox); return false; + } else { + // insert the first item to the list, this does not happen automatically if level==1 (see below) + vec.insert(vec.begin(), optimum_start); + return true; } - return true; } // if not the zeroth level @@ -153,24 +153,46 @@ bool Inkscape::DistributionSnapper::_findSidewaysSnaps( if (it == end) return true; + int og_level = level; + std::vector best_result; + int max_length = 0; while (next_bbox != end) { + level = og_level; + Geom::Coord this_dist; Geom::Coord next_dist = distance_func(source_bbox, *next_bbox); + auto result = new std::vector; if (level == 1 && compare_double(dist, next_dist, tol)){ // if this is the first level, check if the snap is within tolerance // we cancel here if the possible snap in not whithing tolerance, saves us some time! - dist = next_dist; - vec.push_back(source_bbox); - return _findSidewaysSnaps(*next_bbox, ++it, end, vec, dist, tol, distance_func, ++level); - } else if (compare_double(dist, next_dist)) { - return _findSidewaysSnaps(*next_bbox, ++it, end, vec, dist, tol, distance_func, ++level); + this_dist = next_dist; + if (_findSidewaysSnaps(*next_bbox, ++it, end, *result, this_dist, tol, distance_func, ++level)) { + if (result->size() > max_length) { + max_length = result->size(); + dist = this_dist; + best_result = *result; + } + } + result->clear(); + delete result; + + } else if (compare_double(dist, next_dist, level * DISTRIBUTION_SNAPPING_EPSILON)) { + + if (_findSidewaysSnaps(*next_bbox, ++it, end, *result, dist, tol, distance_func, ++level)) { + if (result->size() > max_length) { + max_length = result->size(); + best_result = *result; + } + } + result->clear(); + delete result; } ++next_bbox; } - // once reach the end, return false if level == 1, as there is just one(or more in case of overlap) item to that side. - return level != 1; + vec.insert(vec.end(), best_result.begin(), best_result.end()); + return true; } Inkscape::DistributionSnapper::DistributionSnapper(SnapManager *sm, Geom::Coord const d) -- GitLab From 3bbf79f05a85413264b2c879584cde17cefb4840 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Mon, 28 Jun 2021 11:29:40 +0530 Subject: [PATCH 52/66] minor improvements to snap-indicators --- src/display/control/snap-indicator.cpp | 38 ++++++++++++++------------ src/ui/dialog/inkscape-preferences.cpp | 2 +- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index 2fa26b2279..7d6b62eaf3 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -32,8 +32,6 @@ #include "ui/tools/measure-tool.h" -#define ALIGNMENT_GUIDE_MEASURE_OFFSET 15 - namespace Inkscape { namespace Display { @@ -105,6 +103,8 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap // Besides, negatives values would ....? } + // TODO: should this be a constant or a separate prefrence + // we are using the preference of measure tool here. double fontsize = prefs->getDouble("/tools/measure/fontsize", 10.0); if (is_distribution) { @@ -318,13 +318,13 @@ Geom::Coord get_x(Geom::Rect const &source, Geom::Rect const &target) void SnapIndicator::make_alignment_indicator(Geom::Point const &p1, Geom::Point const &p2, guint32 color, double fontsize, double scale) { Preferences *prefs = Preferences::get(); - bool show_distance = prefs->getBool("/options/snapindicatordistance/value", true); + bool show_distance = prefs->getBool("/options/snapindicatordistance/value", false); Inkscape::CanvasItemCurve *line; if (show_distance) { auto dist = Geom::L2(p2 - p1); - double offset = ALIGNMENT_GUIDE_MEASURE_OFFSET/_desktop->current_zoom(); + double offset = (fontsize + 5)/_desktop->current_zoom(); auto direction = Geom::unit_vector(p1 - p2); auto text_pos = (p1 + p2)/2; @@ -377,7 +377,7 @@ void SnapIndicator::make_alignment_indicator(Geom::Point const &p1, Geom::Point Inkscape::CanvasItemCurve* SnapIndicator::make_stub_line_v(Geom::Point const & p) { - Geom::Coord length = 20; + Geom::Coord length = 10/_desktop->current_zoom(); auto line = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p + Geom::Point(0, length/2), p - Geom::Point(0, length/2)); line->set_stroke(0xff5f1fff); return line; @@ -385,7 +385,7 @@ Inkscape::CanvasItemCurve* SnapIndicator::make_stub_line_v(Geom::Point const & p Inkscape::CanvasItemCurve* SnapIndicator::make_stub_line_h(Geom::Point const & p) { - Geom::Coord length = 20; + Geom::Coord length = 10/_desktop->current_zoom(); auto line = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p + Geom::Point(length/2, 0), p - Geom::Point(length/2, 0)); line->set_stroke(0xff5f1fff); return line; @@ -402,6 +402,8 @@ void SnapIndicator::make_distribution_indicators(SnappedPoint const &p, guint32 text_fill = 0xffffffff; guint32 text_bg = 0xff5f1fff; //0x33337f7f Geom::Point text_pos; + double text_offset = (fontsize * 2); + double line_offset = 5/_desktop->current_zoom(); Glib::ustring unit_name = _desktop->doc()->getDisplayUnit()->abbr.c_str(); if (!unit_name.compare("")) { @@ -427,9 +429,9 @@ void SnapIndicator::make_distribution_indicators(SnappedPoint const &p, case SNAPTARGET_DISTRIBUTION_LEFT: case SNAPTARGET_DISTRIBUTION_X: y = get_y(*it,*std::next(it)); - p1 = Geom::Point(it->max().x(), y); - p2 = Geom::Point(std::next(it)->min().x(), y); - text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(0, -2*fontsize)); + p1 = Geom::Point(it->max().x() + line_offset, y); + p2 = Geom::Point(std::next(it)->min().x() - line_offset, y); + text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(0, -text_offset)); point1 = make_stub_line_v(p1); point2 = make_stub_line_v(p2); @@ -439,9 +441,9 @@ void SnapIndicator::make_distribution_indicators(SnappedPoint const &p, case SNAPTARGET_DISTRIBUTION_UP: case SNAPTARGET_DISTRIBUTION_Y: x = get_x(*it,*std::next(it)); - p1 = Geom::Point(x, it->max().y()); - p2 = Geom::Point(x, std::next(it)->min().y()); - text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(-2*fontsize, 0)); + p1 = Geom::Point(x, it->max().y() + line_offset); + p2 = Geom::Point(x, std::next(it)->min().y() - line_offset); + text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(-text_offset, 0)); point1 = make_stub_line_h(p1); point2 = make_stub_line_h(p2); @@ -476,9 +478,9 @@ void SnapIndicator::make_distribution_indicators(SnappedPoint const &p, for (auto it = p.getBBoxes().begin(); it + 1 != p.getBBoxes().end(); it++) { y = get_y(*it,*std::next(it)); - p1 = Geom::Point(it->max().x(), y); - p2 = Geom::Point(std::next(it)->min().x(), y); - text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(0, -2*fontsize)); + p1 = Geom::Point(it->max().x() + line_offset, y); + p2 = Geom::Point(std::next(it)->min().x() - line_offset, y); + text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(0, -text_offset)); point1 = make_stub_line_v(p1); point2 = make_stub_line_v(p2); @@ -502,9 +504,9 @@ void SnapIndicator::make_distribution_indicators(SnappedPoint const &p, for (auto it = p.getBBoxes2().begin(); it + 1 != p.getBBoxes2().end(); it++) { x = get_x(*it,*std::next(it)); - p1 = Geom::Point(x, it->max().y()); - p2 = Geom::Point(x, std::next(it)->min().y()); - text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(-2*fontsize, 0)); + p1 = Geom::Point(x, it->max().y() + line_offset); + p2 = Geom::Point(x, std::next(it)->min().y() - line_offset); + text_pos = (p1 + p2)/2 + _desktop->w2d(Geom::Point(-text_offset, 0)); point1 = make_stub_line_h(p1); point2 = make_stub_line_h(p2); diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp index 6ad8a64fc2..b07e1f2a46 100644 --- a/src/ui/dialog/inkscape-preferences.cpp +++ b/src/ui/dialog/inkscape-preferences.cpp @@ -2390,7 +2390,7 @@ void InkscapePreferences::initPageBehavior() _page_snapping.add_group_header( _("Intelligent Snapping")); - _snap_indicator_distance.init( _("Show snap distance in case of alignment or distribution snap"), "/options/snapindicatordistance/value", true); + _snap_indicator_distance.init( _("Show snap distance in case of alignment or distribution snap"), "/options/snapindicatordistance/value", false); _page_snapping.add_line( true, "", _snap_indicator_distance, "", _("Show snap distance in case of alignment or distribution snap")); -- GitLab From 8a62ede942b805555c99206023f05e57a066245f Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Mon, 28 Jun 2021 12:03:44 +0530 Subject: [PATCH 53/66] make target and source name maps static members of SnapIndicators main reason for doing this was to use out-of-line definition to keep all the translatable string in the .cpp file --- src/display/control/snap-indicator.cpp | 60 +++++++++++++++++++++++++ src/display/control/snap-indicator.h | 61 +------------------------- 2 files changed, 62 insertions(+), 59 deletions(-) diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index 7d6b62eaf3..f435085218 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -35,6 +35,66 @@ namespace Inkscape { namespace Display { +std::unordered_map SnapIndicator::source2string = { + {SNAPSOURCE_UNDEFINED, _("UNDEFINED")}, + {SNAPSOURCE_BBOX_CORNER, _("Bounding box corner")}, + {SNAPSOURCE_BBOX_MIDPOINT, _("Bounding box midpoint")}, + {SNAPSOURCE_BBOX_EDGE_MIDPOINT, _("Bounding box side midpoint")}, + {SNAPSOURCE_NODE_SMOOTH, _("Smooth node")}, + {SNAPSOURCE_NODE_CUSP, _("Cusp node")}, + {SNAPSOURCE_LINE_MIDPOINT, _("Line midpoint")}, + {SNAPSOURCE_PATH_INTERSECTION, _("Path intersection")}, + {SNAPSOURCE_RECT_CORNER, _("Corner")}, + {SNAPSOURCE_CONVEX_HULL_CORNER, _("Convex hull corner")}, + {SNAPSOURCE_ELLIPSE_QUADRANT_POINT, _("Quadrant point")}, + {SNAPSOURCE_NODE_HANDLE, _("Handle")}, + {SNAPSOURCE_GUIDE, _("Guide")}, + {SNAPSOURCE_GUIDE_ORIGIN, _("Guide origin")}, + {SNAPSOURCE_ROTATION_CENTER, _("Object rotation center")}, + {SNAPSOURCE_OBJECT_MIDPOINT, _("Object midpoint")}, + {SNAPSOURCE_IMG_CORNER, _("Corner")}, + {SNAPSOURCE_TEXT_ANCHOR, _("Text anchor")}, + {SNAPSOURCE_OTHER_HANDLE, _("Handle")}, + {SNAPSOURCE_GRID_PITCH, _("Multiple of grid spacing")}, +}; + +std::unordered_map SnapIndicator::target2string = { + {SNAPTARGET_UNDEFINED, _("UNDEFINED")}, + {SNAPTARGET_BBOX_CORNER, _("bounding box corner")}, + {SNAPTARGET_BBOX_EDGE, _("bounding box side")}, + {SNAPTARGET_BBOX_EDGE_MIDPOINT, _("bounding box side midpoint")}, + {SNAPTARGET_BBOX_MIDPOINT, _("bounding box midpoint")}, + {SNAPTARGET_NODE_SMOOTH, _("smooth node")}, + {SNAPTARGET_NODE_CUSP, _("cusp node")}, + {SNAPTARGET_LINE_MIDPOINT, _("line midpoint")}, + {SNAPTARGET_PATH, _("path")}, + {SNAPTARGET_PATH_PERPENDICULAR, _("path (perpendicular)")}, + {SNAPTARGET_PATH_TANGENTIAL, _("path (tangential)")}, + {SNAPTARGET_PATH_INTERSECTION, _("path intersection")}, + {SNAPTARGET_PATH_GUIDE_INTERSECTION, _("guide-path intersection")}, + {SNAPTARGET_PATH_CLIP, _("clip-path")}, + {SNAPTARGET_PATH_MASK, _("mask-path")}, + {SNAPTARGET_ELLIPSE_QUADRANT_POINT, _("quadrant point")}, + {SNAPTARGET_RECT_CORNER, _("corner")}, + {SNAPTARGET_GRID, _("grid line")}, + {SNAPTARGET_GRID_INTERSECTION, _("grid intersection")}, + {SNAPTARGET_GRID_PERPENDICULAR, _("grid line (perpendicular)")}, + {SNAPTARGET_GUIDE, _("guide")}, + {SNAPTARGET_GUIDE_INTERSECTION, _("guide intersection")}, + {SNAPTARGET_GUIDE_ORIGIN, _("guide origin")}, + {SNAPTARGET_GUIDE_PERPENDICULAR, _("guide (perpendicular)")}, + {SNAPTARGET_GRID_GUIDE_INTERSECTION, _("grid-guide intersection")}, + {SNAPTARGET_PAGE_BORDER, _("page border")}, + {SNAPTARGET_PAGE_CORNER, _("page corner")}, + {SNAPTARGET_OBJECT_MIDPOINT, _("object midpoint")}, + {SNAPTARGET_IMG_CORNER, _("corner")}, + {SNAPTARGET_ROTATION_CENTER, _("object rotation center")}, + {SNAPTARGET_TEXT_ANCHOR, _("text anchor")}, + {SNAPTARGET_TEXT_BASELINE, _("text baseline")}, + {SNAPTARGET_CONSTRAINED_ANGLE, _("constrained angle")}, + {SNAPTARGET_CONSTRAINT, _("constraint")}, +}; + SnapIndicator::SnapIndicator(SPDesktop * desktop) : _snaptarget(nullptr), _snaptarget_tooltip(nullptr), diff --git a/src/display/control/snap-indicator.h b/src/display/control/snap-indicator.h index 271c6a9cb2..76d083aeed 100644 --- a/src/display/control/snap-indicator.h +++ b/src/display/control/snap-indicator.h @@ -68,65 +68,8 @@ private: Inkscape::CanvasItemCurve* make_stub_line_h(Geom::Point const &p); Inkscape::CanvasItemCurve* make_stub_line_v(Geom::Point const &p); - std::unordered_map source2string = { - {SNAPSOURCE_UNDEFINED, _("UNDEFINED")}, - {SNAPSOURCE_BBOX_CORNER, _("Bounding box corner")}, - {SNAPSOURCE_BBOX_MIDPOINT, _("Bounding box midpoint")}, - {SNAPSOURCE_BBOX_EDGE_MIDPOINT, _("Bounding box side midpoint")}, - {SNAPSOURCE_NODE_SMOOTH, _("Smooth node")}, - {SNAPSOURCE_NODE_CUSP, _("Cusp node")}, - {SNAPSOURCE_LINE_MIDPOINT, _("Line midpoint")}, - {SNAPSOURCE_PATH_INTERSECTION, _("Path intersection")}, - {SNAPSOURCE_RECT_CORNER, _("Corner")}, - {SNAPSOURCE_CONVEX_HULL_CORNER, _("Convex hull corner")}, - {SNAPSOURCE_ELLIPSE_QUADRANT_POINT, _("Quadrant point")}, - {SNAPSOURCE_NODE_HANDLE, _("Handle")}, - {SNAPSOURCE_GUIDE, _("Guide")}, - {SNAPSOURCE_GUIDE_ORIGIN, _("Guide origin")}, - {SNAPSOURCE_ROTATION_CENTER, _("Object rotation center")}, - {SNAPSOURCE_OBJECT_MIDPOINT, _("Object midpoint")}, - {SNAPSOURCE_IMG_CORNER, _("Corner")}, - {SNAPSOURCE_TEXT_ANCHOR, _("Text anchor")}, - {SNAPSOURCE_OTHER_HANDLE, _("Handle")}, - {SNAPSOURCE_GRID_PITCH, _("Multiple of grid spacing")}, - }; - - std::unordered_map target2string = { - {SNAPTARGET_UNDEFINED, _("UNDEFINED")}, - {SNAPTARGET_BBOX_CORNER, _("bounding box corner")}, - {SNAPTARGET_BBOX_EDGE, _("bounding box side")}, - {SNAPTARGET_BBOX_EDGE_MIDPOINT, _("bounding box side midpoint")}, - {SNAPTARGET_BBOX_MIDPOINT, _("bounding box midpoint")}, - {SNAPTARGET_NODE_SMOOTH, _("smooth node")}, - {SNAPTARGET_NODE_CUSP, _("cusp node")}, - {SNAPTARGET_LINE_MIDPOINT, _("line midpoint")}, - {SNAPTARGET_PATH, _("path")}, - {SNAPTARGET_PATH_PERPENDICULAR, _("path (perpendicular)")}, - {SNAPTARGET_PATH_TANGENTIAL, _("path (tangential)")}, - {SNAPTARGET_PATH_INTERSECTION, _("path intersection")}, - {SNAPTARGET_PATH_GUIDE_INTERSECTION, _("guide-path intersection")}, - {SNAPTARGET_PATH_CLIP, _("clip-path")}, - {SNAPTARGET_PATH_MASK, _("mask-path")}, - {SNAPTARGET_ELLIPSE_QUADRANT_POINT, _("quadrant point")}, - {SNAPTARGET_RECT_CORNER, _("corner")}, - {SNAPTARGET_GRID, _("grid line")}, - {SNAPTARGET_GRID_INTERSECTION, _("grid intersection")}, - {SNAPTARGET_GRID_PERPENDICULAR, _("grid line (perpendicular)")}, - {SNAPTARGET_GUIDE, _("guide")}, - {SNAPTARGET_GUIDE_INTERSECTION, _("guide intersection")}, - {SNAPTARGET_GUIDE_ORIGIN, _("guide origin")}, - {SNAPTARGET_GUIDE_PERPENDICULAR, _("guide (perpendicular)")}, - {SNAPTARGET_GRID_GUIDE_INTERSECTION, _("grid-guide intersection")}, - {SNAPTARGET_PAGE_BORDER, _("page border")}, - {SNAPTARGET_PAGE_CORNER, _("page corner")}, - {SNAPTARGET_OBJECT_MIDPOINT, _("object midpoint")}, - {SNAPTARGET_IMG_CORNER, _("corner")}, - {SNAPTARGET_ROTATION_CENTER, _("object rotation center")}, - {SNAPTARGET_TEXT_ANCHOR, _("text anchor")}, - {SNAPTARGET_TEXT_BASELINE, _("text baseline")}, - {SNAPTARGET_CONSTRAINED_ANGLE, _("constrained angle")}, - {SNAPTARGET_CONSTRAINT, _("constraint")}, - }; + static std::unordered_map source2string; + static std::unordered_map target2string; }; } //namespace Display -- GitLab From 17dfcb8728740364126e4496521cf373859baa31 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Mon, 28 Jun 2021 18:19:22 +0530 Subject: [PATCH 54/66] made alignment guides bg width 3 and added a new member for that --- src/display/control/canvas-item-curve.cpp | 2 +- src/display/control/canvas-item-curve.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/display/control/canvas-item-curve.cpp b/src/display/control/canvas-item-curve.cpp index 3590551c0c..34372875c6 100644 --- a/src/display/control/canvas-item-curve.cpp +++ b/src/display/control/canvas-item-curve.cpp @@ -193,7 +193,7 @@ void CanvasItemCurve::render(Inkscape::CanvasItemBuffer *buf) } buf->cr->set_source_rgba(1.0, 1.0, 1.0, 0.5); - buf->cr->set_line_width(2); + buf->cr->set_line_width(background_width); buf->cr->stroke_preserve(); buf->cr->set_source_rgba(SP_RGBA32_R_F(_stroke), SP_RGBA32_G_F(_stroke), diff --git a/src/display/control/canvas-item-curve.h b/src/display/control/canvas-item-curve.h index aae4a804f0..dfa4d0df5b 100644 --- a/src/display/control/canvas-item-curve.h +++ b/src/display/control/canvas-item-curve.h @@ -63,6 +63,7 @@ protected: bool _is_fill = true; // Fill or stroke, used by meshes. int width = 1; + int background_width = 3; // this should be an odd number so that the background appears on both the sides of the curve. int _corner0 = -1; // For meshes int _corner1 = -1; // For meshes }; -- GitLab From ae06306521d24800748e339b1320370055393628 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Tue, 29 Jun 2021 11:09:20 +0530 Subject: [PATCH 55/66] Convert raw pointers to smart pointers in Object/Alignment/Distribution snappers --- src/alignment-snapper.cpp | 6 +++--- src/alignment-snapper.h | 3 ++- src/distribution-snapper.cpp | 16 +++++----------- src/distribution-snapper.h | 9 +++++---- src/object-snapper.cpp | 12 +++++------- src/object-snapper.h | 5 +++-- 6 files changed, 23 insertions(+), 28 deletions(-) diff --git a/src/alignment-snapper.cpp b/src/alignment-snapper.cpp index 05377294c0..db96327618 100644 --- a/src/alignment-snapper.cpp +++ b/src/alignment-snapper.cpp @@ -14,6 +14,7 @@ #include <2geom/line.h> #include <2geom/path-intersection.h> #include <2geom/path-sink.h> +#include #include "desktop.h" #include "display/curve.h" @@ -41,13 +42,12 @@ Inkscape::AlignmentSnapper::AlignmentSnapper(SnapManager *sm, Geom::Coord const d) : Snapper(sm, d) { - _points_to_snap_to = new std::vector; + _points_to_snap_to = std::make_unique>(); } Inkscape::AlignmentSnapper::~AlignmentSnapper() { _points_to_snap_to->clear(); - delete _points_to_snap_to; } void Inkscape::AlignmentSnapper::_collectBBoxPoints(bool const &first_point) const @@ -88,7 +88,7 @@ void Inkscape::AlignmentSnapper::_collectBBoxPoints(bool const &first_point) con // if candidate is not a clip or a mask object then extract its BBox points if (!candidate.clip_or_mask) { Geom::OptRect b = root_item->desktopBounds(bbox_type); - getBBoxPoints(b, _points_to_snap_to, true, true, false, true, true); + getBBoxPoints(b, _points_to_snap_to.get(), true, true, false, true, true); } } diff --git a/src/alignment-snapper.h b/src/alignment-snapper.h index c7a3c27c76..30d3de515d 100644 --- a/src/alignment-snapper.h +++ b/src/alignment-snapper.h @@ -12,6 +12,7 @@ #define SEEN_ALIGNMENT_SNAPPER_H #include <2geom/affine.h> +#include #include "snap-enums.h" #include "snapper.h" @@ -63,7 +64,7 @@ public: std::vector *unselected_nodes) const override; private: - std::vector *_points_to_snap_to; + std::unique_ptr> _points_to_snap_to; /** Collects and caches points on bounding boxes of the candidates * @param is the point first point in the selection? diff --git a/src/distribution-snapper.cpp b/src/distribution-snapper.cpp index e86b3c5043..ccf69ca6ae 100644 --- a/src/distribution-snapper.cpp +++ b/src/distribution-snapper.cpp @@ -14,6 +14,7 @@ #include <2geom/line.h> #include <2geom/path-intersection.h> #include <2geom/path-sink.h> +#include #include "desktop.h" #include "display/curve.h" @@ -198,25 +199,18 @@ bool Inkscape::DistributionSnapper::_findSidewaysSnaps( Inkscape::DistributionSnapper::DistributionSnapper(SnapManager *sm, Geom::Coord const d) : Snapper(sm, d) { - _bboxes_right = new std::vector; - _bboxes_left = new std::vector; - _bboxes_up = new std::vector; - _bboxes_down = new std::vector; + _bboxes_right = std::make_unique>(); + _bboxes_left = std::make_unique>(); + _bboxes_up = std::make_unique>(); + _bboxes_down = std::make_unique>(); } Inkscape::DistributionSnapper::~DistributionSnapper() { _bboxes_right->clear(); - delete _bboxes_right; - _bboxes_left->clear(); - delete _bboxes_left; - _bboxes_up->clear(); - delete _bboxes_up; - _bboxes_down->clear(); - delete _bboxes_down; } void Inkscape::DistributionSnapper::_collectBBoxes(Geom::OptRect const &bbox_to_snap, bool const &first_point) const diff --git a/src/distribution-snapper.h b/src/distribution-snapper.h index f5ce46cf11..a3042e92e3 100644 --- a/src/distribution-snapper.h +++ b/src/distribution-snapper.h @@ -12,6 +12,7 @@ #define SEEN_DISTRIBUTION_SNAPPER_H #include <2geom/affine.h> +#include #include "snap-enums.h" #include "snapper.h" @@ -63,10 +64,10 @@ public: std::vector *unselected_nodes) const override; private: - std::vector *_bboxes_left; - std::vector *_bboxes_right; - std::vector *_bboxes_down; - std::vector *_bboxes_up; + std::unique_ptr> _bboxes_left; + std::unique_ptr> _bboxes_right; + std::unique_ptr> _bboxes_down; + std::unique_ptr> _bboxes_up; /** Collects and caches bounding boxes to the left, right, up, and down of the * selected object. diff --git a/src/object-snapper.cpp b/src/object-snapper.cpp index cca1690d0c..67083e1e14 100644 --- a/src/object-snapper.cpp +++ b/src/object-snapper.cpp @@ -17,6 +17,7 @@ #include <2geom/line.h> #include <2geom/path-intersection.h> #include <2geom/path-sink.h> +#include #include "desktop.h" #include "display/curve.h" @@ -44,17 +45,14 @@ Inkscape::ObjectSnapper::ObjectSnapper(SnapManager *sm, Geom::Coord const d) : Snapper(sm, d) { - _points_to_snap_to = new std::vector; - _paths_to_snap_to = new std::vector; + _points_to_snap_to = std::make_unique>(); + _paths_to_snap_to = std::make_unique>(); } Inkscape::ObjectSnapper::~ObjectSnapper() { _points_to_snap_to->clear(); - delete _points_to_snap_to; - _clear_paths(); - delete _paths_to_snap_to; } Geom::Coord Inkscape::ObjectSnapper::getSnapperTolerance() const @@ -99,7 +97,7 @@ void Inkscape::ObjectSnapper::_collectNodes(SnapSourceType const &t, // Consider the page border for snapping to if (_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_PAGE_CORNER)) { - _getBorderNodes(_points_to_snap_to); + _getBorderNodes(_points_to_snap_to.get()); } for (const auto & _candidate : *_snapmanager->obj_snapper_candidates) { @@ -168,7 +166,7 @@ void Inkscape::ObjectSnapper::_collectNodes(SnapSourceType const &t, // of the item AND the bbox of the clipping path at the same time if (!_candidate.clip_or_mask) { Geom::OptRect b = root_item->desktopBounds(bbox_type); - getBBoxPoints(b, _points_to_snap_to, true, + getBBoxPoints(b, _points_to_snap_to.get(), true, _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_BBOX_CORNER), _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_BBOX_EDGE_MIDPOINT), _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_BBOX_MIDPOINT)); diff --git a/src/object-snapper.h b/src/object-snapper.h index 8e5c3d16c9..b0b55ede55 100644 --- a/src/object-snapper.h +++ b/src/object-snapper.h @@ -11,6 +11,7 @@ * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ +#include #include "snapper.h" #include "snap-candidate.h" @@ -60,8 +61,8 @@ public: std::vector *unselected_nodes) const override; private: - std::vector *_points_to_snap_to; - std::vector *_paths_to_snap_to; + std::unique_ptr> _points_to_snap_to; + std::unique_ptr> _paths_to_snap_to; void _snapNodes(IntermSnapResults &isr, Inkscape::SnapCandidatePoint const &p, // in desktop coordinates -- GitLab From 3f21399f9ec1b6f4e279a9651055e2afae062013 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Tue, 29 Jun 2021 16:55:58 +0530 Subject: [PATCH 56/66] add outline to alignment indicators --- src/display/control/canvas-item-curve.cpp | 12 +++++++- src/display/control/canvas-item-curve.h | 2 ++ src/display/control/snap-indicator.cpp | 37 +++++++++++++---------- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/display/control/canvas-item-curve.cpp b/src/display/control/canvas-item-curve.cpp index 34372875c6..e8ff9d325b 100644 --- a/src/display/control/canvas-item-curve.cpp +++ b/src/display/control/canvas-item-curve.cpp @@ -94,6 +94,16 @@ void CanvasItemCurve::set_width(int w) request_update(); } +/** + * Set background stroke alpha. + */ +void CanvasItemCurve::set_bg_alpha(float alpha) +{ + bg_alpha = alpha; + + request_update(); +} + /** * Returns distance between point in canvas units and nearest point on curve. */ @@ -192,7 +202,7 @@ void CanvasItemCurve::render(Inkscape::CanvasItemBuffer *buf) buf->cr->curve_to(curve[1].x(), curve[1].y(), curve[2].x(), curve[2].y(), curve[3].x(), curve[3].y()); } - buf->cr->set_source_rgba(1.0, 1.0, 1.0, 0.5); + buf->cr->set_source_rgba(1.0, 1.0, 1.0, bg_alpha); buf->cr->set_line_width(background_width); buf->cr->stroke_preserve(); diff --git a/src/display/control/canvas-item-curve.h b/src/display/control/canvas-item-curve.h index dfa4d0df5b..84d6511b4a 100644 --- a/src/display/control/canvas-item-curve.h +++ b/src/display/control/canvas-item-curve.h @@ -39,6 +39,7 @@ public: void set_coords(Geom::Point const &p0, Geom::Point const &p1, Geom::Point const &p2, Geom::Point const &p3); void set(Geom::BezierCurve &curve); void set_width(int w); + void set_bg_alpha(float alpha); bool is_line() { return _curve->size() == 2; } void update(Geom::Affine const &affine) override; @@ -64,6 +65,7 @@ protected: int width = 1; int background_width = 3; // this should be an odd number so that the background appears on both the sides of the curve. + float bg_alpha = 0.5f; int _corner0 = -1; // For meshes int _corner1 = -1; // For meshes }; diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index f435085218..1e57255cf6 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -382,6 +382,24 @@ void SnapIndicator::make_alignment_indicator(Geom::Point const &p1, Geom::Point Inkscape::CanvasItemCurve *line; + auto ctrl = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); + ctrl->set_size(6); + ctrl->set_mode(Inkscape::CanvasItemCtrlMode::CANVAS_ITEM_CTRL_MODE_COLOR); + ctrl->set_stroke(0xffffffff); + ctrl->set_fill(color); + ctrl->set_position(p1); + ctrl->set_pickable(false); + _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl, 0)); + + ctrl = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); + ctrl->set_size(6); + ctrl->set_mode(Inkscape::CanvasItemCtrlMode::CANVAS_ITEM_CTRL_MODE_COLOR); + ctrl->set_stroke(0xffffffff); + ctrl->set_fill(color); + ctrl->set_position(p2); + ctrl->set_pickable(false); + _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl, 0)); + if (show_distance) { auto dist = Geom::L2(p2 - p1); double offset = (fontsize + 5)/_desktop->current_zoom(); @@ -406,33 +424,20 @@ void SnapIndicator::make_alignment_indicator(Geom::Point const &p1, Geom::Point auto temp_point = text_pos + offset*direction; line = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p1, temp_point); line->set_stroke(color); + line->set_bg_alpha(1.0f); _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line, 0)); temp_point = text_pos - offset*direction; line = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), temp_point, p2); line->set_stroke(color); + line->set_bg_alpha(1.0f); _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line, 0)); } else { line = new Inkscape::CanvasItemCurve(_desktop->getCanvasTemp(), p1, p2); line->set_stroke(color); + line->set_bg_alpha(1.0f); _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(line, 0)); } - - auto ctrl = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); - ctrl->set_size(7); - ctrl->set_stroke(color); - ctrl->set_fill(color); - ctrl->set_position(p1); - ctrl->set_pickable(false); - _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl, 0)); - - ctrl = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); - ctrl->set_size(7); - ctrl->set_stroke(color); - ctrl->set_fill(color); - ctrl->set_position(p2); - ctrl->set_pickable(false); - _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl, 0)); } Inkscape::CanvasItemCurve* SnapIndicator::make_stub_line_v(Geom::Point const & p) -- GitLab From 09e514d809d5c4d82e88623648428102d3a4b4f7 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Wed, 30 Jun 2021 12:14:03 +0530 Subject: [PATCH 57/66] fix selection bbox correction for bidirectional distribution snap --- src/distribution-snapper.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/distribution-snapper.cpp b/src/distribution-snapper.cpp index ccf69ca6ae..4ce9baeef3 100644 --- a/src/distribution-snapper.cpp +++ b/src/distribution-snapper.cpp @@ -607,7 +607,8 @@ void Inkscape::DistributionSnapper::_snapEquidistantPoints(IntermSnapResults &is std::vector bboxes_x = sx.getBBoxes(); std::vector bboxes_y = sy.getBBoxes(); - _correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); + // Do not need to correct here, already did that earlier for each direction separately + //_correctSelectionBBox(target, p.getPoint(), *bbox_to_snap); auto si = SnappedPoint(target, bboxes_x, bboxes_y, bbox, sx.getDistributionDistance(), sy.getDistributionDistance(), p.getSourceType(), p.getSourceNum(), SNAPTARGET_DISTRIBUTION_XY, offset, getSnapperTolerance(), getSnapperAlwaysSnap(), false, true); isr.points.push_back(si); return; -- GitLab From 50511e58f185801d930e8d90c494907898cf0a1c Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Wed, 30 Jun 2021 16:50:10 +0530 Subject: [PATCH 58/66] add icons --- .../scalable/actions/snap-alignment-self.svg | 138 ++++++++++++++++++ .../Tango/scalable/actions/snap-alignment.svg | 116 +++++++++++++++ .../scalable/actions/snap-distribution.svg | 89 +++++++++++ .../scalable/actions/snap-alignment-self.svg | 138 ++++++++++++++++++ .../scalable/actions/snap-alignment.svg | 116 +++++++++++++++ .../scalable/actions/snap-distribution.svg | 89 +++++++++++ .../actions/snap-alignment-self-symbolic.svg | 138 ++++++++++++++++++ .../actions/snap-alignment-symbolic.svg | 116 +++++++++++++++ .../actions/snap-distribution-symbolic.svg | 89 +++++++++++ .../actions/snap-alignment-self-symbolic.svg | 138 ++++++++++++++++++ .../actions/snap-alignment-symbolic.svg | 116 +++++++++++++++ .../actions/snap-distribution-symbolic.svg | 89 +++++++++++ share/ui/toolbar-snap.ui | 8 +- 13 files changed, 1376 insertions(+), 4 deletions(-) create mode 100644 share/icons/Tango/scalable/actions/snap-alignment-self.svg create mode 100644 share/icons/Tango/scalable/actions/snap-alignment.svg create mode 100644 share/icons/Tango/scalable/actions/snap-distribution.svg create mode 100644 share/icons/hicolor/scalable/actions/snap-alignment-self.svg create mode 100644 share/icons/hicolor/scalable/actions/snap-alignment.svg create mode 100644 share/icons/hicolor/scalable/actions/snap-distribution.svg create mode 100644 share/icons/hicolor/symbolic/actions/snap-alignment-self-symbolic.svg create mode 100644 share/icons/hicolor/symbolic/actions/snap-alignment-symbolic.svg create mode 100644 share/icons/hicolor/symbolic/actions/snap-distribution-symbolic.svg create mode 100644 share/icons/multicolor/symbolic/actions/snap-alignment-self-symbolic.svg create mode 100644 share/icons/multicolor/symbolic/actions/snap-alignment-symbolic.svg create mode 100644 share/icons/multicolor/symbolic/actions/snap-distribution-symbolic.svg diff --git a/share/icons/Tango/scalable/actions/snap-alignment-self.svg b/share/icons/Tango/scalable/actions/snap-alignment-self.svg new file mode 100644 index 0000000000..fc9d589259 --- /dev/null +++ b/share/icons/Tango/scalable/actions/snap-alignment-self.svg @@ -0,0 +1,138 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/share/icons/Tango/scalable/actions/snap-alignment.svg b/share/icons/Tango/scalable/actions/snap-alignment.svg new file mode 100644 index 0000000000..7971954611 --- /dev/null +++ b/share/icons/Tango/scalable/actions/snap-alignment.svg @@ -0,0 +1,116 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/share/icons/Tango/scalable/actions/snap-distribution.svg b/share/icons/Tango/scalable/actions/snap-distribution.svg new file mode 100644 index 0000000000..71f76eae89 --- /dev/null +++ b/share/icons/Tango/scalable/actions/snap-distribution.svg @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + diff --git a/share/icons/hicolor/scalable/actions/snap-alignment-self.svg b/share/icons/hicolor/scalable/actions/snap-alignment-self.svg new file mode 100644 index 0000000000..fc9d589259 --- /dev/null +++ b/share/icons/hicolor/scalable/actions/snap-alignment-self.svg @@ -0,0 +1,138 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/share/icons/hicolor/scalable/actions/snap-alignment.svg b/share/icons/hicolor/scalable/actions/snap-alignment.svg new file mode 100644 index 0000000000..7971954611 --- /dev/null +++ b/share/icons/hicolor/scalable/actions/snap-alignment.svg @@ -0,0 +1,116 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/share/icons/hicolor/scalable/actions/snap-distribution.svg b/share/icons/hicolor/scalable/actions/snap-distribution.svg new file mode 100644 index 0000000000..71f76eae89 --- /dev/null +++ b/share/icons/hicolor/scalable/actions/snap-distribution.svg @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + diff --git a/share/icons/hicolor/symbolic/actions/snap-alignment-self-symbolic.svg b/share/icons/hicolor/symbolic/actions/snap-alignment-self-symbolic.svg new file mode 100644 index 0000000000..f405486eae --- /dev/null +++ b/share/icons/hicolor/symbolic/actions/snap-alignment-self-symbolic.svg @@ -0,0 +1,138 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/share/icons/hicolor/symbolic/actions/snap-alignment-symbolic.svg b/share/icons/hicolor/symbolic/actions/snap-alignment-symbolic.svg new file mode 100644 index 0000000000..ecb3eec514 --- /dev/null +++ b/share/icons/hicolor/symbolic/actions/snap-alignment-symbolic.svg @@ -0,0 +1,116 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/share/icons/hicolor/symbolic/actions/snap-distribution-symbolic.svg b/share/icons/hicolor/symbolic/actions/snap-distribution-symbolic.svg new file mode 100644 index 0000000000..4b8ca7bb9a --- /dev/null +++ b/share/icons/hicolor/symbolic/actions/snap-distribution-symbolic.svg @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + diff --git a/share/icons/multicolor/symbolic/actions/snap-alignment-self-symbolic.svg b/share/icons/multicolor/symbolic/actions/snap-alignment-self-symbolic.svg new file mode 100644 index 0000000000..f405486eae --- /dev/null +++ b/share/icons/multicolor/symbolic/actions/snap-alignment-self-symbolic.svg @@ -0,0 +1,138 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/share/icons/multicolor/symbolic/actions/snap-alignment-symbolic.svg b/share/icons/multicolor/symbolic/actions/snap-alignment-symbolic.svg new file mode 100644 index 0000000000..ecb3eec514 --- /dev/null +++ b/share/icons/multicolor/symbolic/actions/snap-alignment-symbolic.svg @@ -0,0 +1,116 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/share/icons/multicolor/symbolic/actions/snap-distribution-symbolic.svg b/share/icons/multicolor/symbolic/actions/snap-distribution-symbolic.svg new file mode 100644 index 0000000000..4b8ca7bb9a --- /dev/null +++ b/share/icons/multicolor/symbolic/actions/snap-distribution-symbolic.svg @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + diff --git a/share/ui/toolbar-snap.ui b/share/ui/toolbar-snap.ui index 91e6cda415..42e6e55106 100644 --- a/share/ui/toolbar-snap.ui +++ b/share/ui/toolbar-snap.ui @@ -224,7 +224,7 @@ True doc.snap-alignment - snap + snap-alignment Alignment @@ -233,12 +233,12 @@ True doc.snap-alignment-self - snap + snap-alignment-self Self Alignment - + @@ -250,7 +250,7 @@ True doc.snap-distribution - snap + snap-distribution Distribution -- GitLab From ae0f39cee739d492b27a0dba4d3d6fbaff28f64f Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Wed, 30 Jun 2021 17:58:46 +0530 Subject: [PATCH 59/66] use other icon for distribution snapping --- .../scalable/actions/snap-distribution.svg | 210 ++++++++++++------ .../scalable/actions/snap-distribution.svg | 210 ++++++++++++------ .../actions/snap-distribution-symbolic.svg | 208 +++++++++++------ .../actions/snap-distribution-symbolic.svg | 208 +++++++++++------ 4 files changed, 550 insertions(+), 286 deletions(-) diff --git a/share/icons/Tango/scalable/actions/snap-distribution.svg b/share/icons/Tango/scalable/actions/snap-distribution.svg index 71f76eae89..83dd3ccc0b 100644 --- a/share/icons/Tango/scalable/actions/snap-distribution.svg +++ b/share/icons/Tango/scalable/actions/snap-distribution.svg @@ -1,89 +1,155 @@ - - + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + + + + image/svg+xml + + + + + + + - + inkscape:current-layer="path-division" + inkscape:document-rotation="0" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="0" + inkscape:snap-bbox="true" + inkscape:bbox-paths="true" + inkscape:bbox-nodes="true" + inkscape:snap-bbox-edge-midpoints="true" + inkscape:snap-bbox-midpoints="true" + inkscape:showpageshadow="false"> + + - - - - - - - + transform="translate(-165,-667.36218)" + inkscape:label="00080" + id="path-division"> + + + + + + + + + + diff --git a/share/icons/hicolor/scalable/actions/snap-distribution.svg b/share/icons/hicolor/scalable/actions/snap-distribution.svg index 71f76eae89..83dd3ccc0b 100644 --- a/share/icons/hicolor/scalable/actions/snap-distribution.svg +++ b/share/icons/hicolor/scalable/actions/snap-distribution.svg @@ -1,89 +1,155 @@ - - + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + + + + image/svg+xml + + + + + + + - + inkscape:current-layer="path-division" + inkscape:document-rotation="0" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="0" + inkscape:snap-bbox="true" + inkscape:bbox-paths="true" + inkscape:bbox-nodes="true" + inkscape:snap-bbox-edge-midpoints="true" + inkscape:snap-bbox-midpoints="true" + inkscape:showpageshadow="false"> + + - - - - - - - + transform="translate(-165,-667.36218)" + inkscape:label="00080" + id="path-division"> + + + + + + + + + + diff --git a/share/icons/hicolor/symbolic/actions/snap-distribution-symbolic.svg b/share/icons/hicolor/symbolic/actions/snap-distribution-symbolic.svg index 4b8ca7bb9a..83dd3ccc0b 100644 --- a/share/icons/hicolor/symbolic/actions/snap-distribution-symbolic.svg +++ b/share/icons/hicolor/symbolic/actions/snap-distribution-symbolic.svg @@ -1,89 +1,155 @@ - - + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + + + + image/svg+xml + + + + + + + - + inkscape:current-layer="path-division" + inkscape:document-rotation="0" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="0" + inkscape:snap-bbox="true" + inkscape:bbox-paths="true" + inkscape:bbox-nodes="true" + inkscape:snap-bbox-edge-midpoints="true" + inkscape:snap-bbox-midpoints="true" + inkscape:showpageshadow="false"> + + - - - - - - - + transform="translate(-165,-667.36218)" + inkscape:label="00080" + id="path-division"> + + + + + + + + + + diff --git a/share/icons/multicolor/symbolic/actions/snap-distribution-symbolic.svg b/share/icons/multicolor/symbolic/actions/snap-distribution-symbolic.svg index 4b8ca7bb9a..83dd3ccc0b 100644 --- a/share/icons/multicolor/symbolic/actions/snap-distribution-symbolic.svg +++ b/share/icons/multicolor/symbolic/actions/snap-distribution-symbolic.svg @@ -1,89 +1,155 @@ - - + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + + + + image/svg+xml + + + + + + + - + inkscape:current-layer="path-division" + inkscape:document-rotation="0" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="0" + inkscape:snap-bbox="true" + inkscape:bbox-paths="true" + inkscape:bbox-nodes="true" + inkscape:snap-bbox-edge-midpoints="true" + inkscape:snap-bbox-midpoints="true" + inkscape:showpageshadow="false"> + + - - - - - - - + transform="translate(-165,-667.36218)" + inkscape:label="00080" + id="path-division"> + + + + + + + + + + -- GitLab From 0a0cf4be2e481e904b09cdb4540e8c2fc86fc201 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Wed, 30 Jun 2021 23:22:09 +0530 Subject: [PATCH 60/66] revert size of alignment-guide circles from 6 to 7 using even number gives error messages --- src/display/control/snap-indicator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/display/control/snap-indicator.cpp b/src/display/control/snap-indicator.cpp index 1e57255cf6..132f094b10 100644 --- a/src/display/control/snap-indicator.cpp +++ b/src/display/control/snap-indicator.cpp @@ -383,7 +383,7 @@ void SnapIndicator::make_alignment_indicator(Geom::Point const &p1, Geom::Point Inkscape::CanvasItemCurve *line; auto ctrl = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); - ctrl->set_size(6); + ctrl->set_size(7); ctrl->set_mode(Inkscape::CanvasItemCtrlMode::CANVAS_ITEM_CTRL_MODE_COLOR); ctrl->set_stroke(0xffffffff); ctrl->set_fill(color); @@ -392,7 +392,7 @@ void SnapIndicator::make_alignment_indicator(Geom::Point const &p1, Geom::Point _alignment_snap_indicators.push_back(_desktop->add_temporary_canvasitem(ctrl, 0)); ctrl = new Inkscape::CanvasItemCtrl(_desktop->getCanvasTemp(), Inkscape::CANVAS_ITEM_CTRL_SHAPE_CIRCLE); - ctrl->set_size(6); + ctrl->set_size(7); ctrl->set_mode(Inkscape::CanvasItemCtrlMode::CANVAS_ITEM_CTRL_MODE_COLOR); ctrl->set_stroke(0xffffffff); ctrl->set_fill(color); -- GitLab From 3c1e35aab20cda39b5acef38e39012ed987f2580 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Thu, 1 Jul 2021 11:25:32 +0530 Subject: [PATCH 61/66] use unique_ptr in snap.h --- src/snap.cpp | 8 +++----- src/snap.h | 5 +++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/snap.cpp b/src/snap.cpp index 13e8940a15..11fcb594c8 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -16,6 +16,7 @@ * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ +#include #include #include @@ -63,17 +64,14 @@ SnapManager::SnapManager(SPNamedView const *v) : _snapindicator(true), _unselected_nodes(nullptr) { - obj_snapper_candidates = new std::vector; - align_snapper_candidates = new std::vector; + obj_snapper_candidates = std::make_unique>(); + align_snapper_candidates = std::make_unique>(); } SnapManager::~SnapManager() { obj_snapper_candidates->clear(); - delete obj_snapper_candidates; - align_snapper_candidates->clear(); - delete align_snapper_candidates; } SnapManager::SnapperList SnapManager::getSnappers() const diff --git a/src/snap.h b/src/snap.h index c0b5f7d6f6..ad34b44361 100644 --- a/src/snap.h +++ b/src/snap.h @@ -18,6 +18,7 @@ #ifndef SEEN_SNAP_H #define SEEN_SNAP_H +#include #include #include "guide-snapper.h" @@ -446,8 +447,8 @@ private: bool const _clip_or_mask, Geom::Affine const additional_affine) const; - std::vector *obj_snapper_candidates; - std::vector *align_snapper_candidates; + std::unique_ptr> obj_snapper_candidates; + std::unique_ptr> align_snapper_candidates; friend class Inkscape::ObjectSnapper; friend class Inkscape::AlignmentSnapper; -- GitLab From d21ced39e627e3f8c496d947419ae409413ec21a Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Fri, 2 Jul 2021 11:59:44 +0530 Subject: [PATCH 62/66] Redesign _addBBoxForIntersectingBoxes Fixes insertion errors caused by invalid vector iterators Also make the function verstile to take vectors as parameter and an enum to identify direction --- src/distribution-snapper.cpp | 165 ++++++++++++----------------------- src/distribution-snapper.h | 9 +- 2 files changed, 65 insertions(+), 109 deletions(-) diff --git a/src/distribution-snapper.cpp b/src/distribution-snapper.cpp index 4ce9baeef3..0cbc11c745 100644 --- a/src/distribution-snapper.cpp +++ b/src/distribution-snapper.cpp @@ -74,6 +74,23 @@ static int sortBoxesDown(Geom::Rect const &a, Geom::Rect const &b) return 0; } +Inkscape::DistributionSnapper::DistributionSnapper(SnapManager *sm, Geom::Coord const d) + : Snapper(sm, d) +{ + _bboxes_right = std::make_unique>(); + _bboxes_left = std::make_unique>(); + _bboxes_up = std::make_unique>(); + _bboxes_down = std::make_unique>(); +} + +Inkscape::DistributionSnapper::~DistributionSnapper() +{ + _bboxes_right->clear(); + _bboxes_left->clear(); + _bboxes_up->clear(); + _bboxes_down->clear(); +} + Geom::Coord Inkscape::DistributionSnapper::distRight(Geom::Rect const &a, Geom::Rect const &b) { return -a.max().x() + b.min().x(); @@ -196,23 +213,6 @@ bool Inkscape::DistributionSnapper::_findSidewaysSnaps( return true; } -Inkscape::DistributionSnapper::DistributionSnapper(SnapManager *sm, Geom::Coord const d) - : Snapper(sm, d) -{ - _bboxes_right = std::make_unique>(); - _bboxes_left = std::make_unique>(); - _bboxes_up = std::make_unique>(); - _bboxes_down = std::make_unique>(); -} - -Inkscape::DistributionSnapper::~DistributionSnapper() -{ - _bboxes_right->clear(); - _bboxes_left->clear(); - _bboxes_up->clear(); - _bboxes_down->clear(); -} - void Inkscape::DistributionSnapper::_collectBBoxes(Geom::OptRect const &bbox_to_snap, bool const &first_point) const { if (!first_point) @@ -274,107 +274,56 @@ void Inkscape::DistributionSnapper::_collectBBoxes(Geom::OptRect const &bbox_to_ std::stable_sort(_bboxes_up->begin(), _bboxes_up->end(), sortBoxesUp); std::stable_sort(_bboxes_down->begin(), _bboxes_down->end(), sortBoxesDown); - _addBBoxForIntersectingBoxes(); + _addBBoxForIntersectingBoxes(_bboxes_right.get(), Direction::RIGHT); + _addBBoxForIntersectingBoxes(_bboxes_left.get(), Direction::LEFT); + _addBBoxForIntersectingBoxes(_bboxes_up.get(), Direction::UP); + _addBBoxForIntersectingBoxes(_bboxes_down.get(), Direction::DOWN); } -void Inkscape::DistributionSnapper::_addBBoxForIntersectingBoxes() const { - if (_bboxes_right->size() > 0) { - for (auto it = _bboxes_right->begin(); std::next(it) != _bboxes_right->end(); it++) { - Geom::Rect comb(*it); - int num = 0; - auto start = it; - auto insertPos = it; - - while (std::next(it) != _bboxes_right->end() && it->intersects(*std::next(it))) { - comb.unionWith(*std::next(it)); - if (comb.midpoint().x() > it->midpoint().x()) { - insertPos = std::next(it); - } else { - ++num; - } - ++it; - } - - if (it != start) { - it = _bboxes_right->insert(insertPos, comb); - } - - it += num; - } +void Inkscape::DistributionSnapper::_addBBoxForIntersectingBoxes(std::vector *vec, Direction dir) const { + if (vec->size() < 1) { + return; } - if (_bboxes_left->size() > 0) { - for (auto it = _bboxes_left->begin(); std::next(it) != _bboxes_left->end(); it++) { - Geom::Rect comb(*it); - int num = 0; - auto start = it; - auto insertPos = it; - - while (std::next(it) != _bboxes_left->end() && it->intersects(*std::next(it))) { - comb.unionWith(*std::next(it)); - if (comb.midpoint().x() < it->midpoint().x()) { - insertPos = std::next(it); - } else { - ++num; - } - ++it; - } - - if (it != start) { - it = _bboxes_left->insert(insertPos, comb); + int count = 0; + std::vector> insertPositions; + + for (auto it = vec->begin(); it != vec->end(); it++, count++) { + Geom::Rect comb(*it); + int num = 0; + int insertPos = count; + + while (std::next(it) != vec->end() && it->intersects(*std::next(it))) { + comb.unionWith(*std::next(it)); + + if (dir == Direction::RIGHT && comb.midpoint().x() > it->midpoint().x()) { + ++insertPos; + } else if (dir == Direction::LEFT && comb.midpoint().x() < it->midpoint().x()){ + ++insertPos; + } else if (dir == Direction::UP && comb.midpoint().y() > it->midpoint().y()){ + ++insertPos; + } else if (dir == Direction::DOWN && comb.midpoint().y() < it->midpoint().y()){ + ++insertPos; } - it += num; + ++it; + ++num; + ++count; } - } - - if (_bboxes_up->size() > 0) { - for (auto it = _bboxes_up->begin(); std::next(it) != _bboxes_up->end(); it++) { - Geom::Rect comb(*it); - int num = 0; - auto start = it; - auto insertPos = it; - - while (std::next(it) != _bboxes_up->end() && it->intersects(*std::next(it))) { - comb.unionWith(*std::next(it)); - if (comb.midpoint().y() > it->midpoint().y()) { - insertPos = std::next(it); - } else { - ++num; - } - ++it; - } - - if (it != start) { - it = _bboxes_up->insert(insertPos, comb); - } - it += num; + if (num > 0) { + insertPositions.emplace_back(insertPos, comb); } } - - if (_bboxes_down->size() > 0) { - for (auto it = _bboxes_down->begin(); std::next(it) != _bboxes_down->end(); it++) { - Geom::Rect comb(*it); - int num = 0; - auto start = it; - auto insertPos = it; - - while (std::next(it) != _bboxes_down->end() && it->intersects(*std::next(it))) { - comb.unionWith(*std::next(it)); - if (comb.midpoint().y() < it->midpoint().y()) { - insertPos = std::next(it); - } else { - ++num; - } - ++it; - } - - if (it != start) { - it = _bboxes_down->insert(insertPos, comb); - } - - it += num; + + if (insertPositions.size() != 0) { + // TODO: Does this improve performance? + vec->reserve(vec->size() + insertPositions.size()); + + count = 0; + for (auto pair : insertPositions) { + vec->insert(vec->begin() + pair.first + count, pair.second); + ++count; } } } diff --git a/src/distribution-snapper.h b/src/distribution-snapper.h index a3042e92e3..9c4153c649 100644 --- a/src/distribution-snapper.h +++ b/src/distribution-snapper.h @@ -122,12 +122,19 @@ private: std::function const & distance_func, int level = 0) const; + enum class Direction { + RIGHT, + LEFT, + UP, + DOWN + }; + /** This functions adds overlapping bounding boxes to the list of bounding boxes. * The new bounding boxes are added such that the final list is still sorted. * This extra step is needed so that the overall union of any overlapping bounding * boxes is also considered during distribution snapping. */ - void _addBBoxForIntersectingBoxes() const; + void _addBBoxForIntersectingBoxes(std::vector *vec, Direction dir) const; // distance functions for different orientations static Geom::Coord distRight(Geom::Rect const &a, Geom::Rect const &b); -- GitLab From 3f17621e23b57d1009e83f90b3f2c42656551a11 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Sat, 3 Jul 2021 14:02:12 +0530 Subject: [PATCH 63/66] modify adding candidates in _findCandidates --- src/snap.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/snap.cpp b/src/snap.cpp index 11fcb594c8..a6b8b67196 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -935,19 +935,17 @@ void SnapManager::_findCandidates(SPObject* parent, // For debugging: print the id of the candidate to the console // SPObject *obj = (SPObject*)item; // std::cout << "Snap candidate added: " << obj->getId() << std::endl; - if (align_snapper_candidates->size() > 200) { // This makes Inkscape crawl already - overflow = true; + + if (bbox_to_snap_incl.intersects(*bbox_of_item) + || (snapprefs.isTargetSnappable(Inkscape::SNAPTARGET_ROTATION_CENTER) && bbox_to_snap_incl.contains(item->getCenter()))) { // rotation center might be outside of the bounding box + // This item is within snapping range, so record it as a candidate + obj_snapper_candidates->push_back(Inkscape::SnapCandidateItem(item, clip_or_mask, additional_affine)); + // For debugging: print the id of the candidate to the console + // SPObject *obj = (SPObject*)item; + // std::cout << "Snap candidate added: " << obj->getId() << std::endl; } - } - if (bbox_to_snap_incl.intersects(*bbox_of_item) - || (snapprefs.isTargetSnappable(Inkscape::SNAPTARGET_ROTATION_CENTER) && bbox_to_snap_incl.contains(item->getCenter()))) { // rotation center might be outside of the bounding box - // This item is within snapping range, so record it as a candidate - obj_snapper_candidates->push_back(Inkscape::SnapCandidateItem(item, clip_or_mask, additional_affine)); - // For debugging: print the id of the candidate to the console - // SPObject *obj = (SPObject*)item; - // std::cout << "Snap candidate added: " << obj->getId() << std::endl; - if (obj_snapper_candidates->size() > 200) { // This makes Inkscape crawl already + if (align_snapper_candidates->size() > 200) { // This makes Inkscape crawl already overflow = true; } } -- GitLab From af3274745a4805b281839f2617c4b7603d7473f3 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Mon, 5 Jul 2021 10:31:32 +0530 Subject: [PATCH 64/66] remove intelligent snapping - no names --- src/ui/dialog/inkscape-preferences.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp index b07e1f2a46..cb59d885b8 100644 --- a/src/ui/dialog/inkscape-preferences.cpp +++ b/src/ui/dialog/inkscape-preferences.cpp @@ -2368,6 +2368,10 @@ void InkscapePreferences::initPageBehavior() _page_snapping.add_line( true, _("Snap indicator persistence (in seconds):"), _snap_persistence, "", _("Controls how long the snap indicator message will be shown, before it disappears"), true); + _snap_indicator_distance.init( _("Show snap distance in case of alignment or distribution snap"), "/options/snapindicatordistance/value", false); + _page_snapping.add_line( true, "", _snap_indicator_distance, "", + _("Show snap distance in case of alignment or distribution snap")); + _page_snapping.add_group_header( _("What should snap")); _snap_closest_only.init( _("Only snap the node closest to the pointer"), "/options/snapclosestonly/value", false); @@ -2388,12 +2392,6 @@ void InkscapePreferences::initPageBehavior() _page_snapping.add_line( true, _("Delay (in seconds):"), _snap_delay, "", _("Postpone snapping as long as the mouse is moving, and then wait an additional fraction of a second. This additional delay is specified here. When set to zero or to a very small number, snapping will be immediate."), true); - _page_snapping.add_group_header( _("Intelligent Snapping")); - - _snap_indicator_distance.init( _("Show snap distance in case of alignment or distribution snap"), "/options/snapindicatordistance/value", false); - _page_snapping.add_line( true, "", _snap_indicator_distance, "", - _("Show snap distance in case of alignment or distribution snap")); - this->AddPage(_page_snapping, _("Snapping"), iter_behavior, PREFS_PAGE_BEHAVIOR_SNAPPING); // Steps options -- GitLab From c3ef6aa224d426a92084d2857ff9c00a4510f476 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Tue, 6 Jul 2021 11:24:08 +0530 Subject: [PATCH 65/66] alignment/distribution snapping turned on by default --- src/object/sp-namedview.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/object/sp-namedview.cpp b/src/object/sp-namedview.cpp index 7ec84cda75..68ee49a310 100644 --- a/src/object/sp-namedview.cpp +++ b/src/object/sp-namedview.cpp @@ -546,7 +546,7 @@ void SPNamedView::set(SPAttr key, const gchar* value) { this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SPAttr::INKSCAPE_SNAP_ALIGNMENT: - this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_ALIGNMENT_CATEGORY, value ? sp_str_to_bool(value) : FALSE); + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_ALIGNMENT_CATEGORY, value ? sp_str_to_bool(value) : TRUE); this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SPAttr::INKSCAPE_SNAP_ALIGNMENT_SELF: @@ -554,7 +554,7 @@ void SPNamedView::set(SPAttr key, const gchar* value) { this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SPAttr::INKSCAPE_SNAP_DISTRIBUTION: - this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_DISTRIBUTION_CATEGORY, value ? sp_str_to_bool(value) : FALSE); + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_DISTRIBUTION_CATEGORY, value ? sp_str_to_bool(value) : TRUE); this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SPAttr::INKSCAPE_CURRENT_LAYER: -- GitLab From 42c03640ae04ed5552065df614a329889bcb28f9 Mon Sep 17 00:00:00 2001 From: Parth Pant Date: Thu, 8 Jul 2021 21:48:54 +0530 Subject: [PATCH 66/66] fix for macOs std::optional::value --- src/snapped-point.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/snapped-point.h b/src/snapped-point.h index 20b37dbd35..aa094971fa 100644 --- a/src/snapped-point.h +++ b/src/snapped-point.h @@ -82,7 +82,7 @@ public: std::optional getAlignmentTarget() const { if (_alignment_target.has_value()) - return _alignment_target.value(); + return *_alignment_target; else return {}; } @@ -90,14 +90,14 @@ public: std::optional getAlignmentTarget2() const { if (_alignment_target2.has_value()) - return _alignment_target2.value(); + return *_alignment_target2; else return {}; } Geom::Coord getDistanceToAlignTarget() const { - return _alignment_target.has_value() ? Geom::L2(_point - _alignment_target.value()) : Geom::infinity(); + return _alignment_target.has_value() ? Geom::L2(_point - *_alignment_target) : Geom::infinity(); } bool getAtIntersection() const {return _at_intersection;} @@ -109,7 +109,7 @@ public: SnapTargetType getTarget() const {return _target;} SnapTargetType getAlignmentTargetType() const { - return _alignment_target_type.has_value() ? _alignment_target_type.value() : SNAPTARGET_UNDEFINED; + return _alignment_target_type.has_value() ? *_alignment_target_type : SNAPTARGET_UNDEFINED; } void setTargetBBox(Geom::OptRect const target) {_target_bbox = target;} Geom::OptRect const getTargetBBox() const {return _target_bbox;} -- GitLab