~valavanisalex/ubuntu/precise/inkscape/fix-943984

« back to all changes in this revision

Viewing changes to src/snap.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Bryce Harrington
  • Date: 2009-07-02 17:09:45 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20090702170945-nn6d6zswovbwju1t
Tags: 0.47~pre1-0ubuntu1
* New upstream release.
  - Don't constrain maximization on small resolution devices (pre0)
    (LP: #348842)
  - Fixes segfault on startup (pre0)
    (LP: #391149)

Show diffs side-by-side

added added

removed removed

Lines of Context:
50
50
}
51
51
 
52
52
/**
 
53
 *  \brief Return a list of snappers
 
54
 *
 
55
 *  Inkscape snaps to objects, grids, and guides. For each of these snap targets a
 
56
 *  separate class is used, which has been derived from the base Snapper class. The
 
57
 *  getSnappers() method returns a list of pointers to instances of this class. This
 
58
 *  list contains exactly one instance of the guide snapper and of the object snapper
 
59
 *  class, but any number of grid snappers (because each grid has its own snapper
 
60
 *  instance)
 
61
 *
53
62
 *  \return List of snappers that we use.
54
63
 */
55
64
SnapManager::SnapperList
66
75
}
67
76
 
68
77
/**
 
78
 *  \brief Return a list of gridsnappers
 
79
 *
 
80
 *  Each grid has its own instance of the snapper class. This way snapping can
 
81
 *  be enabled per grid individually. A list will be returned containing the
 
82
 *  pointers to these instances, but only for grids that are being displayed
 
83
 *  and for which snapping is enabled.
 
84
 *
69
85
 *  \return List of gridsnappers that we use.
70
86
 */
71
87
SnapManager::SnapperList
73
89
{
74
90
    SnapperList s;
75
91
 
76
 
    //FIXME: this code should actually do this: add new grid snappers that are active for this desktop. now it just adds all gridsnappers
77
92
    if (_desktop && _desktop->gridsEnabled() && snapprefs.getSnapToGrids()) {
78
93
        for ( GSList const *l = _named_view->grids; l != NULL; l = l->next) {
79
94
            Inkscape::CanvasGrid *grid = (Inkscape::CanvasGrid*) l->data;
85
100
}
86
101
 
87
102
/**
88
 
 * \return true if one of the snappers will try to snap something.
 
103
 * \brief Return true if any snapping might occur, whether its to grids, guides or objects
 
104
 *
 
105
 * Each snapper instance handles its own snapping target, e.g. grids, guides or
 
106
 * objects. This method iterates through all these snapper instances and returns
 
107
 * true if any of the snappers might possible snap, considering only the relevant
 
108
 * snapping preferences.
 
109
 *
 
110
 * \return true if one of the snappers will try to snap to something.
89
111
 */
90
112
 
91
113
bool SnapManager::someSnapperMightSnap() const
104
126
}
105
127
 
106
128
/**
107
 
 * \return true if one of the snappers will try to snap something.
 
129
 * \return true if one of the grids might be snapped to.
108
130
 */
109
131
 
110
132
bool SnapManager::gridSnapperMightSnap() const
123
145
}
124
146
 
125
147
/**
126
 
 *  Try to snap a point to any of the specified snappers.
127
 
 *
128
 
 *  \param point_type Type of point.
129
 
 *  \param p Point.
130
 
 *  \param first_point If true then this point is the first one from a whole bunch of points
131
 
 *  \param points_to_snap The whole bunch of points, all from the same selection and having the same transformation
132
 
 *  \param snappers List of snappers to try to snap to
133
 
 *  \return Snapped point.
 
148
 *  \brief Try to snap a point to grids, guides or objects.
 
149
 *
 
150
 *  Try to snap a point to grids, guides or objects, in two degrees-of-freedom,
 
151
 *  i.e. snap in any direction on the two dimensional canvas to the nearest
 
152
 *  snap target. freeSnapReturnByRef() is equal in snapping behavior to
 
153
 *  freeSnap(), but the former returns the snapped point trough the referenced
 
154
 *  parameter p. This parameter p initially contains the position of the snap
 
155
 *  source and will we overwritten by the target position if snapping has occurred.
 
156
 *  This makes snapping transparent to the calling code. If this is not desired
 
157
 *  because either the calling code must know whether snapping has occurred, or
 
158
 *  because the original position should not be touched, then freeSnap() should be
 
159
 *  called instead.
 
160
 *
 
161
 *  PS: SnapManager::setup() must have been called before calling this method,
 
162
 *  but only once for a set of points
 
163
 *
 
164
 *  \param point_type Category of points to which the source point belongs: node, guide or bounding box
 
165
 *  \param p Current position of the snap source; will be overwritten by the position of the snap target if snapping has occurred
 
166
 *  \param source_type Detailed description of the source type, will be used by the snap indicator
 
167
 *  \param first_point If true then this point is the first one from a set of points, all from the same selection and having the same transformation
 
168
 *  \param bbox_to_snap Bounding box hulling the set of points, all from the same selection and having the same transformation
134
169
 */
135
170
 
136
171
void SnapManager::freeSnapReturnByRef(Inkscape::SnapPreferences::PointType point_type,
139
174
                                      bool first_point,
140
175
                                      Geom::OptRect const &bbox_to_snap) const
141
176
{
 
177
    //TODO: PointType and source_type are somewhat redundant; can't we get rid of the point_type parameter?
142
178
    Inkscape::SnappedPoint const s = freeSnap(point_type, p, source_type, first_point, bbox_to_snap);
143
179
    s.getPoint(p);
144
180
}
145
181
 
146
182
 
147
183
/**
148
 
 *  Try to snap a point to any of the specified snappers.
149
 
 *
150
 
 *  \param point_type Type of point.
151
 
 *  \param p Point.
152
 
 *  \param first_point If true then this point is the first one from a whole bunch of points
153
 
 *  \param points_to_snap The whole bunch of points, all from the same selection and having the same transformation
154
 
 *  \param snappers List of snappers to try to snap to
155
 
 *  \return Snapped point.
 
184
 *  \brief Try to snap a point to grids, guides or objects.
 
185
 *
 
186
 *  Try to snap a point to grids, guides or objects, in two degrees-of-freedom,
 
187
 *  i.e. snap in any direction on the two dimensional canvas to the nearest
 
188
 *  snap target. freeSnap() is equal in snapping behavior to
 
189
 *  freeSnapReturnByRef(). Please read the comments of the latter for more details
 
190
 *
 
191
 *  PS: SnapManager::setup() must have been called before calling this method,
 
192
 *  but only once for a set of points
 
193
 *
 
194
 *  \param point_type Category of points to which the source point belongs: node, guide or bounding box
 
195
 *  \param p Current position of the snap source
 
196
 *  \param source_type Detailed description of the source type, will be used by the snap indicator
 
197
 *  \param first_point If true then this point is the first one from a set of points, all from the same selection and having the same transformation
 
198
 *  \param bbox_to_snap Bounding box hulling the set of points, all from the same selection and having the same transformation
 
199
 *  \return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics
156
200
 */
157
201
 
 
202
 
158
203
Inkscape::SnappedPoint SnapManager::freeSnap(Inkscape::SnapPreferences::PointType point_type,
159
204
                                             Geom::Point const &p,
160
205
                                             Inkscape::SnapSourceType const &source_type,
196
241
    return findBestSnap(p, source_type, sc, false);
197
242
}
198
243
 
199
 
// When pasting, we would like to snap to the grid. Problem is that we don't know which nodes were
200
 
// aligned to the grid at the time of copying, so we don't know which nodes to snap. If we'd snap an
201
 
// unaligned node to the grid, previously aligned nodes would become unaligned. That's undesirable.
202
 
// Instead we will make sure that the offset between the source and the copy is a multiple of the grid
203
 
// pitch. If the source was aligned, then the copy will therefore also be aligned
204
 
// PS: Whether we really find a multiple also depends on the snapping range!
 
244
/**
 
245
 * \brief Snap to the closest multiple of a grid pitch
 
246
 *
 
247
 * When pasting, we would like to snap to the grid. Problem is that we don't know which
 
248
 * nodes were aligned to the grid at the time of copying, so we don't know which nodes
 
249
 * to snap. If we'd snap an unaligned node to the grid, previously aligned nodes would
 
250
 * become unaligned. That's undesirable. Instead we will make sure that the offset
 
251
 * between the source and its pasted copy is a multiple of the grid pitch. If the source
 
252
 * was aligned, then the copy will therefore also be aligned.
 
253
 *
 
254
 * PS: Whether we really find a multiple also depends on the snapping range! Most users
 
255
 * will have "always snap" enabled though, in which case a multiple will always be found.
 
256
 * PS2: When multiple grids are present then the result will become ambiguous. There is no
 
257
 * way to control to which grid this method will snap.
 
258
 *
 
259
 * \param t Vector that represents the offset of the pasted copy with respect to the original
 
260
 * \return Offset vector after snapping to the closest multiple of a grid pitch
 
261
 */
 
262
 
205
263
Geom::Point SnapManager::multipleOfGridPitch(Geom::Point const &t) const
206
264
{
207
265
    if (!snapprefs.getSnapEnabledGlobally()) // No need to check for snapprefs.getSnapPostponedGlobally() here
208
266
        return t;
209
267
 
210
 
    //FIXME: this code should actually do this: add new grid snappers that are active for this desktop. now it just adds all gridsnappers
211
 
 
212
268
    if (_desktop && _desktop->gridsEnabled()) {
213
269
        bool success = false;
214
270
        Geom::Point nearest_multiple;
252
308
}
253
309
 
254
310
/**
255
 
 *  Try to snap a point to any interested snappers.  A snap will only occur along
256
 
 *  a line described by a Inkscape::Snapper::ConstraintLine.
257
 
 *
258
 
 *  \param point_type Type of point.
259
 
 *  \param p Point.
260
 
 *  \param first_point If true then this point is the first one from a whole bunch of points
261
 
 *  \param points_to_snap The whole bunch of points, all from the same selection and having the same transformation
262
 
 *  \param constraint Constraint line.
263
 
 *  \return Snapped point.
 
311
 *  \brief Try to snap a point along a constraint line to grids, guides or objects.
 
312
 *
 
313
 *  Try to snap a point to grids, guides or objects, in only one degree-of-freedom,
 
314
 *  i.e. snap in a specific direction on the two dimensional canvas to the nearest
 
315
 *  snap target.
 
316
 *
 
317
 *  constrainedSnapReturnByRef() is equal in snapping behavior to
 
318
 *  constrainedSnap(), but the former returns the snapped point trough the referenced
 
319
 *  parameter p. This parameter p initially contains the position of the snap
 
320
 *  source and will we overwritten by the target position if snapping has occurred.
 
321
 *  This makes snapping transparent to the calling code. If this is not desired
 
322
 *  because either the calling code must know whether snapping has occurred, or
 
323
 *  because the original position should not be touched, then constrainedSnap() should
 
324
 *  be called instead.
 
325
 *
 
326
 *  PS: SnapManager::setup() must have been called before calling this method,
 
327
 *  but only once for a set of points
 
328
 *
 
329
 *  \param point_type Category of points to which the source point belongs: node, guide or bounding box
 
330
 *  \param p Current position of the snap source; will be overwritten by the position of the snap target if snapping has occurred
 
331
 *  \param source_type Detailed description of the source type, will be used by the snap indicator
 
332
 *  \param constraint The direction or line along which snapping must occur
 
333
 *  \param first_point If true then this point is the first one from a set of points, all from the same selection and having the same transformation
 
334
 *  \param bbox_to_snap Bounding box hulling the set of points, all from the same selection and having the same transformation
264
335
 */
265
336
 
266
337
void SnapManager::constrainedSnapReturnByRef(Inkscape::SnapPreferences::PointType point_type,
267
338
                                             Geom::Point &p,
268
339
                                             Inkscape::SnapSourceType const source_type,
269
340
                                             Inkscape::Snapper::ConstraintLine const &constraint,
270
 
                                             bool const snap_projection,
271
341
                                             bool first_point,
272
342
                                             Geom::OptRect const &bbox_to_snap) const
273
343
{
274
 
    Inkscape::SnappedPoint const s = constrainedSnap(point_type, p, source_type, constraint, snap_projection, first_point, bbox_to_snap);
 
344
    Inkscape::SnappedPoint const s = constrainedSnap(point_type, p, source_type, constraint, first_point, bbox_to_snap);
275
345
    s.getPoint(p);
276
346
}
277
347
 
278
 
 
279
348
/**
280
 
 *  Try to snap a point to any interested snappers.  A snap will only occur along
281
 
 *  a line described by a Inkscape::Snapper::ConstraintLine.
282
 
 *
283
 
 *  \param point_type Type of point.
284
 
 *  \param p Point.
285
 
 *  \param first_point If true then this point is the first one from a whole bunch of points
286
 
 *  \param points_to_snap The whole bunch of points, all from the same selection and having the same transformation
287
 
 *  \param constraint Constraint line.
288
 
 *  \return Snapped point.
 
349
 *  \brief Try to snap a point along a constraint line to grids, guides or objects.
 
350
 *
 
351
 *  Try to snap a point to grids, guides or objects, in only one degree-of-freedom,
 
352
 *  i.e. snap in a specific direction on the two dimensional canvas to the nearest
 
353
 *  snap target. constrainedSnap is equal in snapping behavior to
 
354
 *  constrainedSnapReturnByRef(). Please read the comments of the latter for more details.
 
355
 *
 
356
 *  PS: SnapManager::setup() must have been called before calling this method,
 
357
 *  but only once for a set of points
 
358
 *
 
359
 *  \param point_type Category of points to which the source point belongs: node, guide or bounding box
 
360
 *  \param p Current position of the snap source
 
361
 *  \param source_type Detailed description of the source type, will be used by the snap indicator
 
362
 *  \param constraint The direction or line along which snapping must occur
 
363
 *  \param first_point If true then this point is the first one from a set of points, all from the same selection and having the same transformation
 
364
 *  \param bbox_to_snap Bounding box hulling the set of points, all from the same selection and having the same transformation
289
365
 */
290
366
 
291
367
Inkscape::SnappedPoint SnapManager::constrainedSnap(Inkscape::SnapPreferences::PointType point_type,
292
368
                                                    Geom::Point const &p,
293
369
                                                    Inkscape::SnapSourceType const &source_type,
294
370
                                                    Inkscape::Snapper::ConstraintLine const &constraint,
295
 
                                                    bool /*snap_projection*/,
296
371
                                                    bool first_point,
297
372
                                                    Geom::OptRect const &bbox_to_snap) const
298
373
{
299
 
        if (_desktop->event_context && _desktop->event_context->_snap_window_open == false) {
 
374
    if (_desktop->event_context && _desktop->event_context->_snap_window_open == false) {
300
375
                g_warning("The current tool tries to snap, but it hasn't yet opened the snap window. Please report this!");
301
376
                // When the context goes into dragging-mode, then Inkscape should call this: sp_event_context_snap_window_open(event_context);
302
377
        }
330
405
    return findBestSnap(p, source_type, sc, true);
331
406
}
332
407
 
333
 
// guideFreeSnap is used when dragging or rotating the guide
 
408
/**
 
409
 *  \brief Try to snap a point of a guide to another guide or to a node
 
410
 *
 
411
 *  Try to snap a point of a guide to another guide or to a node in two degrees-
 
412
 *  of-freedom, i.e. snap in any direction on the two dimensional canvas to the
 
413
 *  nearest snap target. This method is used when dragging or rotating a guide
 
414
 *
 
415
 *  PS: SnapManager::setup() must have been called before calling this method,
 
416
 *
 
417
 *  \param p Current position of the point on the guide that is to be snapped; will be overwritten by the position of the snap target if snapping has occurred
 
418
 *  \param guide_normal Vector normal to the guide line
 
419
 */
334
420
void SnapManager::guideFreeSnap(Geom::Point &p, Geom::Point const &guide_normal) const
335
421
{
336
 
    // This method is used to snap a guide to nodes or to other guides, while dragging the guide around. Will not snap to grids!
337
 
 
338
 
        if (_desktop->event_context && _desktop->event_context->_snap_window_open == false) {
 
422
    if (_desktop->event_context && _desktop->event_context->_snap_window_open == false) {
339
423
                        g_warning("The current tool tries to snap, but it hasn't yet opened the snap window. Please report this!");
340
424
                        // When the context goes into dragging-mode, then Inkscape should call this: sp_event_context_snap_window_open(event_context);
341
425
        }
365
449
    s.getPoint(p);
366
450
}
367
451
 
368
 
// guideConstrainedSnap is used when dragging the origin of the guide along the guide itself
 
452
/**
 
453
 *  \brief Try to snap a point on a guide to the intersection with another guide or a path
 
454
 *
 
455
 *  Try to snap a point on a guide to the intersection of that guide with another
 
456
 *  guide or with a path. The snapped point will lie somewhere on the guide-line,
 
457
 *  making this is a constrained snap, i.e. in only one degree-of-freedom.
 
458
 *  This method is used when dragging the origin of the guide along the guide itself.
 
459
 *
 
460
 *  PS: SnapManager::setup() must have been called before calling this method,
 
461
 *
 
462
 *  \param p Current position of the point on the guide that is to be snapped; will be overwritten by the position of the snap target if snapping has occurred
 
463
 *  \param guide_normal Vector normal to the guide line
 
464
 */
 
465
 
369
466
void SnapManager::guideConstrainedSnap(Geom::Point &p, SPGuide const &guideline) const
370
467
{
371
 
    // This method is used to snap a guide to paths or to other guides, while dragging the origin of the guide around. Will not snap to grids!
372
 
 
373
468
        if (_desktop->event_context && _desktop->event_context->_snap_window_open == false) {
374
469
                        g_warning("The current tool tries to snap, but it hasn't yet opened the snap window. Please report this!");
375
470
                        // When the context goes into dragging-mode, then Inkscape should call this: sp_event_context_snap_window_open(event_context);
402
497
}
403
498
 
404
499
/**
405
 
 *  Main internal snapping method, which is called by the other, friendlier, public
406
 
 *  methods.  It's a bit hairy as it has lots of parameters, but it saves on a lot
407
 
 *  of duplicated code.
408
 
 *
409
 
 *  \param type Type of points being snapped.
410
 
 *  \param points List of points to snap (i.e. untransformed).
411
 
 *  \param pointer Location of the mouse pointer, at the time when dragging started (i.e. "untransformed")
412
 
 *  \param constrained true if the snap is constrained.
413
 
 *  \param constraint Constraint line to use, if `constrained' is true, otherwise undefined.
 
500
 *  \brief Method for snapping sets of points while they are being transformed
 
501
 *
 
502
 *  Method for snapping sets of points while they are being transformed, when using
 
503
 *  for example the selector tool. This method is for internal use only, and should
 
504
 *  not have to be called directly. Use freeSnapTransalation(), constrainedSnapScale(),
 
505
 *  etc. instead.
 
506
 *
 
507
 *  This is what is being done in this method: transform each point, find out whether
 
508
 *  a free snap or constrained snap is more appropriate, do the snapping, calculate
 
509
 *  some metrics to quantify the snap "distance", and see if it's better than the
 
510
 *  previous snap. Finally, the best ("nearest") snap from all these points is returned.
 
511
 *
 
512
 *  \param type Category of points to which the source point belongs: node or bounding box.
 
513
 *  \param points Collection of points to snap (snap sources), at their untransformed position, all points undergoing the same transformation. Paired with an identifier of the type of the snap source.
 
514
 *  \param pointer Location of the mouse pointer at the time dragging started (i.e. when the selection was still untransformed).
 
515
 *  \param constrained true if the snap is constrained, e.g. for stretching or for purely horizontal translation.
 
516
 *  \param constraint The direction or line along which snapping must occur, if 'constrained' is true; otherwise undefined.
414
517
 *  \param transformation_type Type of transformation to apply to points before trying to snap them.
415
518
 *  \param transformation Description of the transformation; details depend on the type.
416
519
 *  \param origin Origin of the transformation, if applicable.
417
 
 *  \param dim Dimension of the transformation, if applicable.
 
520
 *  \param dim Dimension to which the transformation applies, if applicable.
418
521
 *  \param uniform true if the transformation should be uniform; only applicable for stretching and scaling.
 
522
 *  \return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics.
419
523
 */
420
524
 
421
525
Inkscape::SnappedPoint SnapManager::_snapTransformed(
499
603
            if (transformation_type == SCALE && !uniform) {
500
604
                g_warning("Non-uniform constrained scaling is not supported!");
501
605
            }
502
 
            snapped_point = constrainedSnap(type, (*j).first, static_cast<Inkscape::SnapSourceType>((*j).second), dedicated_constraint, false, i == points.begin(), bbox);
 
606
            snapped_point = constrainedSnap(type, (*j).first, static_cast<Inkscape::SnapSourceType>((*j).second), dedicated_constraint, i == points.begin(), bbox);
503
607
        } else {
504
608
            bool const c1 = fabs(b[Geom::X]) < 1e-6;
505
609
            bool const c2 = fabs(b[Geom::Y]) < 1e-6;
508
612
                // move in that specific direction; therefore it should only snap in that direction, otherwise
509
613
                // we will get snapped points with an invalid transformation
510
614
                dedicated_constraint = Inkscape::Snapper::ConstraintLine(origin, component_vectors[c1]);
511
 
                snapped_point = constrainedSnap(type, (*j).first, static_cast<Inkscape::SnapSourceType>((*j).second), dedicated_constraint, false, i == points.begin(), bbox);
 
615
                snapped_point = constrainedSnap(type, (*j).first, static_cast<Inkscape::SnapSourceType>((*j).second), dedicated_constraint, i == points.begin(), bbox);
512
616
            } else {
513
617
                snapped_point = freeSnap(type, (*j).first, static_cast<Inkscape::SnapSourceType>((*j).second), i == points.begin(), bbox);
514
618
            }
649
753
 
650
754
 
651
755
/**
652
 
 *  Try to snap a list of points to any interested snappers after they have undergone
653
 
 *  a translation.
 
756
 *  \brief Apply a translation to a set of points and try to snap freely in 2 degrees-of-freedom
654
757
 *
655
 
 *  \param point_type Type of points.
656
 
 *  \param p Points.
657
 
 *  \param tr Proposed translation.
658
 
 *  \return Snapped translation, if a snap occurred, and a flag indicating whether a snap occurred.
 
758
 *  \param point_type Category of points to which the source point belongs: node or bounding box.
 
759
 *  \param p Collection of points to snap (snap sources), at their untransformed position, all points undergoing the same transformation. Paired with an identifier of the type of the snap source.
 
760
 *  \param pointer Location of the mouse pointer at the time dragging started (i.e. when the selection was still untransformed).
 
761
 *  \param tr Proposed translation; the final translation can only be calculated after snapping has occurred
 
762
 *  \return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics.
659
763
 */
660
764
 
661
765
Inkscape::SnappedPoint SnapManager::freeSnapTranslation(Inkscape::SnapPreferences::PointType point_type,
670
774
    return _snapTransformed(point_type, p, pointer, false, Geom::Point(0,0), TRANSLATION, tr, Geom::Point(0,0), Geom::X, false);
671
775
}
672
776
 
673
 
 
674
777
/**
675
 
 *  Try to snap a list of points to any interested snappers after they have undergone a
676
 
 *  translation.  A snap will only occur along a line described by a
677
 
 *  Inkscape::Snapper::ConstraintLine.
 
778
 *  \brief Apply a translation to a set of points and try to snap along a constraint
678
779
 *
679
 
 *  \param point_type Type of points.
680
 
 *  \param p Points.
681
 
 *  \param constraint Constraint line.
682
 
 *  \param tr Proposed translation.
683
 
 *  \return Snapped translation, if a snap occurred, and a flag indicating whether a snap occurred.
 
780
 *  \param point_type Category of points to which the source point belongs: node or bounding box.
 
781
 *  \param p Collection of points to snap (snap sources), at their untransformed position, all points undergoing the same transformation. Paired with an identifier of the type of the snap source.
 
782
 *  \param pointer Location of the mouse pointer at the time dragging started (i.e. when the selection was still untransformed).
 
783
 *  \param constraint The direction or line along which snapping must occur.
 
784
 *  \param tr Proposed translation; the final translation can only be calculated after snapping has occurred.
 
785
 *  \return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics.
684
786
 */
685
787
 
686
788
Inkscape::SnappedPoint SnapManager::constrainedSnapTranslation(Inkscape::SnapPreferences::PointType point_type,
698
800
 
699
801
 
700
802
/**
701
 
 *  Try to snap a list of points to any interested snappers after they have undergone
702
 
 *  a scale.
 
803
 *  \brief Apply a scaling to a set of points and try to snap freely in 2 degrees-of-freedom
703
804
 *
704
 
 *  \param point_type Type of points.
705
 
 *  \param p Points.
706
 
 *  \param s Proposed scale.
707
 
 *  \param o Origin of proposed scale.
708
 
 *  \return Snapped scale, if a snap occurred, and a flag indicating whether a snap occurred.
 
805
 *  \param point_type Category of points to which the source point belongs: node or bounding box.
 
806
 *  \param p Collection of points to snap (snap sources), at their untransformed position, all points undergoing the same transformation. Paired with an identifier of the type of the snap source.
 
807
 *  \param pointer Location of the mouse pointer at the time dragging started (i.e. when the selection was still untransformed).
 
808
 *  \param s Proposed scaling; the final scaling can only be calculated after snapping has occurred
 
809
 *  \param o Origin of the scaling
 
810
 *  \return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics.
709
811
 */
710
812
 
711
813
Inkscape::SnappedPoint SnapManager::freeSnapScale(Inkscape::SnapPreferences::PointType point_type,
723
825
 
724
826
 
725
827
/**
726
 
 *  Try to snap a list of points to any interested snappers after they have undergone
727
 
 *  a scale.  A snap will only occur along a line described by a
728
 
 *  Inkscape::Snapper::ConstraintLine.
 
828
 *  \brief Apply a scaling to a set of points and snap such that the aspect ratio of the selection is preserved
729
829
 *
730
 
 *  \param point_type Type of points.
731
 
 *  \param p Points.
732
 
 *  \param s Proposed scale.
733
 
 *  \param o Origin of proposed scale.
734
 
 *  \return Snapped scale, if a snap occurred, and a flag indicating whether a snap occurred.
 
830
 *  \param point_type Category of points to which the source point belongs: node or bounding box.
 
831
 *  \param p Collection of points to snap (snap sources), at their untransformed position, all points undergoing the same transformation. Paired with an identifier of the type of the snap source.
 
832
 *  \param pointer Location of the mouse pointer at the time dragging started (i.e. when the selection was still untransformed).
 
833
 *  \param s Proposed scaling; the final scaling can only be calculated after snapping has occurred
 
834
 *  \param o Origin of the scaling
 
835
 *  \return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics.
735
836
 */
736
837
 
737
838
Inkscape::SnappedPoint SnapManager::constrainedSnapScale(Inkscape::SnapPreferences::PointType point_type,
748
849
    return _snapTransformed(point_type, p, pointer, true, Geom::Point(0,0), SCALE, Geom::Point(s[Geom::X], s[Geom::Y]), o, Geom::X, true);
749
850
}
750
851
 
751
 
 
752
852
/**
753
 
 *  Try to snap a list of points to any interested snappers after they have undergone
754
 
 *  a stretch.
 
853
 *  \brief Apply a stretch to a set of points and snap such that the direction of the stretch is preserved
755
854
 *
756
 
 *  \param point_type Type of points.
757
 
 *  \param p Points.
758
 
 *  \param s Proposed stretch.
759
 
 *  \param o Origin of proposed stretch.
 
855
 *  \param point_type Category of points to which the source point belongs: node or bounding box.
 
856
 *  \param p Collection of points to snap (snap sources), at their untransformed position, all points undergoing the same transformation. Paired with an identifier of the type of the snap source.
 
857
 *  \param pointer Location of the mouse pointer at the time dragging started (i.e. when the selection was still untransformed).
 
858
 *  \param s Proposed stretch; the final stretch can only be calculated after snapping has occurred
 
859
 *  \param o Origin of the stretching
760
860
 *  \param d Dimension in which to apply proposed stretch.
761
 
 *  \param u true if the stretch should be uniform (ie to be applied equally in both dimensions)
762
 
 *  \return Snapped stretch, if a snap occurred, and a flag indicating whether a snap occurred.
 
861
 *  \param u true if the stretch should be uniform (i.e. to be applied equally in both dimensions)
 
862
 *  \return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics.
763
863
 */
764
864
 
765
865
Inkscape::SnappedPoint SnapManager::constrainedSnapStretch(Inkscape::SnapPreferences::PointType point_type,
777
877
    return _snapTransformed(point_type, p, pointer, true, Geom::Point(0,0), STRETCH, Geom::Point(s, s), o, d, u);
778
878
}
779
879
 
780
 
 
781
880
/**
782
 
 *  Try to snap a list of points to any interested snappers after they have undergone
783
 
 *  a skew.
 
881
 *  \brief Apply a skew to a set of points and snap such that the direction of the skew is preserved
784
882
 *
785
 
 *  \param point_type Type of points.
786
 
 *  \param p Points.
787
 
 *  \param s Proposed skew.
788
 
 *  \param o Origin of proposed skew.
 
883
 *  \param point_type Category of points to which the source point belongs: node or bounding box.
 
884
 *  \param p Collection of points to snap (snap sources), at their untransformed position, all points undergoing the same transformation. Paired with an identifier of the type of the snap source.
 
885
 *  \param pointer Location of the mouse pointer at the time dragging started (i.e. when the selection was still untransformed).
 
886
 *  \param constraint The direction or line along which snapping must occur.
 
887
 *  \param s Proposed skew; the final skew can only be calculated after snapping has occurred
 
888
 *  \param o Origin of the proposed skew
789
889
 *  \param d Dimension in which to apply proposed skew.
790
 
 *  \return Snapped skew, if a snap occurred, and a flag indicating whether a snap occurred.
 
890
 *  \return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics.
791
891
 */
792
892
 
793
893
Inkscape::SnappedPoint SnapManager::constrainedSnapSkew(Inkscape::SnapPreferences::PointType point_type,
800
900
{
801
901
    // "s" contains skew factor in s[0], and scale factor in s[1]
802
902
 
803
 
    // Snapping the nodes of the boundingbox of a selection that is being transformed, will only work if
 
903
    // Snapping the nodes of the bounding box of a selection that is being transformed, will only work if
804
904
    // the transformation of the bounding box is equal to the transformation of the individual nodes. This is
805
905
    // NOT the case for example when rotating or skewing. The bounding box itself cannot possibly rotate or skew,
806
906
    // so it's corners have a different transformation. The snappers cannot handle this, therefore snapping
814
914
    return _snapTransformed(point_type, p, pointer, true, constraint, SKEW, s, o, d, false);
815
915
}
816
916
 
817
 
Inkscape::SnappedPoint SnapManager::findBestSnap(Geom::Point const &p, Inkscape::SnapSourceType const source_type, SnappedConstraints &sc, bool constrained) const
 
917
/**
 
918
 * \brief Given a set of possible snap targets, find the best target (which is not necessarily
 
919
 * also the nearest target), and show the snap indicator if requested
 
920
 *
 
921
 * \param p Current position of the snap source
 
922
 * \param source_type Detailed description of the source type, will be used by the snap indicator
 
923
 * \param sc A structure holding all snap targets that have been found so far
 
924
 * \param constrained True if the snap is constrained, e.g. for stretching or for purely horizontal translation.
 
925
 * \return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics
 
926
 */
 
927
 
 
928
Inkscape::SnappedPoint SnapManager::findBestSnap(Geom::Point const &p,
 
929
                                                                                             Inkscape::SnapSourceType const source_type,
 
930
                                                                                             SnappedConstraints &sc,
 
931
                                                                                             bool constrained) const
818
932
{
819
933
 
820
934
    /*
925
1039
    return bestSnappedPoint;
926
1040
}
927
1041
 
 
1042
/**
 
1043
 * \brief Prepare the snap manager for the actual snapping, which includes building a list of snap targets
 
1044
 * to ignore and toggling the snap indicator
 
1045
 *
 
1046
 * There are two overloaded setup() methods, of which this one only allows for a single item to be ignored
 
1047
 * whereas the other one will take a list of items to ignore
 
1048
 *
 
1049
 * \param desktop Reference to the desktop to which this snap manager is attached
 
1050
 * \param snapindicator If true then a snap indicator will be displayed automatically (when enabled in the preferences)
 
1051
 * \param item_to_ignore This item will not be snapped to, e.g. the item that is currently being dragged. This avoids "self-snapping"
 
1052
 * \param unselected_nodes Stationary nodes of the path that is currently being edited in the node tool and
 
1053
 * that can be snapped too. Nodes not in this list will not be snapped to, to avoid "self-snapping". Of each
 
1054
 * unselected node both the position (Geom::Point) and the type (Inkscape::SnapTargetType) will be stored
 
1055
 * \param guide_to_ignore Guide that is currently being dragged and should not be snapped to
 
1056
 */
 
1057
 
928
1058
void SnapManager::setup(SPDesktop const *desktop,
929
1059
                        bool snapindicator,
930
1060
                        SPItem const *item_to_ignore,
940
1070
    _guide_to_ignore = guide_to_ignore;
941
1071
}
942
1072
 
 
1073
/**
 
1074
 * \brief Prepare the snap manager for the actual snapping, which includes building a list of snap targets
 
1075
 * to ignore and toggling the snap indicator
 
1076
 *
 
1077
 * There are two overloaded setup() methods, of which the other one only allows for a single item to be ignored
 
1078
 * whereas this one will take a list of items to ignore
 
1079
 *
 
1080
 * \param desktop Reference to the desktop to which this snap manager is attached
 
1081
 * \param snapindicator If true then a snap indicator will be displayed automatically (when enabled in the preferences)
 
1082
 * \param items_to_ignore These items will not be snapped to, e.g. the items that are currently being dragged. This avoids "self-snapping"
 
1083
 * \param unselected_nodes Stationary nodes of the path that is currently being edited in the node tool and
 
1084
 * that can be snapped too. Nodes not in this list will not be snapped to, to avoid "self-snapping". Of each
 
1085
 * unselected node both the position (Geom::Point) and the type (Inkscape::SnapTargetType) will be stored
 
1086
 * \param guide_to_ignore Guide that is currently being dragged and should not be snapped to
 
1087
 */
 
1088
 
943
1089
void SnapManager::setup(SPDesktop const *desktop,
944
1090
                        bool snapindicator,
945
1091
                        std::vector<SPItem const *> &items_to_ignore,
960
1106
    return _named_view->document;
961
1107
}
962
1108
 
 
1109
/**
 
1110
 * \brief Takes an untransformed point, applies the given transformation, and returns the transformed point. Eliminates lots of duplicated code
 
1111
 *
 
1112
 * \param p The untransformed position of the point, paired with an identifier of the type of the snap source.
 
1113
 * \param transformation_type Type of transformation to apply.
 
1114
 * \param transformation Mathematical description of the transformation; details depend on the type.
 
1115
 * \param origin Origin of the transformation, if applicable.
 
1116
 * \param dim Dimension to which the transformation applies, if applicable.
 
1117
 * \param uniform true if the transformation should be uniform; only applicable for stretching and scaling.
 
1118
 * \return The position of the point after transformation
 
1119
 */
 
1120
 
963
1121
Geom::Point SnapManager::_transformPoint(std::pair<Geom::Point, int> const &p,
964
1122
                                        Transformation const transformation_type,
965
1123
                                        Geom::Point const &transformation,
1002
1160
    return transformed;
1003
1161
}
1004
1162
 
 
1163
/**
 
1164
 * \brief Mark the location of the snap source (not the snap target!) on the canvas by drawing a symbol
 
1165
 *
 
1166
 * \param point_type Category of points to which the source point belongs: node, guide or bounding box
 
1167
 * \param p The transformed position of the source point, paired with an identifier of the type of the snap source.
 
1168
 */
 
1169
 
1005
1170
void SnapManager::_displaySnapsource(Inkscape::SnapPreferences::PointType point_type, std::pair<Geom::Point, int> const &p) const {
1006
1171
 
1007
1172
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();