1 /* This file is part of the KDE project
2 * Copyright (C) 2008 Jan Hambrecht <jaham@gmx.net>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #include "KoSnapStrategy.h"
21 #include "KoSnapProxy.h"
22 #include "KoSnapGuide.h"
23 #include <KoPathShape.h>
24 #include <KoPathPoint.h>
25 #include <KoPathSegment.h>
26 #include <KoCanvasBase.h>
27 #include <KoViewConverter.h>
28
29 #include <QPainter>
30 #include <QPainterPath>
31
32 #include <cmath>
33
34 #if defined(_MSC_VER) && (_MSC_VER < 1800)
35 #define isfinite(x) (double)(x)
36 #endif
37
KoSnapStrategy(KoSnapGuide::Strategy type)38 KoSnapStrategy::KoSnapStrategy(KoSnapGuide::Strategy type)
39 : m_snapType(type)
40 {
41 }
42
snappedPosition() const43 QPointF KoSnapStrategy::snappedPosition() const
44 {
45 return m_snappedPosition;
46 }
47
setSnappedPosition(const QPointF & position)48 void KoSnapStrategy::setSnappedPosition(const QPointF &position)
49 {
50 m_snappedPosition = position;
51 }
52
type() const53 KoSnapGuide::Strategy KoSnapStrategy::type() const
54 {
55 return m_snapType;
56 }
57
squareDistance(const QPointF & p1,const QPointF & p2)58 qreal KoSnapStrategy::squareDistance(const QPointF &p1, const QPointF &p2)
59 {
60 const qreal dx = p1.x() - p2.x();
61 const qreal dy = p1.y() - p2.y();
62
63 return dx*dx + dy*dy;
64 }
65
scalarProduct(const QPointF & p1,const QPointF & p2)66 qreal KoSnapStrategy::scalarProduct(const QPointF &p1, const QPointF &p2)
67 {
68 return p1.x() * p2.x() + p1.y() * p2.y();
69 }
70
OrthogonalSnapStrategy()71 OrthogonalSnapStrategy::OrthogonalSnapStrategy()
72 : KoSnapStrategy(KoSnapGuide::OrthogonalSnapping)
73 {
74 }
75
snap(const QPointF & mousePosition,KoSnapProxy * proxy,qreal maxSnapDistance)76 bool OrthogonalSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance)
77 {
78 Q_ASSERT(std::isfinite(maxSnapDistance));
79 QPointF horzSnap, vertSnap;
80 qreal minVertDist = HUGE_VAL;
81 qreal minHorzDist = HUGE_VAL;
82
83 QList<KoShape*> shapes = proxy->shapes(true);
84 Q_FOREACH (KoShape * shape, shapes) {
85 QList<QPointF> points = proxy->pointsFromShape(shape);
86 foreach (const QPointF &point, points) {
87 qreal dx = fabs(point.x() - mousePosition.x());
88 if (dx < minHorzDist && dx < maxSnapDistance) {
89 minHorzDist = dx;
90 horzSnap = point;
91 }
92 qreal dy = fabs(point.y() - mousePosition.y());
93 if (dy < minVertDist && dy < maxSnapDistance) {
94 minVertDist = dy;
95 vertSnap = point;
96 }
97 }
98 }
99
100 QPointF snappedPoint = mousePosition;
101
102 if (minHorzDist < HUGE_VAL)
103 snappedPoint.setX(horzSnap.x());
104 if (minVertDist < HUGE_VAL)
105 snappedPoint.setY(vertSnap.y());
106
107 if (minHorzDist < HUGE_VAL)
108 m_hLine = QLineF(horzSnap, snappedPoint);
109 else
110 m_hLine = QLineF();
111
112 if (minVertDist < HUGE_VAL)
113 m_vLine = QLineF(vertSnap, snappedPoint);
114 else
115 m_vLine = QLineF();
116
117 setSnappedPosition(snappedPoint);
118
119 return (minHorzDist < HUGE_VAL || minVertDist < HUGE_VAL);
120 }
121
decoration(const KoViewConverter &) const122 QPainterPath OrthogonalSnapStrategy::decoration(const KoViewConverter &/*converter*/) const
123 {
124 QPainterPath decoration;
125 if (! m_hLine.isNull()) {
126 decoration.moveTo(m_hLine.p1());
127 decoration.lineTo(m_hLine.p2());
128 }
129 if (! m_vLine.isNull()) {
130 decoration.moveTo(m_vLine.p1());
131 decoration.lineTo(m_vLine.p2());
132 }
133 return decoration;
134 }
135
NodeSnapStrategy()136 NodeSnapStrategy::NodeSnapStrategy()
137 : KoSnapStrategy(KoSnapGuide::NodeSnapping)
138 {
139 }
140
snap(const QPointF & mousePosition,KoSnapProxy * proxy,qreal maxSnapDistance)141 bool NodeSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance)
142 {
143 Q_ASSERT(std::isfinite(maxSnapDistance));
144 const qreal maxDistance = maxSnapDistance * maxSnapDistance;
145 qreal minDistance = HUGE_VAL;
146
147 QRectF rect(-maxSnapDistance, -maxSnapDistance, maxSnapDistance, maxSnapDistance);
148 rect.moveCenter(mousePosition);
149 QList<QPointF> points = proxy->pointsInRect(rect, false);
150 QPointF snappedPoint = mousePosition;
151
152 foreach (const QPointF &point, points) {
153 qreal distance = squareDistance(mousePosition, point);
154 if (distance < maxDistance && distance < minDistance) {
155 snappedPoint = point;
156 minDistance = distance;
157 }
158 }
159
160 setSnappedPosition(snappedPoint);
161
162 return (minDistance < HUGE_VAL);
163 }
164
decoration(const KoViewConverter & converter) const165 QPainterPath NodeSnapStrategy::decoration(const KoViewConverter &converter) const
166 {
167 QRectF unzoomedRect = converter.viewToDocument(QRectF(0, 0, 11, 11));
168 unzoomedRect.moveCenter(snappedPosition());
169 QPainterPath decoration;
170 decoration.addEllipse(unzoomedRect);
171 return decoration;
172 }
173
ExtensionSnapStrategy()174 ExtensionSnapStrategy::ExtensionSnapStrategy()
175 : KoSnapStrategy(KoSnapGuide::ExtensionSnapping)
176 {
177 }
178
snap(const QPointF & mousePosition,KoSnapProxy * proxy,qreal maxSnapDistance)179 bool ExtensionSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance)
180 {
181 Q_ASSERT(std::isfinite(maxSnapDistance));
182
183 const qreal maxDistance = maxSnapDistance * maxSnapDistance;
184 qreal minDistances[2] = { HUGE_VAL, HUGE_VAL };
185
186 QPointF snappedPoints[2] = { mousePosition, mousePosition };
187 QPointF startPoints[2];
188
189 QList<KoShape*> shapes = proxy->shapes(true);
190
191 Q_FOREACH (KoShape * shape, shapes) {
192 KoPathShape * path = dynamic_cast<KoPathShape*>(shape);
193 if (! path) {
194 continue;
195 }
196 QTransform matrix = path->absoluteTransformation();
197
198 const int subpathCount = path->subpathCount();
199 for (int subpathIndex = 0; subpathIndex < subpathCount; ++subpathIndex) {
200 if (path->isClosedSubpath(subpathIndex))
201 continue;
202
203 int pointCount = path->subpathPointCount(subpathIndex);
204
205 // check the extension from the start point
206 KoPathPoint * first = path->pointByIndex(KoPathPointIndex(subpathIndex, 0));
207 QPointF firstSnapPosition = mousePosition;
208 if (snapToExtension(firstSnapPosition, first, matrix)) {
209 qreal distance = squareDistance(firstSnapPosition, mousePosition);
210 if (distance < maxDistance) {
211 if (distance < minDistances[0]) {
212 minDistances[1] = minDistances[0];
213 snappedPoints[1] = snappedPoints[0];
214 startPoints[1] = startPoints[0];
215
216 minDistances[0] = distance;
217 snappedPoints[0] = firstSnapPosition;
218 startPoints[0] = matrix.map(first->point());
219 }
220 else if (distance < minDistances[1]) {
221 minDistances[1] = distance;
222 snappedPoints[1] = firstSnapPosition;
223 startPoints[1] = matrix.map(first->point());
224 }
225 }
226 }
227
228 // now check the extension from the last point
229 KoPathPoint * last = path->pointByIndex(KoPathPointIndex(subpathIndex, pointCount - 1));
230 QPointF lastSnapPosition = mousePosition;
231 if (snapToExtension(lastSnapPosition, last, matrix)) {
232 qreal distance = squareDistance(lastSnapPosition, mousePosition);
233 if (distance < maxDistance) {
234 if (distance < minDistances[0]) {
235 minDistances[1] = minDistances[0];
236 snappedPoints[1] = snappedPoints[0];
237 startPoints[1] = startPoints[0];
238
239 minDistances[0] = distance;
240 snappedPoints[0] = lastSnapPosition;
241 startPoints[0] = matrix.map(last->point());
242 }
243 else if (distance < minDistances[1]) {
244 minDistances[1] = distance;
245 snappedPoints[1] = lastSnapPosition;
246 startPoints[1] = matrix.map(last->point());
247 }
248 }
249 }
250 }
251 }
252
253 m_lines.clear();
254 // if we have to extension near our mouse position, they might have an intersection
255 // near our mouse position which we want to use as the snapped position
256 if (minDistances[0] < HUGE_VAL && minDistances[1] < HUGE_VAL) {
257 // check if intersection of extension lines is near mouse position
258 KoPathSegment s1(startPoints[0], snappedPoints[0] + snappedPoints[0]-startPoints[0]);
259 KoPathSegment s2(startPoints[1], snappedPoints[1] + snappedPoints[1]-startPoints[1]);
260 QList<QPointF> isects = s1.intersections(s2);
261 if (isects.count() == 1 && squareDistance(isects[0], mousePosition) < maxDistance) {
262 // add both extension lines
263 m_lines.append(QLineF(startPoints[0], isects[0]));
264 m_lines.append(QLineF(startPoints[1], isects[0]));
265 setSnappedPosition(isects[0]);
266 }
267 else {
268 // only add nearest extension line of both
269 uint index = minDistances[0] < minDistances[1] ? 0 : 1;
270 m_lines.append(QLineF(startPoints[index], snappedPoints[index]));
271 setSnappedPosition(snappedPoints[index]);
272 }
273 }
274 else if (minDistances[0] < HUGE_VAL) {
275 m_lines.append(QLineF(startPoints[0], snappedPoints[0]));
276 setSnappedPosition(snappedPoints[0]);
277 }
278 else if (minDistances[1] < HUGE_VAL) {
279 m_lines.append(QLineF(startPoints[1], snappedPoints[1]));
280 setSnappedPosition(snappedPoints[1]);
281 }
282 else {
283 // none of the extension lines is near our mouse position
284 return false;
285 }
286 return true;
287 }
288
decoration(const KoViewConverter &) const289 QPainterPath ExtensionSnapStrategy::decoration(const KoViewConverter &/*converter*/) const
290 {
291 QPainterPath decoration;
292 foreach (const QLineF &line, m_lines) {
293 decoration.moveTo(line.p1());
294 decoration.lineTo(line.p2());
295 }
296 return decoration;
297 }
298
snapToExtension(QPointF & position,KoPathPoint * point,const QTransform & matrix)299 bool ExtensionSnapStrategy::snapToExtension(QPointF &position, KoPathPoint * point, const QTransform &matrix)
300 {
301 Q_ASSERT(point);
302 QPointF direction = extensionDirection(point, matrix);
303 if (direction.isNull())
304 return false;
305
306 QPointF extensionStart = matrix.map(point->point());
307 QPointF extensionStop = matrix.map(point->point()) + direction;
308 float posOnExtension = project(extensionStart, extensionStop, position);
309 if (posOnExtension < 0.0)
310 return false;
311
312 position = extensionStart + posOnExtension * direction;
313 return true;
314 }
315
project(const QPointF & lineStart,const QPointF & lineEnd,const QPointF & point)316 qreal ExtensionSnapStrategy::project(const QPointF &lineStart, const QPointF &lineEnd, const QPointF &point)
317 {
318 // This is how the returned value should be used to get the
319 // projectionPoint: ProjectionPoint = lineStart(1-resultingReal) + resultingReal*lineEnd;
320
321 QPointF diff = lineEnd - lineStart;
322 QPointF relPoint = point - lineStart;
323 qreal diffLength = sqrt(diff.x() * diff.x() + diff.y() * diff.y());
324 if (diffLength == 0.0)
325 return 0.0;
326
327 diff /= diffLength;
328 // project mouse position relative to stop position on extension line
329 qreal scalar = relPoint.x() * diff.x() + relPoint.y() * diff.y();
330 return scalar /= diffLength;
331 }
332
extensionDirection(KoPathPoint * point,const QTransform & matrix)333 QPointF ExtensionSnapStrategy::extensionDirection(KoPathPoint * point, const QTransform &matrix)
334 {
335 Q_ASSERT(point);
336
337 KoPathShape * path = point->parent();
338 KoPathPointIndex index = path->pathPointIndex(point);
339
340 // check if it is a start point
341 if (point->properties() & KoPathPoint::StartSubpath) {
342 if (point->activeControlPoint2()) {
343 return matrix.map(point->point()) - matrix.map(point->controlPoint2());
344 } else {
345 KoPathPoint * next = path->pointByIndex(KoPathPointIndex(index.first, index.second + 1));
346 if (! next){
347 return QPointF();
348 }
349 else if (next->activeControlPoint1()) {
350 return matrix.map(point->point()) - matrix.map(next->controlPoint1());
351 }
352 else {
353 return matrix.map(point->point()) - matrix.map(next->point());
354 }
355 }
356 }
357 else {
358 if (point->activeControlPoint1()) {
359 return matrix.map(point->point()) - matrix.map(point->controlPoint1());
360 }
361 else {
362 KoPathPoint * prev = path->pointByIndex(KoPathPointIndex(index.first, index.second - 1));
363 if (! prev){
364 return QPointF();
365 }
366 else if (prev->activeControlPoint2()) {
367 return matrix.map(point->point()) - matrix.map(prev->controlPoint2());
368 }
369 else {
370 return matrix.map(point->point()) - matrix.map(prev->point());
371 }
372 }
373 }
374 }
375
IntersectionSnapStrategy()376 IntersectionSnapStrategy::IntersectionSnapStrategy()
377 : KoSnapStrategy(KoSnapGuide::IntersectionSnapping)
378 {
379 }
380
snap(const QPointF & mousePosition,KoSnapProxy * proxy,qreal maxSnapDistance)381 bool IntersectionSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy *proxy, qreal maxSnapDistance)
382 {
383 Q_ASSERT(std::isfinite(maxSnapDistance));
384 const qreal maxDistance = maxSnapDistance * maxSnapDistance;
385 qreal minDistance = HUGE_VAL;
386
387 QRectF rect(-maxSnapDistance, -maxSnapDistance, maxSnapDistance, maxSnapDistance);
388 rect.moveCenter(mousePosition);
389 QPointF snappedPoint = mousePosition;
390
391 QList<KoPathSegment> segments = proxy->segmentsInRect(rect, false);
392 int segmentCount = segments.count();
393 for (int i = 0; i < segmentCount; ++i) {
394 const KoPathSegment &s1 = segments[i];
395 for (int j = i + 1; j < segmentCount; ++j) {
396 QList<QPointF> isects = s1.intersections(segments[j]);
397 Q_FOREACH (const QPointF &point, isects) {
398 if (! rect.contains(point))
399 continue;
400 qreal distance = squareDistance(mousePosition, point);
401 if (distance < maxDistance && distance < minDistance) {
402 snappedPoint = point;
403 minDistance = distance;
404 }
405 }
406 }
407 }
408
409 setSnappedPosition(snappedPoint);
410
411 return (minDistance < HUGE_VAL);
412 }
413
decoration(const KoViewConverter & converter) const414 QPainterPath IntersectionSnapStrategy::decoration(const KoViewConverter &converter) const
415 {
416 QRectF unzoomedRect = converter.viewToDocument(QRectF(0, 0, 11, 11));
417 unzoomedRect.moveCenter(snappedPosition());
418 QPainterPath decoration;
419 decoration.addRect(unzoomedRect);
420 return decoration;
421 }
422
GridSnapStrategy()423 GridSnapStrategy::GridSnapStrategy()
424 : KoSnapStrategy(KoSnapGuide::GridSnapping)
425 {
426 }
427
snap(const QPointF & mousePosition,KoSnapProxy * proxy,qreal maxSnapDistance)428 bool GridSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy *proxy, qreal maxSnapDistance)
429 {
430 Q_ASSERT(std::isfinite(maxSnapDistance));
431 if (! proxy->canvas()->snapToGrid())
432 return false;
433
434 // The 1e-10 here is a workaround for some weird division problem.
435 // 360.00062366 / 2.83465058 gives 127 'exactly' when shown as a qreal,
436 // but when casting into an int, we get 126. In fact it's 127 - 5.64e-15 !
437 QPointF offset;
438 QSizeF spacing;
439 proxy->canvas()->gridSize(&offset, &spacing);
440
441 // we want to snap to the nearest grid point, so calculate
442 // the grid rows/columns before and after the points position
443 int col = static_cast<int>((mousePosition.x() - offset.x()) / spacing.width() + 1e-10);
444 int nextCol = col + 1;
445 int row = static_cast<int>((mousePosition.y() - offset.y()) / spacing.height() + 1e-10);
446 int nextRow = row + 1;
447
448 // now check which grid line has less distance to the point
449 qreal distToCol = qAbs(offset.x() + col * spacing.width() - mousePosition.x());
450 qreal distToNextCol = qAbs(offset.x() + nextCol * spacing.width() - mousePosition.x());
451
452 if (distToCol > distToNextCol) {
453 col = nextCol;
454 distToCol = distToNextCol;
455 }
456
457 qreal distToRow = qAbs(offset.y() + row * spacing.height() - mousePosition.y());
458 qreal distToNextRow = qAbs(offset.y() + nextRow * spacing.height() - mousePosition.y());
459 if (distToRow > distToNextRow) {
460 row = nextRow;
461 distToRow = distToNextRow;
462 }
463
464 QPointF snappedPoint = mousePosition;
465
466 bool pointIsSnapped = false;
467
468 const qreal sqDistance = distToCol * distToCol + distToRow * distToRow;
469 const qreal maxSqDistance = maxSnapDistance * maxSnapDistance;
470 // now check if we are inside the snap distance
471 if (sqDistance < maxSqDistance) {
472 snappedPoint = QPointF(offset.x() + col * spacing.width(), offset.y() + row * spacing.height());
473 pointIsSnapped = true;
474 } else if (distToRow < maxSnapDistance) {
475 snappedPoint.ry() = offset.y() + row * spacing.height();
476 pointIsSnapped = true;
477 } else if (distToCol < maxSnapDistance) {
478 snappedPoint.rx() = offset.x() + col * spacing.width();
479 pointIsSnapped = true;
480 }
481
482 setSnappedPosition(snappedPoint);
483
484 return pointIsSnapped;
485 }
486
decoration(const KoViewConverter & converter) const487 QPainterPath GridSnapStrategy::decoration(const KoViewConverter &converter) const
488 {
489 QSizeF unzoomedSize = converter.viewToDocument(QSizeF(5, 5));
490 QPainterPath decoration;
491 decoration.moveTo(snappedPosition() - QPointF(unzoomedSize.width(), 0));
492 decoration.lineTo(snappedPosition() + QPointF(unzoomedSize.width(), 0));
493 decoration.moveTo(snappedPosition() - QPointF(0, unzoomedSize.height()));
494 decoration.lineTo(snappedPosition() + QPointF(0, unzoomedSize.height()));
495 return decoration;
496 }
497
BoundingBoxSnapStrategy()498 BoundingBoxSnapStrategy::BoundingBoxSnapStrategy()
499 : KoSnapStrategy(KoSnapGuide::BoundingBoxSnapping)
500 {
501 }
502
snap(const QPointF & mousePosition,KoSnapProxy * proxy,qreal maxSnapDistance)503 bool BoundingBoxSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy *proxy, qreal maxSnapDistance)
504 {
505 Q_ASSERT(std::isfinite(maxSnapDistance));
506 const qreal maxDistance = maxSnapDistance * maxSnapDistance;
507 qreal minDistance = HUGE_VAL;
508
509 QRectF rect(-maxSnapDistance, -maxSnapDistance, maxSnapDistance, maxSnapDistance);
510
511 rect.moveCenter(mousePosition);
512 QPointF snappedPoint = mousePosition;
513
514 KoFlake::AnchorPosition pointId[5] = {
515 KoFlake::TopLeft,
516 KoFlake::TopRight,
517 KoFlake::BottomRight,
518 KoFlake::BottomLeft,
519 KoFlake::Center
520 };
521
522 QList<KoShape*> shapes = proxy->shapesInRect(rect, true);
523 Q_FOREACH (KoShape * shape, shapes) {
524 qreal shapeMinDistance = HUGE_VAL;
525 // first check the corner and center points
526 for (int i = 0; i < 5; ++i) {
527 m_boxPoints[i] = shape->absolutePosition(pointId[i]);
528 qreal d = squareDistance(mousePosition, m_boxPoints[i]);
529 if (d < minDistance && d < maxDistance) {
530 shapeMinDistance = d;
531 minDistance = d;
532 snappedPoint = m_boxPoints[i];
533 }
534 }
535 // prioritize points over edges
536 if (shapeMinDistance < maxDistance)
537 continue;
538
539 // now check distances to edges of bounding box
540 for (int i = 0; i < 4; ++i) {
541 QPointF pointOnLine;
542 qreal d = squareDistanceToLine(m_boxPoints[i], m_boxPoints[(i+1)%4], mousePosition, pointOnLine);
543 if (d < minDistance && d < maxDistance) {
544 minDistance = d;
545 snappedPoint = pointOnLine;
546 }
547 }
548 }
549 setSnappedPosition(snappedPoint);
550
551 return (minDistance < maxDistance);
552 }
553
squareDistanceToLine(const QPointF & lineA,const QPointF & lineB,const QPointF & point,QPointF & pointOnLine)554 qreal BoundingBoxSnapStrategy::squareDistanceToLine(const QPointF &lineA, const QPointF &lineB, const QPointF &point, QPointF &pointOnLine)
555 {
556 QPointF diff = lineB - lineA;
557 if(lineA == lineB)
558 return HUGE_VAL;
559 const qreal diffLength = sqrt(diff.x() * diff.x() + diff.y() * diff.y());
560
561 // project mouse position relative to start position on line
562 const qreal scalar = KoSnapStrategy::scalarProduct(point - lineA, diff / diffLength);
563
564 if (scalar < 0.0 || scalar > diffLength)
565 return HUGE_VAL;
566 // calculate vector between relative mouse position and projected mouse position
567 pointOnLine = lineA + scalar / diffLength * diff;
568 QPointF distVec = pointOnLine - point;
569 return distVec.x()*distVec.x() + distVec.y()*distVec.y();
570 }
571
decoration(const KoViewConverter & converter) const572 QPainterPath BoundingBoxSnapStrategy::decoration(const KoViewConverter &converter) const
573 {
574 QSizeF unzoomedSize = converter.viewToDocument(QSizeF(5, 5));
575
576 QPainterPath decoration;
577 decoration.moveTo(snappedPosition() - QPointF(unzoomedSize.width(), unzoomedSize.height()));
578 decoration.lineTo(snappedPosition() + QPointF(unzoomedSize.width(), unzoomedSize.height()));
579 decoration.moveTo(snappedPosition() - QPointF(unzoomedSize.width(), -unzoomedSize.height()));
580 decoration.lineTo(snappedPosition() + QPointF(unzoomedSize.width(), -unzoomedSize.height()));
581
582 return decoration;
583 }
584
585 // KoGuidesData has been moved into Krita. Please port this class!
586
587 // LineGuideSnapStrategy::LineGuideSnapStrategy()
588 // : KoSnapStrategy(KoSnapGuide::GuideLineSnapping)
589 // {
590 // }
591
592 // bool LineGuideSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance)
593 // {
594 // Q_ASSERT(std::isfinite(maxSnapDistance));
595
596 // KoGuidesData * guidesData = proxy->canvas()->guidesData();
597
598 // if (!guidesData || !guidesData->showGuideLines())
599 // return false;
600
601 // QPointF snappedPoint = mousePosition;
602 // m_orientation = 0;
603
604 // qreal minHorzDistance = maxSnapDistance;
605 // Q_FOREACH (qreal guidePos, guidesData->horizontalGuideLines()) {
606 // qreal distance = qAbs(guidePos - mousePosition.y());
607 // if (distance < minHorzDistance) {
608 // snappedPoint.setY(guidePos);
609 // minHorzDistance = distance;
610 // m_orientation |= Qt::Horizontal;
611 // }
612 // }
613 // qreal minVertSnapDistance = maxSnapDistance;
614 // Q_FOREACH (qreal guidePos, guidesData->verticalGuideLines()) {
615 // qreal distance = qAbs(guidePos - mousePosition.x());
616 // if (distance < minVertSnapDistance) {
617 // snappedPoint.setX(guidePos);
618 // minVertSnapDistance = distance;
619 // m_orientation |= Qt::Vertical;
620 // }
621 // }
622 // setSnappedPosition(snappedPoint);
623 // return (minHorzDistance < maxSnapDistance || minVertSnapDistance < maxSnapDistance);
624 // }
625
626 // QPainterPath LineGuideSnapStrategy::decoration(const KoViewConverter &converter) const
627 // {
628 // QSizeF unzoomedSize = converter.viewToDocument(QSizeF(5, 5));
629 // Q_ASSERT(unzoomedSize.isValid());
630
631 // QPainterPath decoration;
632 // if (m_orientation & Qt::Horizontal) {
633 // decoration.moveTo(snappedPosition() - QPointF(unzoomedSize.width(), 0));
634 // decoration.lineTo(snappedPosition() + QPointF(unzoomedSize.width(), 0));
635 // }
636 // if (m_orientation & Qt::Vertical) {
637 // decoration.moveTo(snappedPosition() - QPointF(0, unzoomedSize.height()));
638 // decoration.lineTo(snappedPosition() + QPointF(0, unzoomedSize.height()));
639 // }
640
641 // return decoration;
642 // }
643