Code

Fixed unintialized variables and minor misc warnings
[inkscape.git] / src / snap.cpp
1 #define __SP_DESKTOP_SNAP_C__
3 /**
4  * \file snap.cpp
5  * \brief SnapManager class.
6  *
7  * Authors:
8  *   Lauris Kaplinski <lauris@kaplinski.com>
9  *   Frank Felfe <innerspace@iname.com>
10  *   Carl Hetherington <inkscape@carlh.net>
11  *
12  * Copyright (C) 2006      Johan Engelen <johan@shouraizou.nl>
13  * Copyright (C) 1999-2002 Authors
14  *
15  * Released under GNU GPL, read the file 'COPYING' for more information
16  */
18 #include "sp-namedview.h"
19 #include "snap.h"
20 #include <libnr/nr-point-fns.h>
21 #include <libnr/nr-scale-ops.h>
22 #include <libnr/nr-values.h>
24 /**
25  *  Construct a SnapManager for a SPNamedView.
26  *
27  *  \param v `Owning' SPNamedView.
28  */
30 SnapManager::SnapManager(SPNamedView const *v) :
31     grid(v, 0),
32     axonomgrid(v, 0),
33     guide(v, 0),
34     object(v, 0),
35     _named_view(v)
36 {
38 }
41 /**
42  *  \return List of snappers that we use.
43  */
45 SnapManager::SnapperList SnapManager::getSnappers() const
46 {
47     SnapManager::SnapperList s;
48     if (_named_view->gridtype == 0) {
49       s.push_back(&grid);
50     } else {
51       s.push_back(&axonomgrid);
52     }
53     s.push_back(&guide);
54     s.push_back(&object);
55     return s;
56 }
58 /**
59  * \return true if one of the snappers will try to snap something.
60  */
62 bool SnapManager::willSnapSomething() const
63 {
64     SnapperList const s = getSnappers();
65     SnapperList::const_iterator i = s.begin();
66     while (i != s.end() && (*i)->willSnapSomething() == false) {
67         i++;
68     }
70     return (i != s.end());
71 }
74 /**
75  *  Try to snap a point to any interested snappers.
76  *
77  *  \param t Type of point.
78  *  \param p Point.
79  *  \param it Item to ignore when snapping.
80  *  \return Snapped point.
81  */
83 Inkscape::SnappedPoint SnapManager::freeSnap(Inkscape::Snapper::PointType t,
84                                              NR::Point const &p,
85                                              SPItem const *it) const
87 {
88     std::list<SPItem const *> lit;
89     lit.push_back(it);
90     return freeSnap(t, p, lit);
91 }
94 /**
95  *  Try to snap a point to any interested snappers.
96  *
97  *  \param t Type of point.
98  *  \param p Point.
99  *  \param it List of items to ignore when snapping.
100  *  \return Snapped point.
101  */
103 Inkscape::SnappedPoint SnapManager::freeSnap(Inkscape::Snapper::PointType t,
104                                              NR::Point const &p,
105                                              std::list<SPItem const *> const &it) const
107     Inkscape::SnappedPoint r(p, NR_HUGE);
109     SnapperList const snappers = getSnappers();
110     for (SnapperList::const_iterator i = snappers.begin(); i != snappers.end(); i++) {
111         Inkscape::SnappedPoint const s = (*i)->freeSnap(t, p, it);
112         if (s.getDistance() < r.getDistance()) {
113             r = s;
114         }
115     }
117     return r;
121 /**
122  *  Try to snap a point to any interested snappers.  A snap will only occur along
123  *  a line described by a Inkscape::Snapper::ConstraintLine.
124  *
125  *  \param t Type of point.
126  *  \param p Point.
127  *  \param c Constraint line.
128  *  \param it Item to ignore when snapping.
129  *  \return Snapped point.
130  */
132 Inkscape::SnappedPoint SnapManager::constrainedSnap(Inkscape::Snapper::PointType t,
133                                                     NR::Point const &p,
134                                                     Inkscape::Snapper::ConstraintLine const &c,
135                                                     SPItem const *it) const
137     std::list<SPItem const *> lit;
138     lit.push_back(it);
139     return constrainedSnap(t, p, c, lit);
144 /**
145  *  Try to snap a point to any interested snappers.  A snap will only occur along
146  *  a line described by a Inkscape::Snapper::ConstraintLine.
147  *
148  *  \param t Type of point.
149  *  \param p Point.
150  *  \param c Constraint line.
151  *  \param it List of items to ignore when snapping.
152  *  \return Snapped point.
153  */
155 Inkscape::SnappedPoint SnapManager::constrainedSnap(Inkscape::Snapper::PointType t,
156                                                     NR::Point const &p,
157                                                     Inkscape::Snapper::ConstraintLine const &c,
158                                                     std::list<SPItem const *> const &it) const
160     Inkscape::SnappedPoint r(p, NR_HUGE);
162     SnapperList const snappers = getSnappers();
163     for (SnapperList::const_iterator i = snappers.begin(); i != snappers.end(); i++) {
164         Inkscape::SnappedPoint const s = (*i)->constrainedSnap(t, p, c, it);
165         if (s.getDistance() < r.getDistance()) {
166             r = s;
167         }
168     }
170     return r;
175 /**
176  *  Main internal snapping method, which is called by the other, friendlier, public
177  *  methods.  It's a bit hairy as it has lots of parameters, but it saves on a lot
178  *  of duplicated code.
179  *
180  *  \param type Type of points being snapped.
181  *  \param points List of points to snap.
182  *  \param ignore List of items to ignore while snapping.
183  *  \param constrained true if the snap is constrained.
184  *  \param constraint Constraint line to use, if `constrained' is true, otherwise undefined.
185  *  \param transformation_type Type of transformation to apply to points before trying to snap them.
186  *  \param transformation Description of the transformation; details depend on the type.
187  *  \param origin Origin of the transformation, if applicable.
188  *  \param dim Dimension of the transformation, if applicable.
189  *  \param uniform true if the transformation should be uniform, if applicable.
190  */
192 std::pair<NR::Point, bool> SnapManager::_snapTransformed(
193     Inkscape::Snapper::PointType type,
194     std::vector<NR::Point> const &points,
195     std::list<SPItem const *> const &ignore,
196     bool constrained,
197     Inkscape::Snapper::ConstraintLine const &constraint,
198     Transformation transformation_type,
199     NR::Point const &transformation,
200     NR::Point const &origin,
201     NR::Dim2 dim,
202     bool uniform) const
204     /* We have a list of points, which we are proposing to transform in some way.  We need to see
205     ** if any of these points, when transformed, snap to anything.  If they do, we return the
206     ** appropriate transformation with `true'; otherwise we return the original scale with `false'.
207     */
209     /* Quick check to see if we have any snappers that are enabled */
210     if (willSnapSomething() == false) {
211         return std::make_pair(transformation, false);
212     }
214     /* The current best transformation */
215     NR::Point best_transformation = transformation;
216     
217     /* The current best metric for the best transformation; lower is better, NR_HUGE
218     ** means that we haven't snapped anything.
219     */
220     double best_metric = NR_HUGE;
222     for (std::vector<NR::Point>::const_iterator i = points.begin(); i != points.end(); i++) {
224         /* Work out the transformed version of this point */
225         NR::Point transformed;
226         switch (transformation_type) {
227             case TRANSLATION:
228                 transformed = *i + transformation;
229                 break;
230             case SCALE:
231                 transformed = ((*i - origin) * NR::scale(transformation[NR::X], transformation[NR::Y])) + origin;
232                 break;
233             case STRETCH:
234             {
235                 NR::scale s(1, 1);
236                 if (uniform)
237                     s[NR::X] = s[NR::Y] = transformation[dim];
238                 else {
239                     s[dim] = transformation[dim];
240                     s[1 - dim] = 1;
241                 }
242                 transformed = ((*i - origin) * s) + origin;
243                 break;
244             }
245             case SKEW:
246                 transformed = *i;
247                 transformed[dim] += transformation[dim] * ((*i)[1 - dim] - origin[1 - dim]);
248                 break;
249             default:
250                 g_assert_not_reached();
251         }
252         
253         /* Snap it */
254         Inkscape::SnappedPoint const snapped = constrained ?
255             constrainedSnap(type, transformed, constraint, ignore) : freeSnap(type, transformed, ignore);
257         if (snapped.getDistance() < NR_HUGE) {
258             /* We snapped.  Find the transformation that describes where the snapped point has
259             ** ended up, and also the metric for this transformation.
260             */
261             NR::Point result;
262             NR::Coord metric;
263             switch (transformation_type) {
264                 case TRANSLATION:
265                     result = snapped.getPoint() - *i;
266                     metric = NR::L2(result);
267                     break;
268                 case SCALE:
269                 {
270                     NR::Point const a = (snapped.getPoint() - origin);
271                     NR::Point const b = (*i - origin);
272                     result = NR::Point(a[NR::X] / b[NR::X], a[NR::Y] / b[NR::Y]);
273                     metric = std::abs(NR::L2(result) - NR::L2(transformation));
274                     break;
275                 }
276                 case STRETCH:
277                 {
278                     for (int j = 0; j < 2; j++) {
279                         if (uniform || j == dim) {
280                             result[j] = (snapped.getPoint()[dim] - origin[dim]) / ((*i)[dim] - origin[dim]);
281                         } else {
282                             result[j] = 1;
283                         }
284                     }
285                     metric = std::abs(result[dim] - transformation[dim]);
286                     break;
287                 }
288                 case SKEW:
289                     result[dim] = (snapped.getPoint()[dim] - (*i)[dim]) / ((*i)[1 - dim] - origin[1 - dim]);
290                     metric = std::abs(result[dim] - transformation[dim]);
291                     break;
292                 default:
293                     g_assert_not_reached();
294             }
296             /* Note it if it's the best so far */
297             if (metric < best_metric && metric != 0) {
298                 best_transformation = result;
299                 best_metric = metric;
300             }
301         }
302     }
303         
304     return std::make_pair(best_transformation, best_metric < NR_HUGE);
308 /**
309  *  Try to snap a list of points to any interested snappers after they have undergone
310  *  a translation.
311  *
312  *  \param t Type of points.
313  *  \param p Points.
314  *  \param it List of items to ignore when snapping.
315  *  \param tr Proposed translation.
316  *  \return Snapped translation, if a snap occurred, and a flag indicating whether a snap occurred.
317  */
319 std::pair<NR::Point, bool> SnapManager::freeSnapTranslation(Inkscape::Snapper::PointType t,
320                                                             std::vector<NR::Point> const &p,
321                                                             std::list<SPItem const *> const &it,
322                                                             NR::Point const &tr) const
324     return _snapTransformed(
325         t, p, it, false, NR::Point(), TRANSLATION, tr, NR::Point(), NR::X, false
326         );
330 /**
331  *  Try to snap a list of points to any interested snappers after they have undergone a
332  *  translation.  A snap will only occur along a line described by a
333  *  Inkscape::Snapper::ConstraintLine.
334  *
335  *  \param t Type of points.
336  *  \param p Points.
337  *  \param it List of items to ignore when snapping.
338  *  \param c Constraint line.
339  *  \param tr Proposed translation.
340  *  \return Snapped translation, if a snap occurred, and a flag indicating whether a snap occurred.
341  */
343 std::pair<NR::Point, bool> SnapManager::constrainedSnapTranslation(Inkscape::Snapper::PointType t,
344                                                                    std::vector<NR::Point> const &p,
345                                                                    std::list<SPItem const *> const &it,
346                                                                    Inkscape::Snapper::ConstraintLine const &c,
347                                                                    NR::Point const &tr) const
349     return _snapTransformed(
350         t, p, it, true, c, TRANSLATION, tr, NR::Point(), NR::X, false
351         );
355 /**
356  *  Try to snap a list of points to any interested snappers after they have undergone
357  *  a scale.
358  *
359  *  \param t Type of points.
360  *  \param p Points.
361  *  \param it List of items to ignore when snapping.
362  *  \param s Proposed scale.
363  *  \param o Origin of proposed scale.
364  *  \return Snapped scale, if a snap occurred, and a flag indicating whether a snap occurred.
365  */
367 std::pair<NR::scale, bool> SnapManager::freeSnapScale(Inkscape::Snapper::PointType t,
368                                                       std::vector<NR::Point> const &p,
369                                                       std::list<SPItem const *> const &it,
370                                                       NR::scale const &s,
371                                                       NR::Point const &o) const
373     return _snapTransformed(
374         t, p, it, false, NR::Point(), SCALE, NR::Point(s[NR::X], s[NR::Y]), o, NR::X, false
375         );
379 /**
380  *  Try to snap a list of points to any interested snappers after they have undergone
381  *  a scale.  A snap will only occur along a line described by a
382  *  Inkscape::Snapper::ConstraintLine.
383  *
384  *  \param t Type of points.
385  *  \param p Points.
386  *  \param it List of items to ignore when snapping.
387  *  \param s Proposed scale.
388  *  \param o Origin of proposed scale.
389  *  \return Snapped scale, if a snap occurred, and a flag indicating whether a snap occurred.
390  */
392 std::pair<NR::scale, bool> SnapManager::constrainedSnapScale(Inkscape::Snapper::PointType t,
393                                                              std::vector<NR::Point> const &p,
394                                                              std::list<SPItem const *> const &it,
395                                                              Inkscape::Snapper::ConstraintLine const &c,
396                                                              NR::scale const &s,
397                                                              NR::Point const &o) const
399     return _snapTransformed(
400         t, p, it, true, c, SCALE, NR::Point(s[NR::X], s[NR::Y]), o, NR::X, false
401         );
405 /**
406  *  Try to snap a list of points to any interested snappers after they have undergone
407  *  a stretch.
408  *
409  *  \param t Type of points.
410  *  \param p Points.
411  *  \param it List of items to ignore when snapping.
412  *  \param s Proposed stretch.
413  *  \param o Origin of proposed stretch.
414  *  \param d Dimension in which to apply proposed stretch.
415  *  \param u true if the stretch should be uniform (ie to be applied equally in both dimensions)
416  *  \return Snapped stretch, if a snap occurred, and a flag indicating whether a snap occurred.
417  */
419 std::pair<NR::Coord, bool> SnapManager::freeSnapStretch(Inkscape::Snapper::PointType t,
420                                                         std::vector<NR::Point> const &p,
421                                                         std::list<SPItem const *> const &it,
422                                                         NR::Coord const &s,
423                                                         NR::Point const &o,
424                                                         NR::Dim2 d,
425                                                         bool u) const
427    std::pair<NR::Point, bool> const r = _snapTransformed(
428         t, p, it, false, NR::Point(), STRETCH, NR::Point(s, s), o, d, u
429         );
431    return std::make_pair(r.first[d], r.second);
435 /**
436  *  Try to snap a list of points to any interested snappers after they have undergone
437  *  a skew.
438  *
439  *  \param t Type of points.
440  *  \param p Points.
441  *  \param it List of items to ignore when snapping.
442  *  \param s Proposed skew.
443  *  \param o Origin of proposed skew.
444  *  \param d Dimension in which to apply proposed skew.
445  *  \return Snapped skew, if a snap occurred, and a flag indicating whether a snap occurred.
446  */
448 std::pair<NR::Coord, bool> SnapManager::freeSnapSkew(Inkscape::Snapper::PointType t,
449                                                      std::vector<NR::Point> const &p,
450                                                      std::list<SPItem const *> const &it,
451                                                      NR::Coord const &s,
452                                                      NR::Point const &o,
453                                                      NR::Dim2 d) const
455    std::pair<NR::Point, bool> const r = _snapTransformed(
456         t, p, it, false, NR::Point(), SKEW, NR::Point(s, s), o, d, false
457         );
459    return std::make_pair(r.first[d], r.second);
462 /*
463   Local Variables:
464   mode:c++
465   c-file-style:"stroustrup"
466   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
467   indent-tabs-mode:nil
468   fill-column:99
469   End:
470 */
471 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :