summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 048cb93)
raw | patch | inline | side by side (parent: 048cb93)
author | dvlierop2 <dvlierop2@users.sourceforge.net> | |
Sun, 14 Dec 2008 20:49:00 +0000 (20:49 +0000) | ||
committer | dvlierop2 <dvlierop2@users.sourceforge.net> | |
Sun, 14 Dec 2008 20:49:00 +0000 (20:49 +0000) |
2) snap intersections within a single shape (as source; as target was already implemented)
22 files changed:
diff --git a/src/attributes-test.h b/src/attributes-test.h
index bffc2779802334d2c825523dc6780693c6947f08..af1ed8a11dc41ba4f9ebbb0e8bda65942b18841b 100644 (file)
--- a/src/attributes-test.h
+++ b/src/attributes-test.h
{"inkscape:snap-guide", true},
{"inkscape:snap-center", true},
{"inkscape:snap-smooth-nodes", true},
+ {"inkscape:snap-midpoints", true},
{"inkscape:snap-intersection-grid-guide", true},
{"inkscape:snap-intersection-paths", true},
{"inkscape:pageopacity", true},
diff --git a/src/attributes.cpp b/src/attributes.cpp
index 149d177f5e2b1db1fb3df273b7a942132a8539c1..1ee33ef832468e8680eb06adb4c988a4c8fcf8c5 100644 (file)
--- a/src/attributes.cpp
+++ b/src/attributes.cpp
{SP_ATTR_INKSCAPE_SNAP_GUIDE, "inkscape:snap-guide"},
{SP_ATTR_INKSCAPE_SNAP_CENTER, "inkscape:snap-center"},
{SP_ATTR_INKSCAPE_SNAP_SMOOTH_NODES, "inkscape:snap-smooth-nodes"},
+ {SP_ATTR_INKSCAPE_SNAP_MIDPOINTS, "inkscape:snap-midpoints"},
{SP_ATTR_INKSCAPE_SNAP_INTERS_GRIDGUIDE, "inkscape:snap-intersection-grid-guide"},
{SP_ATTR_INKSCAPE_SNAP_INTERS_PATHS, "inkscape:snap-intersection-paths"},
{SP_ATTR_INKSCAPE_OBJECT_PATHS, "inkscape:object-paths"},
diff --git a/src/attributes.h b/src/attributes.h
index f8925f47ccca86ced39dcd6b79be90e68d51a53e..68e6135dbd2084aae24b71fb56f1babed465fca3 100644 (file)
--- a/src/attributes.h
+++ b/src/attributes.h
SP_ATTR_INKSCAPE_SNAP_GUIDE,
SP_ATTR_INKSCAPE_SNAP_CENTER,
SP_ATTR_INKSCAPE_SNAP_SMOOTH_NODES,
+ SP_ATTR_INKSCAPE_SNAP_MIDPOINTS,
SP_ATTR_INKSCAPE_SNAP_INTERS_GRIDGUIDE,
SP_ATTR_INKSCAPE_SNAP_INTERS_PATHS,
SP_ATTR_INKSCAPE_OBJECT_PATHS,
index a636d8268eed30ddecea77c336e39abd818ba499..4b45eae339680baf17fd9c0ed72d872ca0971313 100644 (file)
#include "sp-canvas-util.h"
#include "canvas-axonomgrid.h"
-#include "util/mathfns.h"
+#include "util/mathfns.h"
#include "2geom/geom.h"
#include "display-forward.h"
#include <libnr/nr-pixops.h>
Inkscape::UI::Widget::RegisteredColorPicker *_rcp_gcol = Gtk::manage(
new Inkscape::UI::Widget::RegisteredColorPicker(
- _("Grid line _color:"), _("Grid line color"), _("Color of grid lines"),
+ _("Grid line _color:"), _("Grid line color"), _("Color of grid lines"),
"color", "opacity", _wr, repr, doc));
Inkscape::UI::Widget::RegisteredColorPicker *_rcp_gmcol = Gtk::manage(
new Inkscape::UI::Widget::RegisteredColorPicker(
- _("Ma_jor grid line color:"), _("Major grid line color"),
+ _("Ma_jor grid line color:"), _("Major grid line color"),
_("Color of the major (highlighted) grid lines"),
"empcolor", "empopacity", _wr, repr, doc));
}
}
-CanvasAxonomGridSnapper::CanvasAxonomGridSnapper(CanvasAxonomGrid *grid, SnapManager const *sm, Geom::Coord const d) : LineSnapper(sm, d)
+CanvasAxonomGridSnapper::CanvasAxonomGridSnapper(CanvasAxonomGrid *grid, SnapManager *sm, Geom::Coord const d) : LineSnapper(sm, d)
{
this->grid = grid;
}
// - 2 vertical grid lines, one left and one right from the point
// - 2 angled z grid lines, one above and one below the point
// - 2 angled x grid lines, one above and one below the point
-
+
// Calculate the x coordinate of the vertical grid lines
Geom::Coord x_max = Inkscape::Util::round_to_upper_multiple_plus(p[Geom::X], scaled_spacing_h, grid->origin[Geom::X]);
Geom::Coord x_min = Inkscape::Util::round_to_lower_multiple_plus(p[Geom::X], scaled_spacing_h, grid->origin[Geom::X]);
-
+
// Calculate the y coordinate of the intersection of the angled grid lines with the y-axis
- double y_proj_along_z = p[Geom::Y] - grid->tan_angle[Z]*(p[Geom::X] - grid->origin[Geom::X]);
- double y_proj_along_x = p[Geom::Y] + grid->tan_angle[X]*(p[Geom::X] - grid->origin[Geom::X]);
+ double y_proj_along_z = p[Geom::Y] - grid->tan_angle[Z]*(p[Geom::X] - grid->origin[Geom::X]);
+ double y_proj_along_x = p[Geom::Y] + grid->tan_angle[X]*(p[Geom::X] - grid->origin[Geom::X]);
double y_proj_along_z_max = Inkscape::Util::round_to_upper_multiple_plus(y_proj_along_z, scaled_spacing_v, grid->origin[Geom::Y]);
- double y_proj_along_z_min = Inkscape::Util::round_to_lower_multiple_plus(y_proj_along_z, scaled_spacing_v, grid->origin[Geom::Y]);
+ double y_proj_along_z_min = Inkscape::Util::round_to_lower_multiple_plus(y_proj_along_z, scaled_spacing_v, grid->origin[Geom::Y]);
double y_proj_along_x_max = Inkscape::Util::round_to_upper_multiple_plus(y_proj_along_x, scaled_spacing_v, grid->origin[Geom::Y]);
double y_proj_along_x_min = Inkscape::Util::round_to_lower_multiple_plus(y_proj_along_x, scaled_spacing_v, grid->origin[Geom::Y]);
-
+
// Calculate the normal for the angled grid lines
Geom::Point norm_x = Geom::rot90(Geom::Point(1, -grid->tan_angle[X]));
Geom::Point norm_z = Geom::rot90(Geom::Point(1, grid->tan_angle[Z]));
-
+
// The four angled grid lines form a parallellogram, enclosing the point
// One of the two vertical grid lines divides this parallellogram in two triangles
- // We will now try to find out in which half (i.e. triangle) our point is, and return
- // only the three grid lines defining that triangle
-
- // The vertical grid line is at the intersection of two angled grid lines.
+ // We will now try to find out in which half (i.e. triangle) our point is, and return
+ // only the three grid lines defining that triangle
+
+ // The vertical grid line is at the intersection of two angled grid lines.
// Now go find that intersection!
Geom::Point result;
Geom::IntersectorKind is = Geom::line_intersection(norm_x, norm_x[Geom::Y]*y_proj_along_x_max,
norm_z, norm_z[Geom::Y]*y_proj_along_z_max,
result);
-
- // Determine which half of the parallellogram to use
+
+ // Determine which half of the parallellogram to use
bool use_left_half = true;
bool use_right_half = true;
-
+
if (is == Geom::intersects) {
use_left_half = (p[Geom::X] - grid->origin[Geom::X]) < result[Geom::X];
- use_right_half = !use_left_half;
+ use_right_half = !use_left_half;
}
-
+
//std::cout << "intersection at " << result << " leads to use_left_half = " << use_left_half << " and use_right_half = " << use_right_half << std::endl;
-
+
// Return the three grid lines which define the triangle that encloses our point
// If we didn't find an intersection above, all 6 grid lines will be returned
if (use_left_half) {
s.push_back(std::make_pair(norm_z, Geom::Point(grid->origin[Geom::X], y_proj_along_z_max)));
s.push_back(std::make_pair(norm_x, Geom::Point(grid->origin[Geom::X], y_proj_along_x_min)));
- s.push_back(std::make_pair(component_vectors[Geom::X], Geom::Point(x_max, 0)));
+ s.push_back(std::make_pair(component_vectors[Geom::X], Geom::Point(x_max, 0)));
}
-
+
if (use_right_half) {
s.push_back(std::make_pair(norm_z, Geom::Point(grid->origin[Geom::X], y_proj_along_z_min)));
s.push_back(std::make_pair(norm_x, Geom::Point(grid->origin[Geom::X], y_proj_along_x_max)));
- s.push_back(std::make_pair(component_vectors[Geom::X], Geom::Point(x_min, 0)));
- }
-
+ s.push_back(std::make_pair(component_vectors[Geom::X], Geom::Point(x_min, 0)));
+ }
+
return s;
}
-void CanvasAxonomGridSnapper::_addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, Geom::Point const normal_to_line, Geom::Point const point_on_line) const
+void CanvasAxonomGridSnapper::_addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, Geom::Point const normal_to_line, Geom::Point const point_on_line) const
{
SnappedLine dummy = SnappedLine(snapped_point, snapped_distance, getSnapperTolerance(), getSnapperAlwaysSnap(), normal_to_line, point_on_line);
sc.grid_lines.push_back(dummy);
index 1d255d798a49396c2a2d14838b69f1a9e796e53c..0654a942947ae9e22efde24028a4eb03fbd35d71 100644 (file)
void Update (Geom::Matrix const &affine, unsigned int flags);
void Render (SPCanvasBuf *buf);
-
+
void readRepr();
void onReprAttrChanged (Inkscape::XML::Node * repr, const gchar *key, const gchar *oldval, const gchar *newval, bool is_interactive);
double angle_deg[3]; /**< Angle of each axis (note that angle[2] == 0) */
double angle_rad[3]; /**< Angle of each axis (note that angle[2] == 0) */
double tan_angle[3]; /**< tan(angle[.]) */
-
+
bool scaled; /**< Whether the grid is in scaled mode */
-
+
Geom::Point ow; /**< Transformed origin by the affine for the zoom */
double lyw; /**< Transformed length y by the affine for the zoom */
double lxw_x;
double lxw_z;
double spacing_ylines;
-
+
Geom::Point sw; /**< the scaling factors of the affine transform */
protected:
private:
CanvasAxonomGrid(const CanvasAxonomGrid&);
CanvasAxonomGrid& operator=(const CanvasAxonomGrid&);
-
+
void updateWidgets();
};
class CanvasAxonomGridSnapper : public LineSnapper
{
public:
- CanvasAxonomGridSnapper(CanvasAxonomGrid *grid, SnapManager const *sm, Geom::Coord const d);
+ CanvasAxonomGridSnapper(CanvasAxonomGrid *grid, SnapManager *sm, Geom::Coord const d);
-private:
+private:
LineList _getSnapLines(Geom::Point const &p) const;
void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, Geom::Point const normal_to_line, const Geom::Point point_on_line) const;
CanvasAxonomGrid *grid;
-};
+};
}; //namespace Inkscape
-#endif
+#endif
index 8505426d3cb7822fc68bf9fb1c27190de8c23436..b03bfca9e0e2385e3cbb694ca8b31744e23d1da0 100644 (file)
#define INKSCAPE_CANVAS_GRID_C
#include "sp-canvas-util.h"
-#include "util/mathfns.h"
+#include "util/mathfns.h"
#include "display-forward.h"
#include <libnr/nr-pixops.h>
#include "desktop-handles.h"
@@ -357,13 +357,13 @@ CanvasGrid::on_repr_attr_changed(Inkscape::XML::Node *repr, gchar const *key, gc
((CanvasGrid*) data)->onReprAttrChanged(repr, key, oldval, newval, is_interactive);
}
-bool CanvasGrid::isEnabled()
-{
+bool CanvasGrid::isEnabled()
+{
if (snapper == NULL) {
return false;
- }
-
- return snapper->getEnabled();
+ }
+
+ return snapper->getEnabled();
}
// ##########################################################
if ( (value = repr->attribute("visible")) ) {
visible = (strcmp(value,"false") != 0 && strcmp(value, "0") != 0);
}
-
+
if ( (value = repr->attribute("enabled")) ) {
g_assert(snapper != NULL);
snapper->setEnabled(strcmp(value,"false") != 0 && strcmp(value, "0") != 0);
Inkscape::UI::Widget::RegisteredColorPicker *_rcp_gcol = Gtk::manage(
new Inkscape::UI::Widget::RegisteredColorPicker(
- _("Grid line _color:"), _("Grid line color"), _("Color of grid lines"),
+ _("Grid line _color:"), _("Grid line color"), _("Color of grid lines"),
"color", "opacity", _wr, repr, doc));
Inkscape::UI::Widget::RegisteredColorPicker *_rcp_gmcol = Gtk::manage(
new Inkscape::UI::Widget::RegisteredColorPicker(
- _("Ma_jor grid line color:"), _("Major grid line color"),
- _("Color of the major (highlighted) grid lines"), "empcolor", "empopacity",
+ _("Ma_jor grid line color:"), _("Major grid line color"),
+ _("Color of the major (highlighted) grid lines"), "empcolor", "empopacity",
_wr, repr, doc));
-
+
Inkscape::UI::Widget::RegisteredSuffixedInteger *_rsi = Gtk::manage( new Inkscape::UI::Widget::RegisteredSuffixedInteger(
_("_Major grid line every:"), "", _("lines"), "empspacing", _wr, repr, doc) );
}
}
-CanvasXYGridSnapper::CanvasXYGridSnapper(CanvasXYGrid *grid, SnapManager const *sm, Geom::Coord const d) : LineSnapper(sm, d)
+CanvasXYGridSnapper::CanvasXYGridSnapper(CanvasXYGrid *grid, SnapManager *sm, Geom::Coord const d) : LineSnapper(sm, d)
{
this->grid = grid;
}
scaled_spacing /= SP_ACTIVE_DESKTOP->current_zoom();
}
- Geom::Coord rounded;
+ Geom::Coord rounded;
Geom::Point point_on_line;
-
+
rounded = Inkscape::Util::round_to_upper_multiple_plus(p[i], scaled_spacing, grid->origin[i]);
point_on_line = i ? Geom::Point(0, rounded) : Geom::Point(rounded, 0);
s.push_back(std::make_pair(component_vectors[i], point_on_line));
-
+
rounded = Inkscape::Util::round_to_lower_multiple_plus(p[i], scaled_spacing, grid->origin[i]);
point_on_line = i ? Geom::Point(0, rounded) : Geom::Point(rounded, 0);
s.push_back(std::make_pair(component_vectors[i], point_on_line));
return s;
}
-void CanvasXYGridSnapper::_addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, Geom::Point const normal_to_line, Geom::Point const point_on_line) const
+void CanvasXYGridSnapper::_addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, Geom::Point const normal_to_line, Geom::Point const point_on_line) const
{
SnappedLine dummy = SnappedLine(snapped_point, snapped_distance, getSnapperTolerance(), getSnapperAlwaysSnap(), normal_to_line, point_on_line);
sc.grid_lines.push_back(dummy);
index f50537065be93802d641cd39b1c12763fbcafae0..e4bd0141461cf6e4158d89e405c50f35a5631beb 100644 (file)
guint32 color; /**< Color for normal lines */
guint32 empcolor; /**< Color for emphasis lines */
gint empspacing; /**< Spacing between emphasis lines */
-
+
SPUnit const* gridunit;
-
+
Inkscape::XML::Node * repr;
SPDocument *doc;
class CanvasXYGridSnapper : public LineSnapper
{
public:
- CanvasXYGridSnapper(CanvasXYGrid *grid, SnapManager const *sm, Geom::Coord const d);
+ CanvasXYGridSnapper(CanvasXYGrid *grid, SnapManager *sm, Geom::Coord const d);
bool ThisSnapperMightSnap() const;
private:
diff --git a/src/guide-snapper.cpp b/src/guide-snapper.cpp
index d9c57f8293914e53e0b0cb7ec818216b0b954568..be2e84170aff18ce4fbc4241f760c4bd6979d575 100644 (file)
--- a/src/guide-snapper.cpp
+++ b/src/guide-snapper.cpp
#include "sp-namedview.h"
#include "sp-guide.h"
-Inkscape::GuideSnapper::GuideSnapper(SnapManager const *sm, Geom::Coord const d) : LineSnapper(sm, d)
+Inkscape::GuideSnapper::GuideSnapper(SnapManager *sm, Geom::Coord const d) : LineSnapper(sm, d)
{
}
for (GSList const *l = _snapmanager->getNamedView()->guides; l != NULL; l = l->next) {
SPGuide const *g = SP_GUIDE(l->data);
- s.push_back(std::make_pair(g->normal_to_line, g->point_on_line));
+ s.push_back(std::make_pair(g->normal_to_line, g->point_on_line));
}
return s;
diff --git a/src/guide-snapper.h b/src/guide-snapper.h
index a7798c72ff3877c143c1406e47af93a6032adec5..f36d03499605ed7b0c3ce75ca2e3e085dd3e9a3b 100644 (file)
--- a/src/guide-snapper.h
+++ b/src/guide-snapper.h
* Frank Felfe <innerspace@iname.com>
* Carl Hetherington <inkscape@carlh.net>
*
- * Copyright (C) 1999-2002 Authors
+ * Copyright (C) 1999-2002 Authors
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
class GuideSnapper : public LineSnapper
{
public:
- GuideSnapper(SnapManager const *sm, Geom::Coord const d);
+ GuideSnapper(SnapManager *sm, Geom::Coord const d);
bool ThisSnapperMightSnap() const;
private:
- LineList _getSnapLines(Geom::Point const &p) const;
+ LineList _getSnapLines(Geom::Point const &p) const;
void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, Geom::Point const normal_to_line, Geom::Point const point_on_line) const;
};
diff --git a/src/line-snapper.cpp b/src/line-snapper.cpp
index f2d2f2ff624b0b46099fd802e324cf5cdd579a91..bfcda3f79dfba34402853eccf5afeed1e580fd10 100644 (file)
--- a/src/line-snapper.cpp
+++ b/src/line-snapper.cpp
* Authors:
* Diederik van Lierop <mail@diedenrezi.nl>
* And others...
- *
+ *
* Copyright (C) 1999-2008 Authors
*
* Released under GNU GPL, read the file 'COPYING' for more information
#include <gtk/gtk.h>
#include "snap.h"
-Inkscape::LineSnapper::LineSnapper(SnapManager const *sm, Geom::Coord const d) : Snapper(sm, d)
+Inkscape::LineSnapper::LineSnapper(SnapManager *sm, Geom::Coord const d) : Snapper(sm, d)
{
}
{
if (_snap_enabled == false || _snapmanager->snapprefs.getSnapFrom(t) == false) {
return;
- }
-
+ }
+
/* Get the lines that we will try to snap to */
const LineList lines = _getSnapLines(p);
Geom::Point const p2 = p1 + Geom::rot90(i->first); // 2nd point at guide/grid line
// std::cout << " line through " << i->second << " with normal " << i->first;
g_assert(i->first != Geom::Point(0,0)); // we cannot project on an linesegment of zero length
-
+
Geom::Point const p_proj = project_on_linesegment(p, p1, p2);
Geom::Coord const dist = Geom::L2(p_proj - p);
//Store any line that's within snapping range
if (dist < getSnapperTolerance()) {
_addSnappedLine(sc, p_proj, dist, i->first, i->second);
- // std::cout << " -> distance = " << dist;
- }
+ // std::cout << " -> distance = " << dist;
+ }
// std::cout << std::endl;
- }
+ }
}
void Inkscape::LineSnapper::constrainedSnap(SnappedConstraints &sc,
if (_snap_enabled == false || _snapmanager->snapprefs.getSnapFrom(t) == false) {
return;
}
-
+
/* Get the lines that we will try to snap to */
const LineList lines = _getSnapLines(p);
if (Geom::L2(c.getDirection()) > 0) { // Can't do a constrained snap without a constraint
/* Normal to the line we're trying to snap along */
Geom::Point const n(Geom::rot90(Geom::unit_vector(c.getDirection())));
-
+
Geom::Point const point_on_line = c.hasPoint() ? c.getPoint() : p;
-
+
/* Constant term of the line we're trying to snap along */
Geom::Coord const q0 = dot(n, point_on_line);
/* Constant term of the grid or guide line */
- Geom::Coord const q1 = dot(i->first, i->second);
-
+ Geom::Coord const q1 = dot(i->first, i->second);
+
/* Try to intersect this line with the target line */
Geom::Point t_2geom(NR_HUGE, NR_HUGE);
Geom::IntersectorKind const k = Geom::line_intersection(n, q0, i->first, q1, t_2geom);
Geom::Point t(t_2geom);
-
+
if (k == Geom::intersects) {
const Geom::Coord dist = L2(t - p);
if (dist < getSnapperTolerance()) {
// to look for additional intersections; just return the snapped point
// and forget about the line
sc.points.push_back(SnappedPoint(t, Inkscape::SNAPTARGET_UNDEFINED, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true));
- // The type of the snap target is yet undefined, as we cannot tell whether
- // we're snapping to grid or the guide lines; must be set by on a higher level
+ // The type of the snap target is yet undefined, as we cannot tell whether
+ // we're snapping to grid or the guide lines; must be set by on a higher level
}
}
}
diff --git a/src/line-snapper.h b/src/line-snapper.h
index 529db1caaeb833700e6b0cb8da7ac2c916794753..91e8ca596d8e2d2188d0b36c795c603eb19fad0b 100644 (file)
--- a/src/line-snapper.h
+++ b/src/line-snapper.h
* Authors:
* Carl Hetherington <inkscape@carlh.net>
* Diederik van Lierop <mail@diedenrezi.nl>
- *
+ *
* Copyright (C) 1999-2008 Authors
*
* Released under GNU GPL, read the file 'COPYING' for more information.
class LineSnapper : public Snapper
{
public:
- LineSnapper(SnapManager const *sm, Geom::Coord const d);
+ LineSnapper(SnapManager *sm, Geom::Coord const d);
void freeSnap(SnappedConstraints &sc,
Inkscape::SnapPreferences::PointType const &t,
Geom::OptRect const &bbox_to_snap,
std::vector<SPItem const *> const *it,
std::vector<Geom::Point> *unselected_nodes) const;
-
+
void constrainedSnap(SnappedConstraints &sc,
Inkscape::SnapPreferences::PointType const &t,
Geom::Point const &p,
std::vector<SPItem const *> const *it) const;
protected:
- typedef std::list<std::pair<Geom::Point, Geom::Point> > LineList;
+ typedef std::list<std::pair<Geom::Point, Geom::Point> > LineList;
//first point is a vector normal to the line
//second point is a point on the line
* \return List of lines that we should try snapping to.
*/
virtual LineList _getSnapLines(Geom::Point const &p) const = 0;
-
+
virtual void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, Geom::Point const normal_to_line, Geom::Point const point_on_line) const = 0;
};
diff --git a/src/object-snapper.cpp b/src/object-snapper.cpp
index 06f24c47fa1129d28623bfbedea13f6710a82116..922c35bcbe545689f53e1de49a075dd009ea797f 100644 (file)
--- a/src/object-snapper.cpp
+++ b/src/object-snapper.cpp
Inkscape::SnapCandidate::SnapCandidate(SPItem* item, bool clip_or_mask, Geom::Matrix additional_affine)
: item(item), clip_or_mask(clip_or_mask), additional_affine(additional_affine)
-{
+{
}
Inkscape::SnapCandidate::~SnapCandidate()
-{
+{
}
-Inkscape::ObjectSnapper::ObjectSnapper(SnapManager const *sm, Geom::Coord const d)
+Inkscape::ObjectSnapper::ObjectSnapper(SnapManager *sm, Geom::Coord const d)
: Snapper(sm, d), _snap_to_itemnode(true), _snap_to_itempath(true),
_snap_to_bboxnode(true), _snap_to_bboxpath(true), _snap_to_page_border(false),
_strict_snapping(true)
{
bool const c1 = (snap_dim == TRANSL_SNAP_XY) && ThisSnapperMightSnap();
bool const c2 = (snap_dim != TRANSL_SNAP_XY) && GuidesMightSnap();
-
+
if (!(c1 || c2)) {
- return;
+ return;
}
-
+
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 (SPObject* o = sp_object_first_child(parent); o != NULL; o = SP_OBJECT_NEXT(o)) {
g_assert(_snapmanager->getDesktop() != NULL);
if (SP_IS_ITEM(o) && !SP_ITEM(o)->isLocked() && !(_snapmanager->getDesktop()->itemIsHidden(SP_ITEM(o)) && !clip_or_mask)) {
i++;
}
}
-
+
if (it == NULL || i == it->end()) {
- SPItem *item = SP_ITEM(o);
+ SPItem *item = SP_ITEM(o);
Geom::Matrix transform = Geom::identity();
if (item) {
SPObject *obj = NULL;
if (clip_or_mask) { // If the current item is a clipping path or a mask
// then store the transformation of the clipped path or mask itself
- // but also take into account the additional affine of the object
+ // but also take into account the additional affine of the object
// being clipped / masked
transform = to_2geom(item->transform) * additional_affine;
- } else { // cannot clip or mask more than once
+ } else { // 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
obj = SP_OBJECT(item->clip_ref->getObject());
if (obj) {
_findCandidates(obj, it, false, bbox_to_snap, snap_dim, true, item->transform);
- }
+ }
obj = SP_OBJECT(item->mask_ref->getObject());
if (obj) {
_findCandidates(obj, it, false, bbox_to_snap, snap_dim, true, item->transform);
}
}
- }
-
+ }
+
if (SP_IS_GROUP(o)) {
_findCandidates(o, it, false, bbox_to_snap, snap_dim, false, Geom::identity());
} else {
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)
- sp_item_invoke_bbox(item,
+ sp_item_invoke_bbox(item,
bbox_of_item,
sp_item_i2doc_affine(item) * matrix_to_desktop(additional_affine, item),
true);
sp_item_invoke_bbox(item, bbox_of_item, sp_item_i2d_affine(item), true);
}
if (bbox_of_item) {
- // See if the item is within range
+ // See if the item is within range
if (bbox_to_snap_incl.intersects(*bbox_of_item)) {
// This item is within snapping range, so record it as a candidate
_candidates->push_back(SnapCandidate(item, clip_or_mask, additional_affine));
- }
+ }
}
}
}
@@ -171,27 +171,27 @@ void Inkscape::ObjectSnapper::_collectNodes(Inkscape::SnapPreferences::PointType
// first point and store the collection for later use. This significantly improves the performance
if (first_point) {
_points_to_snap_to->clear();
-
+
// Determine the type of bounding box we should snap to
SPItem::BBoxType bbox_type = SPItem::GEOMETRIC_BBOX;
-
+
bool p_is_a_node = t & Inkscape::SnapPreferences::SNAPPOINT_NODE;
bool p_is_a_bbox = t & Inkscape::SnapPreferences::SNAPPOINT_BBOX;
bool p_is_a_guide = t & Inkscape::SnapPreferences::SNAPPOINT_GUIDE;
-
+
// A point considered for snapping should be either a node, a bbox corner or a guide. Pick only ONE!
- g_assert(!((p_is_a_node && p_is_a_bbox) || (p_is_a_bbox && p_is_a_guide) || (p_is_a_node && p_is_a_guide)));
-
+ g_assert(!((p_is_a_node && p_is_a_bbox) || (p_is_a_bbox && p_is_a_guide) || (p_is_a_node && p_is_a_guide)));
+
if (_snap_to_bboxnode) {
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
bool prefs_bbox = prefs->getBool("/tools/bounding_box");
- bbox_type = !prefs_bbox ?
+ bbox_type = !prefs_bbox ?
SPItem::APPROXIMATE_BBOX : SPItem::GEOMETRIC_BBOX;
}
-
+
// Consider the page border for snapping
if (_snap_to_page_border) {
- _getBorderNodes(_points_to_snap_to);
+ _getBorderNodes(_points_to_snap_to);
}
for (std::vector<SnapCandidate>::const_iterator i = _candidates->begin(); i != _candidates->end(); i++) {
@@ -205,7 +205,35 @@ void Inkscape::ObjectSnapper::_collectNodes(Inkscape::SnapPreferences::PointType
//Collect all nodes so we can snap to them
if (_snap_to_itemnode) {
if (!(_strict_snapping && !p_is_a_node) || p_is_a_guide) {
+ // Note: there are two ways in which intersections are considered:
+ // Method 1: Intersections are calculated for each shape individually, for both the
+ // snap source and snap target (see sp_shape_snappoints)
+ // Method 2: Intersections are calculated for each curve or line that we've snapped to, i.e. only for
+ // the target (see the intersect() method in the SnappedCurve and SnappedLine classes)
+ // Some differences:
+ // - Method 1 doesn't find intersections within a set of multiple objects
+ // - Method 2 only works for targets
+ // When considering intersections as snap targets:
+ // - Method 1 only works when snapping to nodes, whereas
+ // - Method 2 only works when snapping to paths
+ // - There will be performance differences too!
+ // If both methods are being used simultaneously, then this might lead to duplicate targets!
+
+ // Well, here we will be looking for snap TARGETS. Both methods can therefore be used.
+ // When snapping to paths, we will get a collection of snapped lines and snapped curves. findBestSnap() will
+ // go hunting for intersections (but only when asked to in the prefs of course). In that case we can just
+ // temporarily block the intersections in sp_item_snappoints, we don't need duplicates. If we're not snapping to
+ // paths though but only to item nodes then we should still look for the intersections in sp_item_snappoints()
+ bool old_pref = _snapmanager->snapprefs.getSnapIntersectionCS();
+ if (_snap_to_itempath) {
+ _snapmanager->snapprefs.setSnapIntersectionCS(false);
+ }
+
sp_item_snappoints(root_item, SnapPointsIter(*_points_to_snap_to), &_snapmanager->snapprefs);
+
+ if (_snap_to_itempath) {
+ _snapmanager->snapprefs.setSnapIntersectionCS(old_pref);
+ }
}
}
@@ -214,7 +242,7 @@ void Inkscape::ObjectSnapper::_collectNodes(Inkscape::SnapPreferences::PointType
if (!(_strict_snapping && !p_is_a_bbox) || p_is_a_guide) {
// Discard the bbox of a clipped path / mask, because we don't want to snap to both the bbox
// of the item AND the bbox of the clipping path at the same time
- if (!(*i).clip_or_mask) {
+ if (!(*i).clip_or_mask) {
Geom::OptRect b = sp_item_bbox_desktop(root_item, bbox_type);
if (b) {
for ( unsigned k = 0 ; k < 4 ; k++ ) {
std::vector<Geom::Point> *unselected_nodes) const
{
// Iterate through all nodes, find out which one is the closest to p, and snap to it!
-
+
_collectNodes(t, first_point);
-
+
if (unselected_nodes != NULL) {
_points_to_snap_to->insert(_points_to_snap_to->end(), unselected_nodes->begin(), unselected_nodes->end());
- }
-
+ }
+
SnappedPoint s;
bool success = false;
-
+
for (std::vector<Geom::Point>::const_iterator k = _points_to_snap_to->begin(); k != _points_to_snap_to->end(); k++) {
- Geom::Coord dist = Geom::L2(*k - p);
+ Geom::Coord dist = Geom::L2(*k - p);
if (dist < getSnapperTolerance() && dist < s.getSnapDistance()) {
s = SnappedPoint(*k, SNAPTARGET_NODE, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
success = true;
}
if (success) {
- sc.points.push_back(s);
+ sc.points.push_back(s);
}
}
@@ -265,16 +293,16 @@ void Inkscape::ObjectSnapper::_snapTranslatingGuideToNodes(SnappedConstraints &s
{
// Iterate through all nodes, find out which one is the closest to this guide, and snap to it!
_collectNodes(t, true);
-
+
SnappedPoint s;
bool success = false;
-
+
Geom::Coord tol = getSnapperTolerance();
-
+
for (std::vector<Geom::Point>::const_iterator k = _points_to_snap_to->begin(); k != _points_to_snap_to->end(); k++) {
// Project each node (*k) on the guide line (running through point p)
Geom::Point p_proj = project_on_linesegment(*k, p, p + Geom::rot90(guide_normal));
- Geom::Coord dist = Geom::L2(*k - p_proj); // distance from node to the guide
+ Geom::Coord dist = Geom::L2(*k - p_proj); // distance from node to the guide
Geom::Coord dist2 = Geom::L2(p - p_proj); // distance from projection of node on the guide, to the mouse location
if ((dist < tol && dist2 < tol) || (getSnapperAlwaysSnap() && dist < s.getSnapDistance())) {
s = SnappedPoint(*k, SNAPTARGET_NODE, dist, tol, getSnapperAlwaysSnap(), true);
@@ -283,7 +311,7 @@ void Inkscape::ObjectSnapper::_snapTranslatingGuideToNodes(SnappedConstraints &s
}
if (success) {
- sc.points.push_back(s);
+ sc.points.push_back(s);
}
}
@@ -300,19 +328,19 @@ void Inkscape::ObjectSnapper::_collectPaths(Inkscape::SnapPreferences::PointType
// first point and store the collection for later use. This significantly improves the performance
if (first_point) {
_clear_paths();
-
+
// Determine the type of bounding box we should snap to
SPItem::BBoxType bbox_type = SPItem::GEOMETRIC_BBOX;
-
+
bool p_is_a_node = t & Inkscape::SnapPreferences::SNAPPOINT_NODE;
-
+
if (_snap_to_bboxpath) {
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
int prefs_bbox = prefs->getBool("/tools/bounding_box", 0);
- bbox_type = !prefs_bbox ?
+ bbox_type = !prefs_bbox ?
SPItem::APPROXIMATE_BBOX : SPItem::GEOMETRIC_BBOX;
}
-
+
// Consider the page border for snapping
if (_snap_to_page_border) {
Geom::PathVector *border_path = _getBorderPathv();
@@ -320,7 +348,7 @@ void Inkscape::ObjectSnapper::_collectPaths(Inkscape::SnapPreferences::PointType
_paths_to_snap_to->push_back(border_path);
}
}
-
+
for (std::vector<SnapCandidate>::const_iterator i = _candidates->begin(); i != _candidates->end(); i++) {
/* Transform the requested snap point to this item's coordinates */
@@ -335,7 +363,7 @@ void Inkscape::ObjectSnapper::_collectPaths(Inkscape::SnapPreferences::PointType
i2doc = sp_item_i2doc_affine((*i).item);
root_item = (*i).item;
}
-
+
//Build a list of all paths considered for snapping to
//Add the item's path to snap to
@@ -361,10 +389,10 @@ void Inkscape::ObjectSnapper::_collectPaths(Inkscape::SnapPreferences::PointType
}
if (!very_lenghty_prose && !very_complex_path) {
- SPCurve *curve = curve_for_item(root_item);
+ SPCurve *curve = curve_for_item(root_item);
if (curve) {
// We will get our own copy of the path, which must be freed at some point
- Geom::PathVector *borderpathv = pathvector_for_curve(root_item, curve, true, true, Geom::identity(), (*i).additional_affine);
+ Geom::PathVector *borderpathv = pathvector_for_curve(root_item, curve, true, true, Geom::identity(), (*i).additional_affine);
_paths_to_snap_to->push_back(borderpathv); // Perhaps for speed, get a reference to the Geom::pathvector, and store the transformation besides it.
curve->unref();
}
@@ -377,12 +405,12 @@ void Inkscape::ObjectSnapper::_collectPaths(Inkscape::SnapPreferences::PointType
if (!(_strict_snapping && p_is_a_node)) {
// Discard the bbox of a clipped path / mask, because we don't want to snap to both the bbox
// of the item AND the bbox of the clipping path at the same time
- if (!(*i).clip_or_mask) {
- Geom::OptRect rect;
- sp_item_invoke_bbox(root_item, rect, i2doc, TRUE, bbox_type);
+ if (!(*i).clip_or_mask) {
+ Geom::OptRect rect;
+ sp_item_invoke_bbox(root_item, rect, i2doc, TRUE, bbox_type);
if (rect) {
- Geom::PathVector *path = _getPathvFromRect(*rect);
- _paths_to_snap_to->push_back(path);
+ Geom::PathVector *path = _getPathvFromRect(*rect);
+ _paths_to_snap_to->push_back(path);
}
}
}
@@ -390,7 +418,7 @@ void Inkscape::ObjectSnapper::_collectPaths(Inkscape::SnapPreferences::PointType
}
}
}
-
+
void Inkscape::ObjectSnapper::_snapPaths(SnappedConstraints &sc,
Inkscape::SnapPreferences::PointType const &t,
Geom::Point const &p,
{
_collectPaths(t, first_point);
// Now we can finally do the real snapping, using the paths collected above
-
- g_assert(_snapmanager->getDesktop() != NULL);
+
+ g_assert(_snapmanager->getDesktop() != NULL);
Geom::Point const p_doc = _snapmanager->getDesktop()->dt2doc(p);
-
+
bool const node_tool_active = _snap_to_itempath && selected_path != NULL;
-
+
if (first_point) {
/* findCandidates() is used for snapping to both paths and nodes. It ignores the path that is
- * currently being edited, because that path requires special care: when snapping to nodes
+ * currently being edited, because that path requires special care: when snapping to nodes
* only the unselected nodes of that path should be considered, and these will be passed on separately.
* This path must not be ignored however when snapping to the paths, so we add it here
- * manually when applicable.
- *
+ * manually when applicable.
+ *
* Note that this path must be the last in line!
- * */
- if (node_tool_active) {
- SPCurve *curve = curve_for_item(SP_ITEM(selected_path));
+ * */
+ if (node_tool_active) {
+ SPCurve *curve = curve_for_item(SP_ITEM(selected_path));
if (curve) {
Geom::PathVector *pathv = pathvector_for_curve(SP_ITEM(selected_path), curve, true, true, Geom::identity(), Geom::identity()); // We will get our own copy of the path, which must be freed at some point
_paths_to_snap_to->push_back(pathv);
}
}
}
-
+
for (std::vector<Geom::PathVector*>::const_iterator it_p = _paths_to_snap_to->begin(); it_p != _paths_to_snap_to->end(); it_p++) {
- bool const being_edited = (node_tool_active && (*it_p) == _paths_to_snap_to->back());
+ bool const being_edited = (node_tool_active && (*it_p) == _paths_to_snap_to->back());
//if true then this pathvector it_pv is currently being edited in the node tool
-
+
// char * svgd = sp_svg_write_path(**it_p);
- // std::cout << "Dumping the pathvector: " << svgd << std::endl;
-
+ // std::cout << "Dumping the pathvector: " << svgd << std::endl;
+
for(Geom::PathVector::iterator it_pv = (*it_p)->begin(); it_pv != (*it_p)->end(); ++it_pv) {
// Find a nearest point for each curve within this path
// n curves will return n time values with 0 <= t <= 1
std::vector<double> anp = (*it_pv).nearestPointPerCurve(p_doc);
-
+
std::vector<double>::const_iterator np = anp.begin();
unsigned int index = 0;
for (; np != anp.end(); np++, index++) {
Geom::Curve const *curve = &((*it_pv).at_index(index));
Geom::Point const sp_doc = curve->pointAt(*np);
-
+
bool c1 = true;
- bool c2 = true;
+ bool c2 = true;
if (being_edited) {
/* If the path is being edited, then we should only snap though to stationary pieces of the path
- * and not to the pieces that are being dragged around. This way we avoid
+ * and not to the pieces that are being dragged around. This way we avoid
* self-snapping. For this we check whether the nodes at both ends of the current
- * piece are unselected; if they are then this piece must be stationary
- */
+ * piece are unselected; if they are then this piece must be stationary
+ */
g_assert(unselected_nodes != NULL);
- Geom::Point start_pt = _snapmanager->getDesktop()->doc2dt(curve->pointAt(0));
- Geom::Point end_pt = _snapmanager->getDesktop()->doc2dt(curve->pointAt(1));
- c1 = isUnselectedNode(start_pt, unselected_nodes);
- c2 = isUnselectedNode(end_pt, unselected_nodes);
+ Geom::Point start_pt = _snapmanager->getDesktop()->doc2dt(curve->pointAt(0));
+ Geom::Point end_pt = _snapmanager->getDesktop()->doc2dt(curve->pointAt(1));
+ c1 = isUnselectedNode(start_pt, unselected_nodes);
+ c2 = isUnselectedNode(end_pt, unselected_nodes);
/* Unfortunately, this might yield false positives for coincident nodes. Inkscape might therefore mistakenly
* snap to path segments that are not stationary. There are at least two possible ways to overcome this:
* - Linking the individual nodes of the SPPath we have here, to the nodes of the NodePath::SubPath class as being
* used in sp_nodepath_selected_nodes_move. This class has a member variable called "selected". For this the nodes
* should be in the exact same order for both classes, so we can index them
* - Replacing the SPPath being used here by the the NodePath::SubPath class; but how?
- */
+ */
}
-
- Geom::Point const sp_dt = _snapmanager->getDesktop()->doc2dt(sp_doc);
+
+ Geom::Point const sp_dt = _snapmanager->getDesktop()->doc2dt(sp_doc);
if (!being_edited || (c1 && c2)) {
Geom::Coord const dist = Geom::distance(sp_doc, p_doc);
if (dist < getSnapperTolerance()) {
- sc.curves.push_back(Inkscape::SnappedCurve(from_2geom(sp_dt), dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, curve));
+ sc.curves.push_back(Inkscape::SnappedCurve(from_2geom(sp_dt), dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, curve));
}
}
- }
- } // End of: for (Geom::PathVector::iterator ....)
- }
+ }
+ } // End of: for (Geom::PathVector::iterator ....)
+ }
}
-/* Returns true if point is coincident with one of the unselected nodes */
+/* Returns true if point is coincident with one of the unselected nodes */
bool Inkscape::ObjectSnapper::isUnselectedNode(Geom::Point const &point, std::vector<Geom::Point> const *unselected_nodes) const
{
if (unselected_nodes == NULL) {
return false;
}
-
+
if (unselected_nodes->size() == 0) {
return false;
}
-
+
for (std::vector<Geom::Point>::const_iterator i = unselected_nodes->begin(); i != unselected_nodes->end(); i++) {
if (Geom::L2(point - *i) < 1e-4) {
return true;
- }
- }
-
- return false;
+ }
+ }
+
+ return false;
}
void Inkscape::ObjectSnapper::_snapPathsConstrained(SnappedConstraints &sc,
bool const &first_point,
ConstraintLine const &c) const
{
-
+
_collectPaths(t, first_point);
-
+
// Now we can finally do the real snapping, using the paths collected above
-
+
g_assert(_snapmanager->getDesktop() != NULL);
- Geom::Point const p_doc = _snapmanager->getDesktop()->dt2doc(p);
-
+ Geom::Point const p_doc = _snapmanager->getDesktop()->dt2doc(p);
+
Geom::Point direction_vector = c.getDirection();
if (!is_zero(direction_vector)) {
direction_vector = Geom::unit_vector(direction_vector);
}
-
+
Geom::Point const p1_on_cl = c.hasPoint() ? c.getPoint() : p;
Geom::Point const p2_on_cl = p1_on_cl + direction_vector;
-
- // The intersection point of the constraint line with any path,
+
+ // The intersection point of the constraint line with any path,
// must lie within two points on the constraintline: p_min_on_cl and p_max_on_cl
// The distance between those points is twice the snapping tolerance
Geom::Point const p_proj_on_cl = project_on_linesegment(p, p1_on_cl, p2_on_cl);
- Geom::Point const p_min_on_cl = _snapmanager->getDesktop()->dt2doc(p_proj_on_cl - getSnapperTolerance() * direction_vector);
+ Geom::Point const p_min_on_cl = _snapmanager->getDesktop()->dt2doc(p_proj_on_cl - getSnapperTolerance() * direction_vector);
Geom::Point const p_max_on_cl = _snapmanager->getDesktop()->dt2doc(p_proj_on_cl + getSnapperTolerance() * direction_vector);
-
+
Geom::Path cl;
- std::vector<Geom::Path> clv;
+ std::vector<Geom::Path> clv;
cl.start(p_min_on_cl);
cl.appendNew<Geom::LineSegment>(p_max_on_cl);
clv.push_back(cl);
-
+
for (std::vector<Geom::PathVector*>::const_iterator k = _paths_to_snap_to->begin(); k != _paths_to_snap_to->end(); k++) {
- if (*k) {
+ if (*k) {
Geom::CrossingSet cs = Geom::crossings(clv, *(*k));
if (cs.size() > 0) {
// We need only the first element of cs, because cl is only a single straight linesegment
// This first element contains a vector filled with crossings of cl with *k
- for (std::vector<Geom::Crossing>::const_iterator m = cs[0].begin(); m != cs[0].end(); m++) {
+ for (std::vector<Geom::Crossing>::const_iterator m = cs[0].begin(); m != cs[0].end(); m++) {
if ((*m).ta >= 0 && (*m).ta <= 1 ) {
// Reconstruct the point of intersection
Geom::Point p_inters = p_min_on_cl + ((*m).ta) * (p_max_on_cl - p_min_on_cl);
// When it's within snapping range, then return it
- // (within snapping range == between p_min_on_cl and p_max_on_cl == 0 < ta < 1)
+ // (within snapping range == between p_min_on_cl and p_max_on_cl == 0 < ta < 1)
Geom::Coord dist = Geom::L2(_snapmanager->getDesktop()->dt2doc(p_proj_on_cl) - p_inters);
SnappedPoint s(_snapmanager->getDesktop()->doc2dt(p_inters), SNAPTARGET_PATH, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
sc.points.push_back(s);
- }
- }
+ }
+ }
}
}
}
std::vector<SPItem const *> const *it,
std::vector<Geom::Point> *unselected_nodes) const
{
- if (_snap_enabled == false || _snapmanager->snapprefs.getSnapFrom(t) == false ) {
+ if (_snap_enabled == false || _snapmanager->snapprefs.getSnapFrom(t) == false ) {
return;
}
Geom::Rect const local_bbox_to_snap = bbox_to_snap ? *bbox_to_snap : Geom::Rect(p, p);
_findCandidates(sp_document_root(_snapmanager->getDocument()), it, first_point, local_bbox_to_snap, TRANSL_SNAP_XY, false, Geom::identity());
}
-
+
if (_snap_to_itemnode || _snap_to_bboxnode || _snap_to_page_border) {
_snapNodes(sc, t, p, first_point, unselected_nodes);
}
-
+
if (_snap_to_itempath || _snap_to_bboxpath || _snap_to_page_border) {
unsigned n = (unselected_nodes == NULL) ? 0 : unselected_nodes->size();
if (n > 0) {
- /* While editing a path in the node tool, findCandidates must ignore that path because
+ /* While editing a path in the node tool, findCandidates must ignore that path because
* of the node snapping requirements (i.e. only unselected nodes must be snapable).
* That path must not be ignored however when snapping to the paths, so we add it here
* manually when applicable
- */
+ */
SPPath *path = NULL;
if (it != NULL) {
g_assert(SP_IS_PATH(*it->begin()));
g_assert(it->size() == 1);
path = SP_PATH(*it->begin());
}
- _snapPaths(sc, t, p, first_point, unselected_nodes, path);
+ _snapPaths(sc, t, p, first_point, unselected_nodes, path);
} else {
- _snapPaths(sc, t, p, first_point, NULL, NULL);
- }
+ _snapPaths(sc, t, p, first_point, NULL, NULL);
+ }
}
}
Geom::Rect const local_bbox_to_snap = bbox_to_snap ? *bbox_to_snap : Geom::Rect(p, p);
_findCandidates(sp_document_root(_snapmanager->getDocument()), it, first_point, local_bbox_to_snap, TRANSL_SNAP_XY, false, Geom::identity());
}
-
+
// A constrained snap, is a snap in only one degree of freedom (specified by the constraint line).
// This is usefull 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).
-
+
// When snapping to objects, we either snap to their nodes or their paths. It is however very
// unlikely that any node will be exactly at the constrained line, so for a constrained snap
// to objects we will only consider the object's paths. Beside, the nodes will be at these paths,
- // so we will more or less snap to them anyhow.
+ // so we will more or less snap to them anyhow.
if (_snap_to_itempath || _snap_to_bboxpath || _snap_to_page_border) {
_snapPathsConstrained(sc, t, p, first_point, c);
/* Get a list of all the SPItems that we will try to snap to */
std::vector<SPItem*> cand;
std::vector<SPItem const *> const it; //just an empty list
-
+
DimensionToSnap snap_dim;
if (guide_normal == to_2geom(component_vectors[Geom::Y])) {
snap_dim = GUIDE_TRANSL_SNAP_Y;
} else {
snap_dim = ANGLED_GUIDE_TRANSL_SNAP;
}
-
- // We don't support ANGLED_GUIDE_ROT_SNAP yet.
-
+
+ // We don't support ANGLED_GUIDE_ROT_SNAP yet.
+
// It would be cool to allow the user to rotate a guide by dragging it, instead of
- // only translating it. (For example when CTRL is pressed). We will need an UI part
- // for that first; and some important usability choices need to be made:
+ // only translating it. (For example when CTRL is pressed). We will need an UI part
+ // for that first; and some important usability choices need to be made:
// E.g. which point should be used for pivoting? A previously snapped point,
// or a transformation center (which can be moved after clicking for the
// second time on an object; but should this point then be constrained to the
// line, or can it be located anywhere?)
-
+
_findCandidates(sp_document_root(_snapmanager->getDocument()), &it, true, Geom::Rect(p, p), snap_dim, false, Geom::identity());
_snapTranslatingGuideToNodes(sc, Inkscape::SnapPreferences::SNAPPOINT_GUIDE, p, guide_normal);
- // _snapRotatingGuideToNodes has not been implemented yet.
+ // _snapRotatingGuideToNodes has not been implemented yet.
}
/**
return (_snap_enabled && _snapmanager->snapprefs.getSnapModeGuide() && snap_to_something);
}
-void Inkscape::ObjectSnapper::_clear_paths() const
+void Inkscape::ObjectSnapper::_clear_paths() const
{
for (std::vector<Geom::PathVector*>::const_iterator k = _paths_to_snap_to->begin(); k != _paths_to_snap_to->end(); k++) {
g_free(*k);
Geom::PathVector* Inkscape::ObjectSnapper::_getBorderPathv() const
{
Geom::Rect const border_rect = Geom::Rect(Geom::Point(0,0), Geom::Point(sp_document_width(_snapmanager->getDocument()),sp_document_height(_snapmanager->getDocument())));
- return _getPathvFromRect(border_rect);
+ return _getPathvFromRect(border_rect);
}
Geom::PathVector* Inkscape::ObjectSnapper::_getPathvFromRect(Geom::Rect const rect) const
@@ -701,7 +729,7 @@ Geom::PathVector* Inkscape::ObjectSnapper::_getPathvFromRect(Geom::Rect const re
return dummy;
} else {
return NULL;
- }
+ }
}
void Inkscape::ObjectSnapper::_getBorderNodes(std::vector<Geom::Point> *points) const
diff --git a/src/object-snapper.h b/src/object-snapper.h
index f235ae5661c6d491f63e07d496494e3221a8b227..9972677e0c301c1461b2960a2834c6f05380ca90 100644 (file)
--- a/src/object-snapper.h
+++ b/src/object-snapper.h
* Carl Hetherington <inkscape@carlh.net>
* Diederik van Lierop <mail@diedenrezi.nl>
*
- * Copyright (C) 2005 - 2008 Authors
+ * Copyright (C) 2005 - 2008 Authors
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
{
class SnapCandidate
-
+
{
public:
SnapCandidate(SPItem* item, bool clip_or_mask, Geom::Matrix _additional_affine);
~SnapCandidate();
-
+
SPItem* item; // An item that is to be considered for snapping to
bool clip_or_mask; // If true, then item refers to a clipping path or a mask
-
- /* To find out the absolute position of a clipping path or mask, we not only need to know
- * the transformation of the clipping path or mask itself, but also the transformation of
+
+ /* To find out the absolute position of a clipping path or mask, we not only need to know
+ * the transformation of the clipping path or mask itself, but also the transformation of
* the object to which the clip or mask is being applied; that transformation is stored here
*/
- Geom::Matrix additional_affine;
+ Geom::Matrix additional_affine;
};
class ObjectSnapper : public Snapper
{
public:
- ObjectSnapper(SnapManager const *sm, Geom::Coord const d);
+ ObjectSnapper(SnapManager *sm, Geom::Coord const d);
~ObjectSnapper();
enum DimensionToSnap {
- GUIDE_TRANSL_SNAP_X, // For snapping a vertical guide (normal in the X-direction) to objects,
+ GUIDE_TRANSL_SNAP_X, // For snapping a vertical guide (normal in the X-direction) to objects,
GUIDE_TRANSL_SNAP_Y, // For snapping a horizontal guide (normal in the Y-direction) to objects
ANGLED_GUIDE_TRANSL_SNAP, // For snapping an angled guide, while translating it accross the desktop
ANGLED_GUIDE_ROT_SNAP, // For snapping an angled guide, while rotating it around some pivot point
void guideSnap(SnappedConstraints &sc,
Geom::Point const &p,
Geom::Point const &guide_normal) const;
-
+
bool ThisSnapperMightSnap() const;
bool GuidesMightSnap() const;
-
+
void freeSnap(SnappedConstraints &sc,
Inkscape::SnapPreferences::PointType const &t,
Geom::Point const &p,
void constrainedSnap(SnappedConstraints &sc,
Inkscape::SnapPreferences::PointType const &t,
Geom::Point const &p,
- bool const &first_point,
+ bool const &first_point,
Geom::OptRect const &bbox_to_snap,
ConstraintLine const &c,
std::vector<SPItem const *> const *it) const;
-
+
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<SnapCandidate> *_candidates;
+ std::vector<SnapCandidate> *_candidates;
std::vector<Geom::Point> *_points_to_snap_to;
std::vector<Geom::PathVector*> *_paths_to_snap_to;
-
+
void _findCandidates(SPObject* parent,
std::vector<SPItem const *> const *it,
bool const &first_point,
DimensionToSnap snap_dim,
bool const _clip_or_mask,
Geom::Matrix const additional_affine) const;
-
+
void _snapNodes(SnappedConstraints &sc,
Inkscape::SnapPreferences::PointType const &t,
Geom::Point const &p, // in desktop coordinates
bool const &first_point,
std::vector<Geom::Point> *unselected_nodes) const; // in desktop coordinates
-
+
void _snapTranslatingGuideToNodes(SnappedConstraints &sc,
Inkscape::SnapPreferences::PointType const &t,
Geom::Point const &p,
Geom::Point const &guide_normal) const;
-
+
void _collectNodes(Inkscape::SnapPreferences::PointType const &t,
bool const &first_point) const;
-
+
void _snapPaths(SnappedConstraints &sc,
- Inkscape::SnapPreferences::PointType const &t,
+ Inkscape::SnapPreferences::PointType const &t,
Geom::Point const &p, // in desktop coordinates
bool const &first_point,
std::vector<Geom::Point> *unselected_nodes, // in desktop coordinates
SPPath const *selected_path) const;
-
+
void _snapPathsConstrained(SnappedConstraints &sc,
Inkscape::SnapPreferences::PointType const &t,
Geom::Point const &p, // in desktop coordinates
bool const &first_point,
ConstraintLine const &c) const;
-
+
bool isUnselectedNode(Geom::Point const &point, std::vector<Geom::Point> const *unselected_nodes) const;
-
- void _collectPaths(Inkscape::SnapPreferences::PointType const &t,
+
+ void _collectPaths(Inkscape::SnapPreferences::PointType const &t,
bool const &first_point) const;
-
+
void _clear_paths() const;
Geom::PathVector* _getBorderPathv() const;
Geom::PathVector* _getPathvFromRect(Geom::Rect const rect) const;
void _getBorderNodes(std::vector<Geom::Point> *points) const;
-
+
bool _snap_to_itemnode;
bool _snap_to_itempath;
bool _snap_to_bboxnode;
bool _snap_to_bboxpath;
bool _snap_to_page_border;
-
- //If enabled, then bbox corners will only snap to bboxes,
+
+ //If enabled, then bbox corners will only snap to bboxes,
//and nodes will only snap to nodes and paths. We will not
//snap bbox corners to nodes, or nodes to bboxes.
//(snapping to grids and guides is not affected by this)
- bool _strict_snapping;
+ bool _strict_snapping;
};
}
diff --git a/src/snap-preferences.h b/src/snap-preferences.h
index d98cd7cef2c7e08f4ed682de0e646621616ad14c..a52e0cfd9a32d079ffee2f9f4a0846af3387d586 100644 (file)
--- a/src/snap-preferences.h
+++ b/src/snap-preferences.h
{
public:
SnapPreferences();
-
+
/// Point types to snap.
typedef int PointType;
static const PointType SNAPPOINT_NODE;
void setSnapIntersectionGG(bool enabled) {_intersectionGG = enabled;}
void setSnapIntersectionCS(bool enabled) {_intersectionCS = enabled;}
void setSnapSmoothNodes(bool enabled) {_smoothNodes = enabled;}
+ void setSnapMidpoints(bool enabled) {_midpoints = enabled;}
bool getSnapIntersectionGG() const {return _intersectionGG;}
- bool getSnapIntersectionCS() const {return _intersectionCS;}
+ bool getSnapIntersectionCS() const {return _intersectionCS;}
bool getSnapSmoothNodes() const {return _smoothNodes;}
-
+ bool getSnapMidpoints() const {return _midpoints;}
+
void setIncludeItemCenter(bool enabled) {_include_item_center = enabled;}
bool getIncludeItemCenter() const {return _include_item_center;}
-
- void setSnapEnabledGlobally(bool enabled) {_snap_enabled_globally = enabled;}
- bool getSnapEnabledGlobally() const {return _snap_enabled_globally;}
-
+
+ void setSnapEnabledGlobally(bool enabled) {_snap_enabled_globally = enabled;}
+ bool getSnapEnabledGlobally() const {return _snap_enabled_globally;}
+
void setSnapPostponedGlobally(bool postponed) {_snap_postponed_globally = postponed;}
bool getSnapPostponedGlobally() const {return _snap_postponed_globally;}
-
+
void setSnapFrom(PointType t, bool s);
bool getSnapFrom(PointType t) const;
-
+
private:
bool _include_item_center; //If true, snapping nodes will also snap the item's center
- bool _intersectionGG;
- bool _intersectionCS;
+ bool _intersectionGG; //Consider snapping to intersections of grid and guides
+ bool _intersectionCS; //Consider snapping to intersections of curves
bool _smoothNodes;
+ bool _midpoints;
bool _snap_enabled_globally; // Toggles ALL snapping
bool _snap_postponed_globally; // Hold all snapping temporarily when the mouse is moving fast
PointType _snap_from; ///< bitmap of point types that we will snap from
-
+
};
}
diff --git a/src/snap.h b/src/snap.h
index b8d9fdd25604680c25bba39e4d318624c2d14a72..14adf399facbb4e564653ee6a7f068beb55e776b 100644 (file)
--- a/src/snap.h
+++ b/src/snap.h
STRETCH,
SKEW
};
-
+
SnapManager(SPNamedView const *v);
typedef std::list<const Inkscape::Snapper*> SnapperList;
bool someSnapperMightSnap() const;
-
+
void setup(SPDesktop const *desktop, bool snapindicator = true, SPItem const *item_to_ignore = NULL, std::vector<Geom::Point> *unselected_nodes = NULL);
void setup(SPDesktop const *desktop, bool snapindicator, std::vector<SPItem const *> &items_to_ignore, std::vector<Geom::Point> *unselected_nodes = NULL);
- // freeSnapReturnByRef() is preferred over freeSnap(), because it only returns a
- // point if snapping has occured (by overwriting p); otherwise p is untouched
+ // freeSnapReturnByRef() is preferred over freeSnap(), because it only returns a
+ // point if snapping has occured (by overwriting p); otherwise p is untouched
void freeSnapReturnByRef(Inkscape::SnapPreferences::PointType point_type,
Geom::Point &p,
bool first_point = true,
Geom::OptRect const &bbox_to_snap = Geom::OptRect()) const;
-
+
Inkscape::SnappedPoint freeSnap(Inkscape::SnapPreferences::PointType point_type,
Geom::Point const &p,
bool first_point = true,
Geom::OptRect const &bbox_to_snap = Geom::OptRect() ) const;
-
+
Geom::Point multipleOfGridPitch(Geom::Point const &t) const;
-
- // constrainedSnapReturnByRef() is preferred over constrainedSnap(), because it only returns a
+
+ // constrainedSnapReturnByRef() is preferred over constrainedSnap(), because it only returns a
// point, by overwriting p, if snapping has occured; otherwise p is untouched
void constrainedSnapReturnByRef(Inkscape::SnapPreferences::PointType point_type,
Geom::Point &p,
Inkscape::Snapper::ConstraintLine const &constraint,
bool first_point = true,
Geom::OptRect const &bbox_to_snap = Geom::OptRect()) const;
-
+
Inkscape::SnappedPoint constrainedSnap(Inkscape::SnapPreferences::PointType point_type,
Geom::Point const &p,
Inkscape::Snapper::ConstraintLine const &constraint,
bool first_point = true,
Geom::OptRect const &bbox_to_snap = Geom::OptRect()) const;
-
+
void guideSnap(Geom::Point &p, Geom::Point const &guide_normal) const;
Inkscape::SnappedPoint freeSnapTranslation(Inkscape::SnapPreferences::PointType point_type,
Geom::Point const &s, // s[0] = skew factor, s[1] = scale factor
Geom::Point const &o,
Geom::Dim2 d) const;
-
+
Inkscape::GuideSnapper guide; ///< guide snapper
Inkscape::ObjectSnapper object; ///< snapper to other objects
Inkscape::SnapPreferences snapprefs;
SnapperList getSnappers() const;
SnapperList getGridSnappers() const;
-
+
SPDesktop const *getDesktop() const {return _desktop;}
SPNamedView const *getNamedView() const {return _named_view;}
SPDocument *getDocument() const;
-
+
protected:
SPNamedView const *_named_view;
private:
- std::vector<SPItem const *> *_items_to_ignore;
+ std::vector<SPItem const *> *_items_to_ignore;
SPItem const *_item_to_ignore;
SPDesktop const *_desktop;
bool _snapindicator;
- std::vector<Geom::Point> *_unselected_nodes;
-
+ std::vector<Geom::Point> *_unselected_nodes;
+
Inkscape::SnappedPoint _snapTransformed(Inkscape::SnapPreferences::PointType type,
std::vector<Geom::Point> const &points,
Geom::Point const &pointer,
Geom::Point const &origin,
Geom::Dim2 dim,
bool uniform) const;
-
- Geom::Point _transformPoint(Geom::Point const &p,
- Transformation const transformation_type,
- Geom::Point const &transformation,
- Geom::Point const &origin,
- Geom::Dim2 const dim,
- bool const uniform) const;
-
- void _displaySnapsource(Inkscape::SnapPreferences::PointType point_type, Geom::Point const &p) const;
-
+
+ Geom::Point _transformPoint(Geom::Point const &p,
+ Transformation const transformation_type,
+ Geom::Point const &transformation,
+ Geom::Point const &origin,
+ Geom::Dim2 const dim,
+ bool const uniform) const;
+
+ void _displaySnapsource(Inkscape::SnapPreferences::PointType point_type, Geom::Point const &p) const;
+
Inkscape::SnappedPoint findBestSnap(Geom::Point const &p, SnappedConstraints &sc, bool constrained) const;
};
diff --git a/src/snapped-curve.cpp b/src/snapped-curve.cpp
index 7b65c5c655b0751f46d64a77008b000ed6d62b10..fa2d561cd2e161c299e8f5e9935a6af39d275124 100644 (file)
--- a/src/snapped-curve.cpp
+++ b/src/snapped-curve.cpp
// There might be multiple intersections: find the closest
Geom::Coord best_dist = NR_HUGE;
Geom::Point best_p = Geom::Point(NR_HUGE, NR_HUGE);
- for (std::vector<Geom::Crossing>::const_iterator i = cs.begin(); i != cs.end(); i++) {
+ for (Geom::Crossings::const_iterator i = cs.begin(); i != cs.end(); i++) {
Geom::Point p_ix = this->_curve->pointAt((*i).ta);
Geom::Coord dist = Geom::distance(p_ix, p);
if (dist < best_dist) {
diff --git a/src/snapper.cpp b/src/snapper.cpp
index 3dd58737ee015678243bed32d672ed84c2e09c31..492e4ca4d019b4da14ac7a72094b470f78fa4504 100644 (file)
--- a/src/snapper.cpp
+++ b/src/snapper.cpp
* \param nv Named view.
* \param d Snap tolerance.
*/
-Inkscape::Snapper::Snapper(SnapManager const *sm, Geom::Coord const t) :
- _snapmanager(sm),
+Inkscape::Snapper::Snapper(SnapManager *sm, Geom::Coord const t) :
+ _snapmanager(sm),
_snap_enabled(true),
_snapper_tolerance(std::max(t, 1.0))
{
diff --git a/src/snapper.h b/src/snapper.h
index 0c405fd2bfadced3d9108896a65f25f9bd177311..f6e1a086e8a18c301e645e435c57c673fe526328 100644 (file)
--- a/src/snapper.h
+++ b/src/snapper.h
{
public:
Snapper() {}
- Snapper(SnapManager const *sm, ::Geom::Coord const t);
+ Snapper(SnapManager *sm, ::Geom::Coord const t);
virtual ~Snapper() {}
-
+
void setSnapperTolerance(Geom::Coord t);
Geom::Coord getSnapperTolerance() const; //returns the tolerance of the snapper in screen pixels (i.e. independent of zoom)
bool getSnapperAlwaysSnap() const; //if true, then the snapper will always snap, regardless of its tolerance
Geom::Point getDirection() const {
return _direction;
}
-
+
void setPoint(Geom::Point const &p) {
_point = p;
- _has_point = true;
+ _has_point = true;
}
private:
std::vector<SPItem const *> const */*it*/) const {};
protected:
- SnapManager const *_snapmanager;
-
+ SnapManager *_snapmanager;
+
bool _snap_enabled; ///< true if this snapper is enabled, otherwise false
private:
diff --git a/src/sp-namedview.cpp b/src/sp-namedview.cpp
index 2b7c8bbc44178eb30f82cc8be2b04a7aa3f55388..c46f30e0696ddca39e83e758b3b64b2b1d3349a2 100644 (file)
--- a/src/sp-namedview.cpp
+++ b/src/sp-namedview.cpp
nv->guides = NULL;
nv->viewcount = 0;
nv->grids = NULL;
-
+
nv->default_layer_id = 0;
nv->connector_spacing = defaultConnSpacing;
@@ -248,6 +248,7 @@ static void sp_namedview_build(SPObject *object, SPDocument *document, Inkscape:
sp_object_read_attr(object, "inkscape:snap-guide");
sp_object_read_attr(object, "inkscape:snap-center");
sp_object_read_attr(object, "inkscape:snap-smooth-nodes");
+ sp_object_read_attr(object, "inkscape:snap-midpoints");
sp_object_read_attr(object, "inkscape:snap-intersection-grid-guide");
sp_object_read_attr(object, "inkscape:snap-intersection-paths");
sp_object_read_attr(object, "inkscape:object-paths");
@@ -469,7 +470,11 @@ static void sp_namedview_set(SPObject *object, unsigned int key, const gchar *va
case SP_ATTR_INKSCAPE_SNAP_SMOOTH_NODES:
nv->snap_manager.snapprefs.setSnapSmoothNodes(value ? sp_str_to_bool(value) : FALSE);
object->requestModified(SP_OBJECT_MODIFIED_FLAG);
- break;
+ break;
+ case SP_ATTR_INKSCAPE_SNAP_MIDPOINTS:
+ nv->snap_manager.snapprefs.setSnapMidpoints(value ? sp_str_to_bool(value) : FALSE);
+ object->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
case SP_ATTR_INKSCAPE_SNAP_GUIDE:
nv->snap_manager.snapprefs.setSnapModeGuide(value ? sp_str_to_bool(value) : FALSE);
object->requestModified(SP_OBJECT_MODIFIED_FLAG);
@@ -501,7 +506,7 @@ static void sp_namedview_set(SPObject *object, unsigned int key, const gchar *va
case SP_ATTR_INKSCAPE_SNAP_PAGE:
nv->snap_manager.object.setSnapToPageBorder(value ? sp_str_to_bool(value) : FALSE);
object->requestModified(SP_OBJECT_MODIFIED_FLAG);
- break;
+ break;
case SP_ATTR_INKSCAPE_CURRENT_LAYER:
nv->default_layer_id = value ? g_quark_from_string(value) : 0;
object->requestModified(SP_OBJECT_MODIFIED_FLAG);
diff --git a/src/sp-shape.cpp b/src/sp-shape.cpp
index d3f357e7688f51e1d6a025aa04eebe1d7738d0ed..7ee2af1ec97321eecde89ff6d8331847cebf773e 100644 (file)
--- a/src/sp-shape.cpp
+++ b/src/sp-shape.cpp
#include <2geom/rect.h>
#include <2geom/transforms.h>
#include <2geom/pathvector.h>
+#include <2geom/path-intersection.h>
#include "helper/geom.h"
#include "helper/geom-nodetype.h"
GType
sp_shape_get_type (void)
{
- static GType type = 0;
- if (!type) {
- GTypeInfo info = {
- sizeof (SPShapeClass),
- NULL, NULL,
- (GClassInitFunc) sp_shape_class_init,
- NULL, NULL,
- sizeof (SPShape),
- 16,
- (GInstanceInitFunc) sp_shape_init,
- NULL, /* value_table */
- };
- type = g_type_register_static (SP_TYPE_LPE_ITEM, "SPShape", &info, (GTypeFlags)0);
- }
- return type;
+ static GType type = 0;
+ if (!type) {
+ GTypeInfo info = {
+ sizeof (SPShapeClass),
+ NULL, NULL,
+ (GClassInitFunc) sp_shape_class_init,
+ NULL, NULL,
+ sizeof (SPShape),
+ 16,
+ (GInstanceInitFunc) sp_shape_init,
+ NULL, /* value_table */
+ };
+ type = g_type_register_static (SP_TYPE_LPE_ITEM, "SPShape", &info, (GTypeFlags)0);
+ }
+ return type;
}
/**
gobject_class->finalize = sp_shape_finalize;
- sp_object_class->build = sp_shape_build;
- sp_object_class->release = sp_shape_release;
+ sp_object_class->build = sp_shape_build;
+ sp_object_class->release = sp_shape_release;
sp_object_class->set = sp_shape_set;
- sp_object_class->update = sp_shape_update;
- sp_object_class->modified = sp_shape_modified;
+ sp_object_class->update = sp_shape_update;
+ sp_object_class->modified = sp_shape_modified;
sp_object_class->write = sp_shape_write;
- item_class->bbox = sp_shape_bbox;
- item_class->print = sp_shape_print;
- item_class->show = sp_shape_show;
- item_class->hide = sp_shape_hide;
+ item_class->bbox = sp_shape_bbox;
+ item_class->print = sp_shape_print;
+ item_class->show = sp_shape_show;
+ item_class->hide = sp_shape_hide;
item_class->snappoints = sp_shape_snappoints;
lpe_item_class->update_patheffect = NULL;
@@ -174,7 +175,7 @@ sp_shape_build (SPObject *object, SPDocument *document, Inkscape::XML::Node *rep
for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) {
sp_shape_set_marker (object, i, object->style->marker[i].value);
- }
+ }
}
/**
@@ -190,31 +191,31 @@ sp_shape_build (SPObject *object, SPDocument *document, Inkscape::XML::Node *rep
static void
sp_shape_release (SPObject *object)
{
- SPItem *item;
- SPShape *shape;
- SPItemView *v;
- int i;
-
- item = (SPItem *) object;
- shape = (SPShape *) object;
-
- for (i=SP_MARKER_LOC_START; i<SP_MARKER_LOC_QTY; i++) {
- if (shape->marker[i]) {
- for (v = item->display; v != NULL; v = v->next) {
- sp_marker_hide ((SPMarker *) shape->marker[i], NR_ARENA_ITEM_GET_KEY (v->arenaitem) + i);
- }
+ SPItem *item;
+ SPShape *shape;
+ SPItemView *v;
+ int i;
+
+ item = (SPItem *) object;
+ shape = (SPShape *) object;
+
+ for (i=SP_MARKER_LOC_START; i<SP_MARKER_LOC_QTY; i++) {
+ if (shape->marker[i]) {
+ for (v = item->display; v != NULL; v = v->next) {
+ sp_marker_hide ((SPMarker *) shape->marker[i], NR_ARENA_ITEM_GET_KEY (v->arenaitem) + i);
+ }
shape->release_connect[i].disconnect();
shape->modified_connect[i].disconnect();
- shape->marker[i] = sp_object_hunref (shape->marker[i], object);
- }
- }
- if (shape->curve) {
- shape->curve = shape->curve->unref();
- }
-
- if (((SPObjectClass *) parent_class)->release) {
- ((SPObjectClass *) parent_class)->release (object);
- }
+ shape->marker[i] = sp_object_hunref (shape->marker[i], object);
+ }
+ }
+ if (shape->curve) {
+ shape->curve = shape->curve->unref();
+ }
+
+ if (((SPObjectClass *) parent_class)->release) {
+ ((SPObjectClass *) parent_class)->release (object);
+ }
}
@@ -237,9 +238,9 @@ sp_shape_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::No
return repr;
}
-/**
+/**
* Updates the shape when its attributes have changed. Also establishes
- * marker objects to match the style settings.
+ * marker objects to match the style settings.
*/
static void
sp_shape_update (SPObject *object, SPCtx *ctx, unsigned int flags)
*/
for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) {
sp_shape_set_marker (object, i, object->style->marker[i].value);
- }
+ }
if (flags & (SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
SPStyle *style;
static void
sp_shape_modified (SPObject *object, unsigned int flags)
{
- SPShape *shape = SP_SHAPE (object);
+ SPShape *shape = SP_SHAPE (object);
- if (((SPObjectClass *) (parent_class))->modified) {
- (* ((SPObjectClass *) (parent_class))->modified) (object, flags);
- }
+ if (((SPObjectClass *) (parent_class))->modified) {
+ (* ((SPObjectClass *) (parent_class))->modified) (object, flags);
+ }
- if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) {
- for (SPItemView *v = SP_ITEM (shape)->display; v != NULL; v = v->next) {
- nr_arena_shape_set_style (NR_ARENA_SHAPE (v->arenaitem), object->style);
- }
- }
+ if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) {
+ for (SPItemView *v = SP_ITEM (shape)->display; v != NULL; v = v->next) {
+ nr_arena_shape_set_style (NR_ARENA_SHAPE (v->arenaitem), object->style);
+ }
+ }
}
/**
@@ -493,7 +494,7 @@ static void sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &
cbbox.y1 = (*geombbox)[1][1];
if ((SPItem::BBoxType) flags != SPItem::GEOMETRIC_BBOX) {
-
+
SPStyle* style=SP_OBJECT_STYLE (item);
if (!style->stroke.isNone()) {
double const scale = transform.descrim();
@@ -611,11 +612,11 @@ static void sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &
void
sp_shape_print (SPItem *item, SPPrintContext *ctx)
{
- NRRect pbox, dbox, bbox;
+ NRRect pbox, dbox, bbox;
- SPShape *shape = SP_SHAPE(item);
+ SPShape *shape = SP_SHAPE(item);
- if (!shape->curve) return;
+ if (!shape->curve) return;
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
gint add_comments = prefs->getBool("/printing/debug/add-label-comments");
*/
for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) {
sp_shape_set_marker (object, i, object->style->marker[i].value);
- }
+ }
if (sp_shape_has_markers (shape)) {
@@ -786,26 +787,26 @@ sp_shape_show (SPItem *item, NRArena *arena, unsigned int /*key*/, unsigned int
static void
sp_shape_hide (SPItem *item, unsigned int key)
{
- SPShape *shape;
- SPItemView *v;
- int i;
+ SPShape *shape;
+ SPItemView *v;
+ int i;
- shape = (SPShape *) item;
+ shape = (SPShape *) item;
- for (i=0; i<SP_MARKER_LOC_QTY; i++) {
- if (shape->marker[i]) {
- for (v = item->display; v != NULL; v = v->next) {
+ for (i=0; i<SP_MARKER_LOC_QTY; i++) {
+ if (shape->marker[i]) {
+ for (v = item->display; v != NULL; v = v->next) {
if (key == v->key) {
- sp_marker_hide ((SPMarker *) shape->marker[i],
+ sp_marker_hide ((SPMarker *) shape->marker[i],
NR_ARENA_ITEM_GET_KEY (v->arenaitem) + i);
}
- }
- }
- }
+ }
+ }
+ }
- if (((SPItemClass *) parent_class)->hide) {
- ((SPItemClass *) parent_class)->hide (item, key);
- }
+ if (((SPItemClass *) parent_class)->hide) {
+ ((SPItemClass *) parent_class)->hide (item, key);
+ }
}
/**
static void
sp_shape_marker_release (SPObject *marker, SPShape *shape)
{
- SPItem *item;
- int i;
-
- item = (SPItem *) shape;
-
- for (i = SP_MARKER_LOC_START; i < SP_MARKER_LOC_QTY; i++) {
- if (marker == shape->marker[i]) {
- SPItemView *v;
- /* Hide marker */
- for (v = item->display; v != NULL; v = v->next) {
- sp_marker_hide ((SPMarker *) (shape->marker[i]), NR_ARENA_ITEM_GET_KEY (v->arenaitem) + i);
- /* fixme: Do we need explicit remove here? (Lauris) */
- /* nr_arena_item_set_mask (v->arenaitem, NULL); */
- }
- /* Detach marker */
+ SPItem *item;
+ int i;
+
+ item = (SPItem *) shape;
+
+ for (i = SP_MARKER_LOC_START; i < SP_MARKER_LOC_QTY; i++) {
+ if (marker == shape->marker[i]) {
+ SPItemView *v;
+ /* Hide marker */
+ for (v = item->display; v != NULL; v = v->next) {
+ sp_marker_hide ((SPMarker *) (shape->marker[i]), NR_ARENA_ITEM_GET_KEY (v->arenaitem) + i);
+ /* fixme: Do we need explicit remove here? (Lauris) */
+ /* nr_arena_item_set_mask (v->arenaitem, NULL); */
+ }
+ /* Detach marker */
shape->release_connect[i].disconnect();
shape->modified_connect[i].disconnect();
- shape->marker[i] = sp_object_hunref (shape->marker[i], item);
- }
- }
+ shape->marker[i] = sp_object_hunref (shape->marker[i], item);
+ }
+ }
}
/**
static void
sp_shape_marker_modified (SPObject */*marker*/, guint /*flags*/, SPItem */*item*/)
{
- /* I think mask does update automagically */
- /* g_warning ("Item %s mask %s modified", SP_OBJECT_ID (item), SP_OBJECT_ID (mask)); */
+ /* I think mask does update automagically */
+ /* g_warning ("Item %s mask %s modified", SP_OBJECT_ID (item), SP_OBJECT_ID (mask)); */
}
/**
- * Adds a new marker to shape object at the location indicated by key. value
+ * Adds a new marker to shape object at the location indicated by key. value
* must be a valid URI reference resolvable from the shape object (i.e., present
* in the document <defs>). If the shape object already has a marker
* registered at the given position, it is removed first. Then the
void
sp_shape_set_shape (SPShape *shape)
{
- g_return_if_fail (shape != NULL);
- g_return_if_fail (SP_IS_SHAPE (shape));
+ g_return_if_fail (shape != NULL);
+ g_return_if_fail (SP_IS_SHAPE (shape));
- if (SP_SHAPE_CLASS (G_OBJECT_GET_CLASS (shape))->set_shape) {
- SP_SHAPE_CLASS (G_OBJECT_GET_CLASS (shape))->set_shape (shape);
- }
+ if (SP_SHAPE_CLASS (G_OBJECT_GET_CLASS (shape))->set_shape) {
+ SP_SHAPE_CLASS (G_OBJECT_GET_CLASS (shape))->set_shape (shape);
+ }
}
/**
void
sp_shape_set_curve (SPShape *shape, SPCurve *curve, unsigned int owner)
{
- if (shape->curve) {
- shape->curve = shape->curve->unref();
- }
- if (curve) {
- if (owner) {
- shape->curve = curve->ref();
- } else {
- shape->curve = curve->copy();
- }
- }
+ if (shape->curve) {
+ shape->curve = shape->curve->unref();
+ }
+ if (curve) {
+ if (owner) {
+ shape->curve = curve->ref();
+ } else {
+ shape->curve = curve->copy();
+ }
+ }
SP_OBJECT(shape)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
}
SPCurve *
sp_shape_get_curve (SPShape *shape)
{
- if (shape->curve) {
- return shape->curve->copy();
- }
- return NULL;
+ if (shape->curve) {
+ return shape->curve->copy();
+ }
+ return NULL;
}
/**
void
sp_shape_set_curve_insync (SPShape *shape, SPCurve *curve, unsigned int owner)
{
- if (shape->curve) {
- shape->curve = shape->curve->unref();
- }
- if (curve) {
- if (owner) {
- shape->curve = curve->ref();
- } else {
- shape->curve = curve->copy();
- }
- }
+ if (shape->curve) {
+ shape->curve = shape->curve->unref();
+ }
+ if (curve) {
+ if (owner) {
+ shape->curve = curve->ref();
+ } else {
+ shape->curve = curve->copy();
+ }
+ }
}
/**
@@ -1058,22 +1059,44 @@ static void sp_shape_snappoints(SPItem const *item, SnapPointsIter p, Inkscape::
while (curve_it2 != path_it->end_closed())
{
/* Test whether to add the node between curve_it1 and curve_it2.
- * Loop to end_closed (so always including closing segment), the last node to be added
- * is the node between the closing segment and the segment before that one. Regardless
- * of the path being closed. If the path is closed, the final point was already added by
+ * Loop to end_closed (so always including closing segment); the last node to be added
+ * is the node between the closing segment and the segment before that, regardless
+ * of the path being closed or not. If the path is closed, the final point was already added by
* adding the initial point. */
Geom::NodeType nodetype = Geom::get_nodetype(*curve_it1, *curve_it2);
- // Depending on the snapping preferences, either add only cusp nodes, or add add both cusp and smooths nodes
+ // Depending on the snapping preferences, either add only cusp nodes, or add add both cusp and smooth nodes
if (snapprefs->getSnapSmoothNodes() || nodetype == Geom::NODE_NONE || nodetype == Geom::NODE_CUSP) {
*p = from_2geom(curve_it1->finalPoint() * i2d);
}
-
+
+ // Consider midpoints of line segments for snapping
+ if (snapprefs->getSnapMidpoints()) {
+ if (Geom::LineSegment const* line_segment = dynamic_cast<Geom::LineSegment const*>(&(*curve_it1))) {
+ *p = from_2geom(Geom::middle_point(*line_segment) * i2d);
+ }
+ }
+
++curve_it1;
++curve_it2;
}
+
+ // Find the internal intersections of each path and consider these for snapping (using "Method 1" as desciribed in Inkscape::ObjectSnapper::_collectNodes())
+ if (snapprefs->getSnapIntersectionCS()) {
+ Geom::Crossings cs;
+ cs = self_crossings(*path_it);
+ if (cs.size() > 0) { // There might be multiple intersections...
+ for (Geom::Crossings::const_iterator i = cs.begin(); i != cs.end(); i++) {
+ Geom::Point p_ix = (*path_it).pointAt((*i).ta);
+ *p = from_2geom(p_ix * i2d);
+ }
+ }
+ }
}
+
+
+
}
/*
index 1bbd201363963a1b59660d841388c166eb990961..713acc23e049592beb554f3a00abddac79a21eab 100644 (file)
//Applies to both nodes and guides, but not to bboxes, that's why its located here
_rcbic( _("Rotation _center"), _("Consider the rotation center of an object when snapping"), "inkscape:snap-center", _wr),
_rcbsm( _("_Smooth nodes"), _("Snap to smooth nodes too, instead of only snapping to cusp nodes"), "inkscape:snap-smooth-nodes", _wr),
+ _rcbmp( _("_Midpoints"), _("Snap midpoints of straight line segments"), "inkscape:snap-midpoints", _wr),
_rcbsigg(_("_Grid with guides"), _("Snap to grid-guide intersections"), "inkscape:snap-intersection-grid-guide", _wr),
_rcbsils(_("_Paths"), _("Snap to intersections of paths ('snap to paths' must be enabled, see the previous tab)"),
"inkscape:snap-intersection-paths", _wr),
//Other options to locate here: e.g. visual snapping indicators on/off
Gtk::Label *label_i= manage (new Gtk::Label);
- label_i->set_markup (_("<b>Snapping to intersections of</b>"));
+ label_i->set_markup (_("<b>Snapping intersections of</b>"));
Gtk::Label *label_m = manage (new Gtk::Label);
label_m->set_markup (_("<b>Special points to consider</b>"));
0, 0,
label_m, 0,
0, &_rcbic,
- 0, &_rcbsm
+ 0, &_rcbsm,
+ 0, &_rcbmp
};
attach_all(_page_snap_dtls.table(), array, G_N_ELEMENTS(array));
_rcbsng.setActive (nv->snap_manager.snapprefs.getSnapModeGuide());
_rcbic.setActive (nv->snap_manager.snapprefs.getIncludeItemCenter());
_rcbsm.setActive (nv->snap_manager.snapprefs.getSnapSmoothNodes());
+ _rcbmp.setActive (nv->snap_manager.snapprefs.getSnapMidpoints());
_rcbsigg.setActive (nv->snap_manager.snapprefs.getSnapIntersectionGG());
_rcbsils.setActive (nv->snap_manager.snapprefs.getSnapIntersectionCS());
_rcbsnop.setActive(nv->snap_manager.object.getSnapToItemPath());
index 2428ab24a826a4030409e2eae3fed7558b59932b..36a6c739b61ae929b9cf89e77766701a7df2ff7d 100644 (file)
RegisteredCheckButton _rcbsnon, _rcbsnbbp, _rcbsnbbn, _rcbsnpb;
ToleranceSlider _rsu_sno, _rsu_sn, _rsu_gusn;
//---------------------------------------------------------------
- RegisteredCheckButton _rcbic, _rcbsm;
+ RegisteredCheckButton _rcbic, _rcbsm, _rcbmp;
RegisteredCheckButton _rcbsigg, _rcbsils;
//---------------------------------------------------------------
Gtk::Menu _menu;