File indexing completed on 2024-05-12 15:56:51
0001 /* This file is part of the KDE project 0002 * SPDX-FileCopyrightText: 2008 Jan Hambrecht <jaham@gmx.net> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "KoSnapStrategy.h" 0008 #include "KoSnapProxy.h" 0009 #include "KoSnapGuide.h" 0010 #include <KoPathShape.h> 0011 #include <KoPathPoint.h> 0012 #include <KoPathSegment.h> 0013 #include <KoCanvasBase.h> 0014 #include <KoViewConverter.h> 0015 0016 #include <QPainter> 0017 #include <QPainterPath> 0018 0019 #include <cmath> 0020 0021 #if defined(_MSC_VER) && (_MSC_VER < 1800) 0022 #define isfinite(x) (double)(x) 0023 #endif 0024 0025 KoSnapStrategy::KoSnapStrategy(KoSnapGuide::Strategy type) 0026 : m_snapType(type) 0027 { 0028 } 0029 0030 QPointF KoSnapStrategy::snappedPosition() const 0031 { 0032 return m_snappedPosition; 0033 } 0034 0035 void KoSnapStrategy::setSnappedPosition(const QPointF &position) 0036 { 0037 m_snappedPosition = position; 0038 } 0039 0040 KoSnapGuide::Strategy KoSnapStrategy::type() const 0041 { 0042 return m_snapType; 0043 } 0044 0045 qreal KoSnapStrategy::squareDistance(const QPointF &p1, const QPointF &p2) 0046 { 0047 const qreal dx = p1.x() - p2.x(); 0048 const qreal dy = p1.y() - p2.y(); 0049 0050 return dx*dx + dy*dy; 0051 } 0052 0053 qreal KoSnapStrategy::scalarProduct(const QPointF &p1, const QPointF &p2) 0054 { 0055 return p1.x() * p2.x() + p1.y() * p2.y(); 0056 } 0057 0058 OrthogonalSnapStrategy::OrthogonalSnapStrategy() 0059 : KoSnapStrategy(KoSnapGuide::OrthogonalSnapping) 0060 { 0061 } 0062 0063 bool OrthogonalSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance) 0064 { 0065 Q_ASSERT(std::isfinite(maxSnapDistance)); 0066 QPointF horzSnap, vertSnap; 0067 qreal minVertDist = HUGE_VAL; 0068 qreal minHorzDist = HUGE_VAL; 0069 0070 QList<KoShape*> shapes = proxy->shapes(true); 0071 Q_FOREACH (KoShape * shape, shapes) { 0072 QList<QPointF> points = proxy->pointsFromShape(shape); 0073 foreach (const QPointF &point, points) { 0074 qreal dx = fabs(point.x() - mousePosition.x()); 0075 if (dx < minHorzDist && dx < maxSnapDistance) { 0076 minHorzDist = dx; 0077 horzSnap = point; 0078 } 0079 qreal dy = fabs(point.y() - mousePosition.y()); 0080 if (dy < minVertDist && dy < maxSnapDistance) { 0081 minVertDist = dy; 0082 vertSnap = point; 0083 } 0084 } 0085 } 0086 0087 QPointF snappedPoint = mousePosition; 0088 0089 if (minHorzDist < HUGE_VAL) 0090 snappedPoint.setX(horzSnap.x()); 0091 if (minVertDist < HUGE_VAL) 0092 snappedPoint.setY(vertSnap.y()); 0093 0094 if (minHorzDist < HUGE_VAL) 0095 m_hLine = QLineF(horzSnap, snappedPoint); 0096 else 0097 m_hLine = QLineF(); 0098 0099 if (minVertDist < HUGE_VAL) 0100 m_vLine = QLineF(vertSnap, snappedPoint); 0101 else 0102 m_vLine = QLineF(); 0103 0104 setSnappedPosition(snappedPoint); 0105 0106 return (minHorzDist < HUGE_VAL || minVertDist < HUGE_VAL); 0107 } 0108 0109 QPainterPath OrthogonalSnapStrategy::decoration(const KoViewConverter &/*converter*/) const 0110 { 0111 QPainterPath decoration; 0112 if (! m_hLine.isNull()) { 0113 decoration.moveTo(m_hLine.p1()); 0114 decoration.lineTo(m_hLine.p2()); 0115 } 0116 if (! m_vLine.isNull()) { 0117 decoration.moveTo(m_vLine.p1()); 0118 decoration.lineTo(m_vLine.p2()); 0119 } 0120 return decoration; 0121 } 0122 0123 NodeSnapStrategy::NodeSnapStrategy() 0124 : KoSnapStrategy(KoSnapGuide::NodeSnapping) 0125 { 0126 } 0127 0128 bool NodeSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance) 0129 { 0130 Q_ASSERT(std::isfinite(maxSnapDistance)); 0131 const qreal maxDistance = maxSnapDistance * maxSnapDistance; 0132 qreal minDistance = HUGE_VAL; 0133 0134 QRectF rect(-maxSnapDistance, -maxSnapDistance, maxSnapDistance, maxSnapDistance); 0135 rect.moveCenter(mousePosition); 0136 QList<QPointF> points = proxy->pointsInRect(rect, false); 0137 QPointF snappedPoint = mousePosition; 0138 0139 foreach (const QPointF &point, points) { 0140 qreal distance = squareDistance(mousePosition, point); 0141 if (distance < maxDistance && distance < minDistance) { 0142 snappedPoint = point; 0143 minDistance = distance; 0144 } 0145 } 0146 0147 setSnappedPosition(snappedPoint); 0148 0149 return (minDistance < HUGE_VAL); 0150 } 0151 0152 QPainterPath NodeSnapStrategy::decoration(const KoViewConverter &converter) const 0153 { 0154 QRectF unzoomedRect = converter.viewToDocument(QRectF(0, 0, 11, 11)); 0155 unzoomedRect.moveCenter(snappedPosition()); 0156 QPainterPath decoration; 0157 decoration.addEllipse(unzoomedRect); 0158 return decoration; 0159 } 0160 0161 ExtensionSnapStrategy::ExtensionSnapStrategy() 0162 : KoSnapStrategy(KoSnapGuide::ExtensionSnapping) 0163 { 0164 } 0165 0166 bool ExtensionSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance) 0167 { 0168 Q_ASSERT(std::isfinite(maxSnapDistance)); 0169 0170 const qreal maxDistance = maxSnapDistance * maxSnapDistance; 0171 qreal minDistances[2] = { HUGE_VAL, HUGE_VAL }; 0172 0173 QPointF snappedPoints[2] = { mousePosition, mousePosition }; 0174 QPointF startPoints[2]; 0175 0176 QList<KoShape*> shapes = proxy->shapes(true); 0177 0178 Q_FOREACH (KoShape * shape, shapes) { 0179 KoPathShape * path = dynamic_cast<KoPathShape*>(shape); 0180 if (! path) { 0181 continue; 0182 } 0183 QTransform matrix = path->absoluteTransformation(); 0184 0185 const int subpathCount = path->subpathCount(); 0186 for (int subpathIndex = 0; subpathIndex < subpathCount; ++subpathIndex) { 0187 if (path->isClosedSubpath(subpathIndex)) 0188 continue; 0189 0190 int pointCount = path->subpathPointCount(subpathIndex); 0191 0192 // check the extension from the start point 0193 KoPathPoint * first = path->pointByIndex(KoPathPointIndex(subpathIndex, 0)); 0194 QPointF firstSnapPosition = mousePosition; 0195 if (snapToExtension(firstSnapPosition, first, matrix)) { 0196 qreal distance = squareDistance(firstSnapPosition, mousePosition); 0197 if (distance < maxDistance) { 0198 if (distance < minDistances[0]) { 0199 minDistances[1] = minDistances[0]; 0200 snappedPoints[1] = snappedPoints[0]; 0201 startPoints[1] = startPoints[0]; 0202 0203 minDistances[0] = distance; 0204 snappedPoints[0] = firstSnapPosition; 0205 startPoints[0] = matrix.map(first->point()); 0206 } 0207 else if (distance < minDistances[1]) { 0208 minDistances[1] = distance; 0209 snappedPoints[1] = firstSnapPosition; 0210 startPoints[1] = matrix.map(first->point()); 0211 } 0212 } 0213 } 0214 0215 // now check the extension from the last point 0216 KoPathPoint * last = path->pointByIndex(KoPathPointIndex(subpathIndex, pointCount - 1)); 0217 QPointF lastSnapPosition = mousePosition; 0218 if (snapToExtension(lastSnapPosition, last, matrix)) { 0219 qreal distance = squareDistance(lastSnapPosition, mousePosition); 0220 if (distance < maxDistance) { 0221 if (distance < minDistances[0]) { 0222 minDistances[1] = minDistances[0]; 0223 snappedPoints[1] = snappedPoints[0]; 0224 startPoints[1] = startPoints[0]; 0225 0226 minDistances[0] = distance; 0227 snappedPoints[0] = lastSnapPosition; 0228 startPoints[0] = matrix.map(last->point()); 0229 } 0230 else if (distance < minDistances[1]) { 0231 minDistances[1] = distance; 0232 snappedPoints[1] = lastSnapPosition; 0233 startPoints[1] = matrix.map(last->point()); 0234 } 0235 } 0236 } 0237 } 0238 } 0239 0240 m_lines.clear(); 0241 // if we have to extension near our mouse position, they might have an intersection 0242 // near our mouse position which we want to use as the snapped position 0243 if (minDistances[0] < HUGE_VAL && minDistances[1] < HUGE_VAL) { 0244 // check if intersection of extension lines is near mouse position 0245 KoPathSegment s1(startPoints[0], snappedPoints[0] + snappedPoints[0]-startPoints[0]); 0246 KoPathSegment s2(startPoints[1], snappedPoints[1] + snappedPoints[1]-startPoints[1]); 0247 QList<QPointF> isects = s1.intersections(s2); 0248 if (isects.count() == 1 && squareDistance(isects[0], mousePosition) < maxDistance) { 0249 // add both extension lines 0250 m_lines.append(QLineF(startPoints[0], isects[0])); 0251 m_lines.append(QLineF(startPoints[1], isects[0])); 0252 setSnappedPosition(isects[0]); 0253 } 0254 else { 0255 // only add nearest extension line of both 0256 uint index = minDistances[0] < minDistances[1] ? 0 : 1; 0257 m_lines.append(QLineF(startPoints[index], snappedPoints[index])); 0258 setSnappedPosition(snappedPoints[index]); 0259 } 0260 } 0261 else if (minDistances[0] < HUGE_VAL) { 0262 m_lines.append(QLineF(startPoints[0], snappedPoints[0])); 0263 setSnappedPosition(snappedPoints[0]); 0264 } 0265 else if (minDistances[1] < HUGE_VAL) { 0266 m_lines.append(QLineF(startPoints[1], snappedPoints[1])); 0267 setSnappedPosition(snappedPoints[1]); 0268 } 0269 else { 0270 // none of the extension lines is near our mouse position 0271 return false; 0272 } 0273 return true; 0274 } 0275 0276 QPainterPath ExtensionSnapStrategy::decoration(const KoViewConverter &/*converter*/) const 0277 { 0278 QPainterPath decoration; 0279 foreach (const QLineF &line, m_lines) { 0280 decoration.moveTo(line.p1()); 0281 decoration.lineTo(line.p2()); 0282 } 0283 return decoration; 0284 } 0285 0286 bool ExtensionSnapStrategy::snapToExtension(QPointF &position, KoPathPoint * point, const QTransform &matrix) 0287 { 0288 Q_ASSERT(point); 0289 QPointF direction = extensionDirection(point, matrix); 0290 if (direction.isNull()) 0291 return false; 0292 0293 QPointF extensionStart = matrix.map(point->point()); 0294 QPointF extensionStop = matrix.map(point->point()) + direction; 0295 float posOnExtension = project(extensionStart, extensionStop, position); 0296 if (posOnExtension < 0.0) 0297 return false; 0298 0299 position = extensionStart + posOnExtension * direction; 0300 return true; 0301 } 0302 0303 qreal ExtensionSnapStrategy::project(const QPointF &lineStart, const QPointF &lineEnd, const QPointF &point) 0304 { 0305 // This is how the returned value should be used to get the 0306 // projectionPoint: ProjectionPoint = lineStart(1-resultingReal) + resultingReal*lineEnd; 0307 0308 QPointF diff = lineEnd - lineStart; 0309 QPointF relPoint = point - lineStart; 0310 qreal diffLength = sqrt(diff.x() * diff.x() + diff.y() * diff.y()); 0311 if (diffLength == 0.0) 0312 return 0.0; 0313 0314 diff /= diffLength; 0315 // project mouse position relative to stop position on extension line 0316 qreal scalar = relPoint.x() * diff.x() + relPoint.y() * diff.y(); 0317 return scalar /= diffLength; 0318 } 0319 0320 QPointF ExtensionSnapStrategy::extensionDirection(KoPathPoint * point, const QTransform &matrix) 0321 { 0322 Q_ASSERT(point); 0323 0324 KoPathShape * path = point->parent(); 0325 KoPathPointIndex index = path->pathPointIndex(point); 0326 0327 // check if it is a start point 0328 if (point->properties() & KoPathPoint::StartSubpath) { 0329 if (point->activeControlPoint2()) { 0330 return matrix.map(point->point()) - matrix.map(point->controlPoint2()); 0331 } else { 0332 KoPathPoint * next = path->pointByIndex(KoPathPointIndex(index.first, index.second + 1)); 0333 if (! next){ 0334 return QPointF(); 0335 } 0336 else if (next->activeControlPoint1()) { 0337 return matrix.map(point->point()) - matrix.map(next->controlPoint1()); 0338 } 0339 else { 0340 return matrix.map(point->point()) - matrix.map(next->point()); 0341 } 0342 } 0343 } 0344 else { 0345 if (point->activeControlPoint1()) { 0346 return matrix.map(point->point()) - matrix.map(point->controlPoint1()); 0347 } 0348 else { 0349 KoPathPoint * prev = path->pointByIndex(KoPathPointIndex(index.first, index.second - 1)); 0350 if (! prev){ 0351 return QPointF(); 0352 } 0353 else if (prev->activeControlPoint2()) { 0354 return matrix.map(point->point()) - matrix.map(prev->controlPoint2()); 0355 } 0356 else { 0357 return matrix.map(point->point()) - matrix.map(prev->point()); 0358 } 0359 } 0360 } 0361 } 0362 0363 IntersectionSnapStrategy::IntersectionSnapStrategy() 0364 : KoSnapStrategy(KoSnapGuide::IntersectionSnapping) 0365 { 0366 } 0367 0368 bool IntersectionSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy *proxy, qreal maxSnapDistance) 0369 { 0370 Q_ASSERT(std::isfinite(maxSnapDistance)); 0371 const qreal maxDistance = maxSnapDistance * maxSnapDistance; 0372 qreal minDistance = HUGE_VAL; 0373 0374 QRectF rect(-maxSnapDistance, -maxSnapDistance, maxSnapDistance, maxSnapDistance); 0375 rect.moveCenter(mousePosition); 0376 QPointF snappedPoint = mousePosition; 0377 0378 QList<KoPathSegment> segments = proxy->segmentsInRect(rect, false); 0379 int segmentCount = segments.count(); 0380 for (int i = 0; i < segmentCount; ++i) { 0381 const KoPathSegment &s1 = segments[i]; 0382 for (int j = i + 1; j < segmentCount; ++j) { 0383 QList<QPointF> isects = s1.intersections(segments[j]); 0384 Q_FOREACH (const QPointF &point, isects) { 0385 if (! rect.contains(point)) 0386 continue; 0387 qreal distance = squareDistance(mousePosition, point); 0388 if (distance < maxDistance && distance < minDistance) { 0389 snappedPoint = point; 0390 minDistance = distance; 0391 } 0392 } 0393 } 0394 } 0395 0396 setSnappedPosition(snappedPoint); 0397 0398 return (minDistance < HUGE_VAL); 0399 } 0400 0401 QPainterPath IntersectionSnapStrategy::decoration(const KoViewConverter &converter) const 0402 { 0403 QRectF unzoomedRect = converter.viewToDocument(QRectF(0, 0, 11, 11)); 0404 unzoomedRect.moveCenter(snappedPosition()); 0405 QPainterPath decoration; 0406 decoration.addRect(unzoomedRect); 0407 return decoration; 0408 } 0409 0410 GridSnapStrategy::GridSnapStrategy() 0411 : KoSnapStrategy(KoSnapGuide::GridSnapping) 0412 { 0413 } 0414 0415 bool GridSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy *proxy, qreal maxSnapDistance) 0416 { 0417 Q_ASSERT(std::isfinite(maxSnapDistance)); 0418 if (! proxy->canvas()->snapToGrid()) 0419 return false; 0420 0421 // The 1e-10 here is a workaround for some weird division problem. 0422 // 360.00062366 / 2.83465058 gives 127 'exactly' when shown as a qreal, 0423 // but when casting into an int, we get 126. In fact it's 127 - 5.64e-15 ! 0424 QPointF offset; 0425 QSizeF spacing; 0426 proxy->canvas()->gridSize(&offset, &spacing); 0427 0428 // we want to snap to the nearest grid point, so calculate 0429 // the grid rows/columns before and after the points position 0430 int col = static_cast<int>((mousePosition.x() - offset.x()) / spacing.width() + 1e-10); 0431 int nextCol = col + 1; 0432 int row = static_cast<int>((mousePosition.y() - offset.y()) / spacing.height() + 1e-10); 0433 int nextRow = row + 1; 0434 0435 // now check which grid line has less distance to the point 0436 qreal distToCol = qAbs(offset.x() + col * spacing.width() - mousePosition.x()); 0437 qreal distToNextCol = qAbs(offset.x() + nextCol * spacing.width() - mousePosition.x()); 0438 0439 if (distToCol > distToNextCol) { 0440 col = nextCol; 0441 distToCol = distToNextCol; 0442 } 0443 0444 qreal distToRow = qAbs(offset.y() + row * spacing.height() - mousePosition.y()); 0445 qreal distToNextRow = qAbs(offset.y() + nextRow * spacing.height() - mousePosition.y()); 0446 if (distToRow > distToNextRow) { 0447 row = nextRow; 0448 distToRow = distToNextRow; 0449 } 0450 0451 QPointF snappedPoint = mousePosition; 0452 0453 bool pointIsSnapped = false; 0454 0455 const qreal sqDistance = distToCol * distToCol + distToRow * distToRow; 0456 const qreal maxSqDistance = maxSnapDistance * maxSnapDistance; 0457 // now check if we are inside the snap distance 0458 if (sqDistance < maxSqDistance) { 0459 snappedPoint = QPointF(offset.x() + col * spacing.width(), offset.y() + row * spacing.height()); 0460 pointIsSnapped = true; 0461 } else if (distToRow < maxSnapDistance) { 0462 snappedPoint.ry() = offset.y() + row * spacing.height(); 0463 pointIsSnapped = true; 0464 } else if (distToCol < maxSnapDistance) { 0465 snappedPoint.rx() = offset.x() + col * spacing.width(); 0466 pointIsSnapped = true; 0467 } 0468 0469 setSnappedPosition(snappedPoint); 0470 0471 return pointIsSnapped; 0472 } 0473 0474 QPainterPath GridSnapStrategy::decoration(const KoViewConverter &converter) const 0475 { 0476 QSizeF unzoomedSize = converter.viewToDocument(QSizeF(5, 5)); 0477 QPainterPath decoration; 0478 decoration.moveTo(snappedPosition() - QPointF(unzoomedSize.width(), 0)); 0479 decoration.lineTo(snappedPosition() + QPointF(unzoomedSize.width(), 0)); 0480 decoration.moveTo(snappedPosition() - QPointF(0, unzoomedSize.height())); 0481 decoration.lineTo(snappedPosition() + QPointF(0, unzoomedSize.height())); 0482 return decoration; 0483 } 0484 0485 BoundingBoxSnapStrategy::BoundingBoxSnapStrategy() 0486 : KoSnapStrategy(KoSnapGuide::BoundingBoxSnapping) 0487 { 0488 } 0489 0490 bool BoundingBoxSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy *proxy, qreal maxSnapDistance) 0491 { 0492 Q_ASSERT(std::isfinite(maxSnapDistance)); 0493 const qreal maxDistance = maxSnapDistance * maxSnapDistance; 0494 qreal minDistance = HUGE_VAL; 0495 0496 QRectF rect(-maxSnapDistance, -maxSnapDistance, maxSnapDistance, maxSnapDistance); 0497 0498 rect.moveCenter(mousePosition); 0499 QPointF snappedPoint = mousePosition; 0500 0501 KoFlake::AnchorPosition pointId[5] = { 0502 KoFlake::TopLeft, 0503 KoFlake::TopRight, 0504 KoFlake::BottomRight, 0505 KoFlake::BottomLeft, 0506 KoFlake::Center 0507 }; 0508 0509 QList<KoShape*> shapes = proxy->shapesInRect(rect, true); 0510 Q_FOREACH (KoShape * shape, shapes) { 0511 qreal shapeMinDistance = HUGE_VAL; 0512 // first check the corner and center points 0513 for (int i = 0; i < 5; ++i) { 0514 m_boxPoints[i] = shape->absolutePosition(pointId[i]); 0515 qreal d = squareDistance(mousePosition, m_boxPoints[i]); 0516 if (d < minDistance && d < maxDistance) { 0517 shapeMinDistance = d; 0518 minDistance = d; 0519 snappedPoint = m_boxPoints[i]; 0520 } 0521 } 0522 // prioritize points over edges 0523 if (shapeMinDistance < maxDistance) 0524 continue; 0525 0526 // now check distances to edges of bounding box 0527 for (int i = 0; i < 4; ++i) { 0528 QPointF pointOnLine; 0529 qreal d = squareDistanceToLine(m_boxPoints[i], m_boxPoints[(i+1)%4], mousePosition, pointOnLine); 0530 if (d < minDistance && d < maxDistance) { 0531 minDistance = d; 0532 snappedPoint = pointOnLine; 0533 } 0534 } 0535 } 0536 setSnappedPosition(snappedPoint); 0537 0538 return (minDistance < maxDistance); 0539 } 0540 0541 qreal BoundingBoxSnapStrategy::squareDistanceToLine(const QPointF &lineA, const QPointF &lineB, const QPointF &point, QPointF &pointOnLine) 0542 { 0543 QPointF diff = lineB - lineA; 0544 if(lineA == lineB) 0545 return HUGE_VAL; 0546 const qreal diffLength = sqrt(diff.x() * diff.x() + diff.y() * diff.y()); 0547 0548 // project mouse position relative to start position on line 0549 const qreal scalar = KoSnapStrategy::scalarProduct(point - lineA, diff / diffLength); 0550 0551 if (scalar < 0.0 || scalar > diffLength) 0552 return HUGE_VAL; 0553 // calculate vector between relative mouse position and projected mouse position 0554 pointOnLine = lineA + scalar / diffLength * diff; 0555 QPointF distVec = pointOnLine - point; 0556 return distVec.x()*distVec.x() + distVec.y()*distVec.y(); 0557 } 0558 0559 QPainterPath BoundingBoxSnapStrategy::decoration(const KoViewConverter &converter) const 0560 { 0561 QSizeF unzoomedSize = converter.viewToDocument(QSizeF(5, 5)); 0562 0563 QPainterPath decoration; 0564 decoration.moveTo(snappedPosition() - QPointF(unzoomedSize.width(), unzoomedSize.height())); 0565 decoration.lineTo(snappedPosition() + QPointF(unzoomedSize.width(), unzoomedSize.height())); 0566 decoration.moveTo(snappedPosition() - QPointF(unzoomedSize.width(), -unzoomedSize.height())); 0567 decoration.lineTo(snappedPosition() + QPointF(unzoomedSize.width(), -unzoomedSize.height())); 0568 0569 return decoration; 0570 } 0571 0572 // KoGuidesData has been moved into Krita. Please port this class! 0573 0574 // LineGuideSnapStrategy::LineGuideSnapStrategy() 0575 // : KoSnapStrategy(KoSnapGuide::GuideLineSnapping) 0576 // { 0577 // } 0578 0579 // bool LineGuideSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance) 0580 // { 0581 // Q_ASSERT(std::isfinite(maxSnapDistance)); 0582 0583 // KoGuidesData * guidesData = proxy->canvas()->guidesData(); 0584 0585 // if (!guidesData || !guidesData->showGuideLines()) 0586 // return false; 0587 0588 // QPointF snappedPoint = mousePosition; 0589 // m_orientation = 0; 0590 0591 // qreal minHorzDistance = maxSnapDistance; 0592 // Q_FOREACH (qreal guidePos, guidesData->horizontalGuideLines()) { 0593 // qreal distance = qAbs(guidePos - mousePosition.y()); 0594 // if (distance < minHorzDistance) { 0595 // snappedPoint.setY(guidePos); 0596 // minHorzDistance = distance; 0597 // m_orientation |= Qt::Horizontal; 0598 // } 0599 // } 0600 // qreal minVertSnapDistance = maxSnapDistance; 0601 // Q_FOREACH (qreal guidePos, guidesData->verticalGuideLines()) { 0602 // qreal distance = qAbs(guidePos - mousePosition.x()); 0603 // if (distance < minVertSnapDistance) { 0604 // snappedPoint.setX(guidePos); 0605 // minVertSnapDistance = distance; 0606 // m_orientation |= Qt::Vertical; 0607 // } 0608 // } 0609 // setSnappedPosition(snappedPoint); 0610 // return (minHorzDistance < maxSnapDistance || minVertSnapDistance < maxSnapDistance); 0611 // } 0612 0613 // QPainterPath LineGuideSnapStrategy::decoration(const KoViewConverter &converter) const 0614 // { 0615 // QSizeF unzoomedSize = converter.viewToDocument(QSizeF(5, 5)); 0616 // Q_ASSERT(unzoomedSize.isValid()); 0617 0618 // QPainterPath decoration; 0619 // if (m_orientation & Qt::Horizontal) { 0620 // decoration.moveTo(snappedPosition() - QPointF(unzoomedSize.width(), 0)); 0621 // decoration.lineTo(snappedPosition() + QPointF(unzoomedSize.width(), 0)); 0622 // } 0623 // if (m_orientation & Qt::Vertical) { 0624 // decoration.moveTo(snappedPosition() - QPointF(0, unzoomedSize.height())); 0625 // decoration.lineTo(snappedPosition() + QPointF(0, unzoomedSize.height())); 0626 // } 0627 0628 // return decoration; 0629 // }