diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 2803c9d724..9335072cd2 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -1,93 +1,93 @@ set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) include_directories( ${CMAKE_SOURCE_DIR}/sdk/tests ${CMAKE_SOURCE_DIR}/libs/pigment ${CMAKE_SOURCE_DIR}/libs/pigment/compositeops ) include_directories(SYSTEM ${EIGEN3_INCLUDE_DIR} ) set(LINK_VC_LIB) if(HAVE_VC) include_directories(${Vc_INCLUDE_DIR}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Vc_DEFINITIONS}") set(LINK_VC_LIB ${Vc_LIBRARIES}) endif() macro_add_unittest_definitions() ########### next target ############### set(kis_datamanager_benchmark_SRCS kis_datamanager_benchmark.cpp) set(kis_hiterator_benchmark_SRCS kis_hline_iterator_benchmark.cpp) set(kis_viterator_benchmark_SRCS kis_vline_iterator_benchmark.cpp) set(kis_random_iterator_benchmark_SRCS kis_random_iterator_benchmark.cpp) set(kis_projection_benchmark_SRCS kis_projection_benchmark.cpp) set(kis_bcontrast_benchmark_SRCS kis_bcontrast_benchmark.cpp) set(kis_blur_benchmark_SRCS kis_blur_benchmark.cpp) set(kis_level_filter_benchmark_SRCS kis_level_filter_benchmark.cpp) set(kis_painter_benchmark_SRCS kis_painter_benchmark.cpp) set(kis_stroke_benchmark_SRCS kis_stroke_benchmark.cpp) set(kis_fast_math_benchmark_SRCS kis_fast_math_benchmark.cpp) set(kis_floodfill_benchmark_SRCS kis_floodfill_benchmark.cpp) set(kis_gradient_benchmark_SRCS kis_gradient_benchmark.cpp) set(kis_mask_generator_benchmark_SRCS kis_mask_generator_benchmark.cpp) set(kis_low_memory_benchmark_SRCS kis_low_memory_benchmark.cpp) set(KisAnimationRenderingBenchmark_SRCS KisAnimationRenderingBenchmark.cpp) set(kis_filter_selections_benchmark_SRCS kis_filter_selections_benchmark.cpp) if (UNIX) - #set(kis_composition_benchmark_SRCS kis_composition_benchmark.cpp) + set(kis_composition_benchmark_SRCS kis_composition_benchmark.cpp) endif() set(kis_thumbnail_benchmark_SRCS kis_thumbnail_benchmark.cpp) krita_add_benchmark(KisDatamanagerBenchmark TESTNAME krita-benchmarks-KisDataManager ${kis_datamanager_benchmark_SRCS}) krita_add_benchmark(KisHLineIteratorBenchmark TESTNAME krita-benchmarks-KisHLineIterator ${kis_hiterator_benchmark_SRCS}) krita_add_benchmark(KisVLineIteratorBenchmark TESTNAME krita-benchmarks-KisVLineIterator ${kis_viterator_benchmark_SRCS}) krita_add_benchmark(KisRandomIteratorBenchmark TESTNAME krita-benchmarks-KisRandomIterator ${kis_random_iterator_benchmark_SRCS}) krita_add_benchmark(KisProjectionBenchmark TESTNAME krita-benchmarks-KisProjectionBenchmark ${kis_projection_benchmark_SRCS}) krita_add_benchmark(KisBContrastBenchmark TESTNAME krita-benchmarks-KisBContrastBenchmark ${kis_bcontrast_benchmark_SRCS}) krita_add_benchmark(KisBlurBenchmark TESTNAME krita-benchmarks-KisBlurBenchmark ${kis_blur_benchmark_SRCS}) krita_add_benchmark(KisLevelFilterBenchmark TESTNAME krita-benchmarks-KisLevelFilterBenchmark ${kis_level_filter_benchmark_SRCS}) krita_add_benchmark(KisPainterBenchmark TESTNAME krita-benchmarks-KisPainterBenchmark ${kis_painter_benchmark_SRCS}) krita_add_benchmark(KisStrokeBenchmark TESTNAME krita-benchmarks-KisStrokeBenchmark ${kis_stroke_benchmark_SRCS}) krita_add_benchmark(KisFastMathBenchmark TESTNAME krita-benchmarks-KisFastMath ${kis_fast_math_benchmark_SRCS}) krita_add_benchmark(KisFloodfillBenchmark TESTNAME krita-benchmarks-KisFloodFill ${kis_floodfill_benchmark_SRCS}) krita_add_benchmark(KisGradientBenchmark TESTNAME krita-benchmarks-KisGradientFill ${kis_gradient_benchmark_SRCS}) krita_add_benchmark(KisMaskGeneratorBenchmark TESTNAME krita-benchmarks-KisMaskGenerator ${kis_mask_generator_benchmark_SRCS}) krita_add_benchmark(KisLowMemoryBenchmark TESTNAME krita-benchmarks-KisLowMemory ${kis_low_memory_benchmark_SRCS}) krita_add_benchmark(KisAnimationRenderingBenchmark TESTNAME krita-benchmarks-KisAnimationRenderingBenchmark ${KisAnimationRenderingBenchmark_SRCS}) krita_add_benchmark(KisFilterSelectionsBenchmark TESTNAME krita-image-KisFilterSelectionsBenchmark ${kis_filter_selections_benchmark_SRCS}) if(UNIX) - #krita_add_benchmark(KisCompositionBenchmark TESTNAME krita-benchmarks-KisComposition ${kis_composition_benchmark_SRCS}) + krita_add_benchmark(KisCompositionBenchmark TESTNAME krita-benchmarks-KisComposition ${kis_composition_benchmark_SRCS}) endif() krita_add_benchmark(KisThumbnailBenchmark TESTNAME krita-benchmarks-KisThumbnail ${kis_thumbnail_benchmark_SRCS}) target_link_libraries(KisDatamanagerBenchmark kritaimage Qt5::Test) target_link_libraries(KisHLineIteratorBenchmark kritaimage Qt5::Test) target_link_libraries(KisVLineIteratorBenchmark kritaimage Qt5::Test) target_link_libraries(KisRandomIteratorBenchmark kritaimage Qt5::Test) target_link_libraries(KisProjectionBenchmark kritaimage kritaui Qt5::Test) target_link_libraries(KisBContrastBenchmark kritaimage Qt5::Test) target_link_libraries(KisBlurBenchmark kritaimage Qt5::Test) target_link_libraries(KisLevelFilterBenchmark kritaimage Qt5::Test) target_link_libraries(KisPainterBenchmark kritaimage Qt5::Test) target_link_libraries(KisStrokeBenchmark kritaimage Qt5::Test) target_link_libraries(KisFastMathBenchmark kritaimage Qt5::Test) target_link_libraries(KisFloodfillBenchmark kritaimage Qt5::Test) target_link_libraries(KisGradientBenchmark kritaimage Qt5::Test) target_link_libraries(KisLowMemoryBenchmark kritaimage Qt5::Test) target_link_libraries(KisAnimationRenderingBenchmark kritaimage kritaui Qt5::Test) target_link_libraries(KisFilterSelectionsBenchmark kritaimage Qt5::Test) if(UNIX) - #target_link_libraries(KisCompositionBenchmark kritaimage Qt5::Test ${LINK_VC_LIB}) + target_link_libraries(KisCompositionBenchmark kritaimage Qt5::Test ${LINK_VC_LIB}) if(HAVE_VC) - #set_property(TARGET KisCompositionBenchmark APPEND PROPERTY COMPILE_OPTIONS "${Vc_ARCHITECTURE_FLAGS}") + set_property(TARGET KisCompositionBenchmark APPEND PROPERTY COMPILE_OPTIONS "${Vc_ARCHITECTURE_FLAGS}") endif() endif() target_link_libraries(KisMaskGeneratorBenchmark kritaimage Qt5::Test) target_link_libraries(KisThumbnailBenchmark kritaimage Qt5::Test) diff --git a/libs/flake/KoSnapStrategy.cpp b/libs/flake/KoSnapStrategy.cpp index 574d8be180..48db78225a 100644 --- a/libs/flake/KoSnapStrategy.cpp +++ b/libs/flake/KoSnapStrategy.cpp @@ -1,703 +1,666 @@ /* This file is part of the KDE project * Copyright (C) 2008 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoSnapStrategy.h" #include "KoSnapProxy.h" #include "KoSnapGuide.h" #include #include #include #include #include #include #include #if defined(_MSC_VER) && (_MSC_VER < 1800) #define isfinite(x) (double)(x) #endif KoSnapStrategy::KoSnapStrategy(KoSnapGuide::Strategy type) : m_snapType(type) { } QPointF KoSnapStrategy::snappedPosition() const { return m_snappedPosition; } void KoSnapStrategy::setSnappedPosition(const QPointF &position) { m_snappedPosition = position; } KoSnapGuide::Strategy KoSnapStrategy::type() const { return m_snapType; } qreal KoSnapStrategy::squareDistance(const QPointF &p1, const QPointF &p2) { const qreal dx = p1.x() - p2.x(); const qreal dy = p1.y() - p2.y(); return dx*dx + dy*dy; } qreal KoSnapStrategy::scalarProduct(const QPointF &p1, const QPointF &p2) { return p1.x() * p2.x() + p1.y() * p2.y(); } OrthogonalSnapStrategy::OrthogonalSnapStrategy() : KoSnapStrategy(KoSnapGuide::OrthogonalSnapping) { } bool OrthogonalSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance) { Q_ASSERT(std::isfinite(maxSnapDistance)); QPointF horzSnap, vertSnap; qreal minVertDist = HUGE_VAL; qreal minHorzDist = HUGE_VAL; QList shapes = proxy->shapes(); Q_FOREACH (KoShape * shape, shapes) { QList points = proxy->pointsFromShape(shape); foreach (const QPointF &point, points) { qreal dx = fabs(point.x() - mousePosition.x()); if (dx < minHorzDist && dx < maxSnapDistance) { minHorzDist = dx; horzSnap = point; } qreal dy = fabs(point.y() - mousePosition.y()); if (dy < minVertDist && dy < maxSnapDistance) { minVertDist = dy; vertSnap = point; } } } QPointF snappedPoint = mousePosition; if (minHorzDist < HUGE_VAL) snappedPoint.setX(horzSnap.x()); if (minVertDist < HUGE_VAL) snappedPoint.setY(vertSnap.y()); if (minHorzDist < HUGE_VAL) m_hLine = QLineF(horzSnap, snappedPoint); else m_hLine = QLineF(); if (minVertDist < HUGE_VAL) m_vLine = QLineF(vertSnap, snappedPoint); else m_vLine = QLineF(); setSnappedPosition(snappedPoint); return (minHorzDist < HUGE_VAL || minVertDist < HUGE_VAL); } QPainterPath OrthogonalSnapStrategy::decoration(const KoViewConverter &/*converter*/) const { QPainterPath decoration; if (! m_hLine.isNull()) { decoration.moveTo(m_hLine.p1()); decoration.lineTo(m_hLine.p2()); } if (! m_vLine.isNull()) { decoration.moveTo(m_vLine.p1()); decoration.lineTo(m_vLine.p2()); } return decoration; } NodeSnapStrategy::NodeSnapStrategy() : KoSnapStrategy(KoSnapGuide::NodeSnapping) { } bool NodeSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance) { Q_ASSERT(std::isfinite(maxSnapDistance)); const qreal maxDistance = maxSnapDistance * maxSnapDistance; qreal minDistance = HUGE_VAL; QRectF rect(-maxSnapDistance, -maxSnapDistance, maxSnapDistance, maxSnapDistance); rect.moveCenter(mousePosition); QList points = proxy->pointsInRect(rect, false); QPointF snappedPoint = mousePosition; foreach (const QPointF &point, points) { qreal distance = squareDistance(mousePosition, point); if (distance < maxDistance && distance < minDistance) { snappedPoint = point; minDistance = distance; } } setSnappedPosition(snappedPoint); return (minDistance < HUGE_VAL); } QPainterPath NodeSnapStrategy::decoration(const KoViewConverter &converter) const { QRectF unzoomedRect = converter.viewToDocument(QRectF(0, 0, 11, 11)); unzoomedRect.moveCenter(snappedPosition()); QPainterPath decoration; decoration.addEllipse(unzoomedRect); return decoration; } ExtensionSnapStrategy::ExtensionSnapStrategy() : KoSnapStrategy(KoSnapGuide::ExtensionSnapping) { } bool ExtensionSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance) { Q_ASSERT(std::isfinite(maxSnapDistance)); const qreal maxDistance = maxSnapDistance * maxSnapDistance; qreal minDistances[2] = { HUGE_VAL, HUGE_VAL }; QPointF snappedPoints[2] = { mousePosition, mousePosition }; QPointF startPoints[2]; QList shapes = proxy->shapes(true); Q_FOREACH (KoShape * shape, shapes) { KoPathShape * path = dynamic_cast(shape); if (! path) { continue; } QTransform matrix = path->absoluteTransformation(0); const int subpathCount = path->subpathCount(); for (int subpathIndex = 0; subpathIndex < subpathCount; ++subpathIndex) { if (path->isClosedSubpath(subpathIndex)) continue; int pointCount = path->subpathPointCount(subpathIndex); // check the extension from the start point KoPathPoint * first = path->pointByIndex(KoPathPointIndex(subpathIndex, 0)); QPointF firstSnapPosition = mousePosition; if (snapToExtension(firstSnapPosition, first, matrix)) { qreal distance = squareDistance(firstSnapPosition, mousePosition); if (distance < maxDistance) { if (distance < minDistances[0]) { minDistances[1] = minDistances[0]; snappedPoints[1] = snappedPoints[0]; startPoints[1] = startPoints[0]; minDistances[0] = distance; snappedPoints[0] = firstSnapPosition; startPoints[0] = matrix.map(first->point()); } else if (distance < minDistances[1]) { minDistances[1] = distance; snappedPoints[1] = firstSnapPosition; startPoints[1] = matrix.map(first->point()); } } } // now check the extension from the last point KoPathPoint * last = path->pointByIndex(KoPathPointIndex(subpathIndex, pointCount - 1)); QPointF lastSnapPosition = mousePosition; if (snapToExtension(lastSnapPosition, last, matrix)) { qreal distance = squareDistance(lastSnapPosition, mousePosition); if (distance < maxDistance) { if (distance < minDistances[0]) { minDistances[1] = minDistances[0]; snappedPoints[1] = snappedPoints[0]; startPoints[1] = startPoints[0]; minDistances[0] = distance; snappedPoints[0] = lastSnapPosition; startPoints[0] = matrix.map(last->point()); } else if (distance < minDistances[1]) { minDistances[1] = distance; snappedPoints[1] = lastSnapPosition; startPoints[1] = matrix.map(last->point()); } } } } } m_lines.clear(); // if we have to extension near our mouse position, they might have an intersection // near our mouse position which we want to use as the snapped position if (minDistances[0] < HUGE_VAL && minDistances[1] < HUGE_VAL) { // check if intersection of extension lines is near mouse position KoPathSegment s1(startPoints[0], snappedPoints[0] + snappedPoints[0]-startPoints[0]); KoPathSegment s2(startPoints[1], snappedPoints[1] + snappedPoints[1]-startPoints[1]); QList isects = s1.intersections(s2); if (isects.count() == 1 && squareDistance(isects[0], mousePosition) < maxDistance) { // add both extension lines m_lines.append(QLineF(startPoints[0], isects[0])); m_lines.append(QLineF(startPoints[1], isects[0])); setSnappedPosition(isects[0]); } else { // only add nearest extension line of both uint index = minDistances[0] < minDistances[1] ? 0 : 1; m_lines.append(QLineF(startPoints[index], snappedPoints[index])); setSnappedPosition(snappedPoints[index]); } } else if (minDistances[0] < HUGE_VAL) { m_lines.append(QLineF(startPoints[0], snappedPoints[0])); setSnappedPosition(snappedPoints[0]); } else if (minDistances[1] < HUGE_VAL) { m_lines.append(QLineF(startPoints[1], snappedPoints[1])); setSnappedPosition(snappedPoints[1]); } else { // none of the extension lines is near our mouse position return false; } return true; } QPainterPath ExtensionSnapStrategy::decoration(const KoViewConverter &/*converter*/) const { QPainterPath decoration; foreach (const QLineF &line, m_lines) { decoration.moveTo(line.p1()); decoration.lineTo(line.p2()); } return decoration; } bool ExtensionSnapStrategy::snapToExtension(QPointF &position, KoPathPoint * point, const QTransform &matrix) { Q_ASSERT(point); QPointF direction = extensionDirection(point, matrix); if (direction.isNull()) return false; QPointF extensionStart = matrix.map(point->point()); QPointF extensionStop = matrix.map(point->point()) + direction; float posOnExtension = project(extensionStart, extensionStop, position); if (posOnExtension < 0.0) return false; position = extensionStart + posOnExtension * direction; return true; } qreal ExtensionSnapStrategy::project(const QPointF &lineStart, const QPointF &lineEnd, const QPointF &point) { // This is how the returned value should be used to get the // projectionPoint: ProjectionPoint = lineStart(1-resultingReal) + resultingReal*lineEnd; QPointF diff = lineEnd - lineStart; QPointF relPoint = point - lineStart; qreal diffLength = sqrt(diff.x() * diff.x() + diff.y() * diff.y()); if (diffLength == 0.0) return 0.0; diff /= diffLength; // project mouse position relative to stop position on extension line qreal scalar = relPoint.x() * diff.x() + relPoint.y() * diff.y(); return scalar /= diffLength; } QPointF ExtensionSnapStrategy::extensionDirection(KoPathPoint * point, const QTransform &matrix) { Q_ASSERT(point); KoPathShape * path = point->parent(); KoPathPointIndex index = path->pathPointIndex(point); // check if it is a start point if (point->properties() & KoPathPoint::StartSubpath) { if (point->activeControlPoint2()) { return matrix.map(point->point()) - matrix.map(point->controlPoint2()); } else { KoPathPoint * next = path->pointByIndex(KoPathPointIndex(index.first, index.second + 1)); if (! next){ return QPointF(); } else if (next->activeControlPoint1()) { return matrix.map(point->point()) - matrix.map(next->controlPoint1()); } else { return matrix.map(point->point()) - matrix.map(next->point()); } } } else { if (point->activeControlPoint1()) { return matrix.map(point->point()) - matrix.map(point->controlPoint1()); } else { KoPathPoint * prev = path->pointByIndex(KoPathPointIndex(index.first, index.second - 1)); if (! prev){ return QPointF(); } else if (prev->activeControlPoint2()) { return matrix.map(point->point()) - matrix.map(prev->controlPoint2()); } else { return matrix.map(point->point()) - matrix.map(prev->point()); } } } } IntersectionSnapStrategy::IntersectionSnapStrategy() : KoSnapStrategy(KoSnapGuide::IntersectionSnapping) { } bool IntersectionSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy *proxy, qreal maxSnapDistance) { Q_ASSERT(std::isfinite(maxSnapDistance)); const qreal maxDistance = maxSnapDistance * maxSnapDistance; qreal minDistance = HUGE_VAL; QRectF rect(-maxSnapDistance, -maxSnapDistance, maxSnapDistance, maxSnapDistance); rect.moveCenter(mousePosition); QPointF snappedPoint = mousePosition; QList segments = proxy->segmentsInRect(rect, false); int segmentCount = segments.count(); for (int i = 0; i < segmentCount; ++i) { const KoPathSegment &s1 = segments[i]; for (int j = i + 1; j < segmentCount; ++j) { QList isects = s1.intersections(segments[j]); Q_FOREACH (const QPointF &point, isects) { if (! rect.contains(point)) continue; qreal distance = squareDistance(mousePosition, point); if (distance < maxDistance && distance < minDistance) { snappedPoint = point; minDistance = distance; } } } } setSnappedPosition(snappedPoint); return (minDistance < HUGE_VAL); } QPainterPath IntersectionSnapStrategy::decoration(const KoViewConverter &converter) const { QRectF unzoomedRect = converter.viewToDocument(QRectF(0, 0, 11, 11)); unzoomedRect.moveCenter(snappedPosition()); QPainterPath decoration; decoration.addRect(unzoomedRect); return decoration; } GridSnapStrategy::GridSnapStrategy() : KoSnapStrategy(KoSnapGuide::GridSnapping) { } bool GridSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy *proxy, qreal maxSnapDistance) { Q_ASSERT(std::isfinite(maxSnapDistance)); if (! proxy->canvas()->snapToGrid()) return false; // The 1e-10 here is a workaround for some weird division problem. // 360.00062366 / 2.83465058 gives 127 'exactly' when shown as a qreal, // but when casting into an int, we get 126. In fact it's 127 - 5.64e-15 ! QPointF offset; QSizeF spacing; proxy->canvas()->gridSize(&offset, &spacing); // we want to snap to the nearest grid point, so calculate // the grid rows/columns before and after the points position int col = static_cast((mousePosition.x() - offset.x()) / spacing.width() + 1e-10); int nextCol = col + 1; int row = static_cast((mousePosition.y() - offset.y()) / spacing.height() + 1e-10); int nextRow = row + 1; // now check which grid line has less distance to the point qreal distToCol = qAbs(offset.x() + col * spacing.width() - mousePosition.x()); qreal distToNextCol = qAbs(offset.x() + nextCol * spacing.width() - mousePosition.x()); if (distToCol > distToNextCol) { col = nextCol; distToCol = distToNextCol; } qreal distToRow = qAbs(offset.y() + row * spacing.height() - mousePosition.y()); qreal distToNextRow = qAbs(offset.y() + nextRow * spacing.height() - mousePosition.y()); if (distToRow > distToNextRow) { row = nextRow; distToRow = distToNextRow; } QPointF snappedPoint = mousePosition; bool pointIsSnapped = false; const qreal sqDistance = distToCol * distToCol + distToRow * distToRow; const qreal maxSqDistance = maxSnapDistance * maxSnapDistance; // now check if we are inside the snap distance if (sqDistance < maxSqDistance) { snappedPoint = QPointF(offset.x() + col * spacing.width(), offset.y() + row * spacing.height()); pointIsSnapped = true; } else if (distToRow < maxSnapDistance) { snappedPoint.ry() = offset.y() + row * spacing.height(); pointIsSnapped = true; } else if (distToCol < maxSnapDistance) { snappedPoint.rx() = offset.x() + col * spacing.width(); pointIsSnapped = true; } setSnappedPosition(snappedPoint); return pointIsSnapped; } QPainterPath GridSnapStrategy::decoration(const KoViewConverter &converter) const { QSizeF unzoomedSize = converter.viewToDocument(QSizeF(5, 5)); QPainterPath decoration; decoration.moveTo(snappedPosition() - QPointF(unzoomedSize.width(), 0)); decoration.lineTo(snappedPosition() + QPointF(unzoomedSize.width(), 0)); decoration.moveTo(snappedPosition() - QPointF(0, unzoomedSize.height())); decoration.lineTo(snappedPosition() + QPointF(0, unzoomedSize.height())); return decoration; } BoundingBoxSnapStrategy::BoundingBoxSnapStrategy() : KoSnapStrategy(KoSnapGuide::BoundingBoxSnapping) { } bool BoundingBoxSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy *proxy, qreal maxSnapDistance) { Q_ASSERT(std::isfinite(maxSnapDistance)); const qreal maxDistance = maxSnapDistance * maxSnapDistance; qreal minDistance = HUGE_VAL; QRectF rect(-maxSnapDistance, -maxSnapDistance, maxSnapDistance, maxSnapDistance); rect.moveCenter(mousePosition); QPointF snappedPoint = mousePosition; KoFlake::AnchorPosition pointId[5] = { KoFlake::TopLeft, KoFlake::TopRight, KoFlake::BottomRight, KoFlake::BottomLeft, KoFlake::Center }; QList shapes = proxy->shapesInRect(rect, true); Q_FOREACH (KoShape * shape, shapes) { qreal shapeMinDistance = HUGE_VAL; // first check the corner and center points for (int i = 0; i < 5; ++i) { m_boxPoints[i] = shape->absolutePosition(pointId[i]); qreal d = squareDistance(mousePosition, m_boxPoints[i]); if (d < minDistance && d < maxDistance) { shapeMinDistance = d; minDistance = d; snappedPoint = m_boxPoints[i]; } } // prioritize points over edges if (shapeMinDistance < maxDistance) continue; // now check distances to edges of bounding box for (int i = 0; i < 4; ++i) { QPointF pointOnLine; qreal d = squareDistanceToLine(m_boxPoints[i], m_boxPoints[(i+1)%4], mousePosition, pointOnLine); if (d < minDistance && d < maxDistance) { minDistance = d; snappedPoint = pointOnLine; } } } setSnappedPosition(snappedPoint); return (minDistance < maxDistance); } qreal BoundingBoxSnapStrategy::squareDistanceToLine(const QPointF &lineA, const QPointF &lineB, const QPointF &point, QPointF &pointOnLine) { QPointF diff = lineB - lineA; if(lineA == lineB) return HUGE_VAL; const qreal diffLength = sqrt(diff.x() * diff.x() + diff.y() * diff.y()); // project mouse position relative to start position on line const qreal scalar = KoSnapStrategy::scalarProduct(point - lineA, diff / diffLength); if (scalar < 0.0 || scalar > diffLength) return HUGE_VAL; // calculate vector between relative mouse position and projected mouse position pointOnLine = lineA + scalar / diffLength * diff; QPointF distVec = pointOnLine - point; return distVec.x()*distVec.x() + distVec.y()*distVec.y(); } QPainterPath BoundingBoxSnapStrategy::decoration(const KoViewConverter &converter) const { QSizeF unzoomedSize = converter.viewToDocument(QSizeF(5, 5)); QPainterPath decoration; decoration.moveTo(snappedPosition() - QPointF(unzoomedSize.width(), unzoomedSize.height())); decoration.lineTo(snappedPosition() + QPointF(unzoomedSize.width(), unzoomedSize.height())); decoration.moveTo(snappedPosition() - QPointF(unzoomedSize.width(), -unzoomedSize.height())); decoration.lineTo(snappedPosition() + QPointF(unzoomedSize.width(), -unzoomedSize.height())); return decoration; } PixelSnapStrategy::PixelSnapStrategy() : KoSnapStrategy(KoSnapGuide::PixelSnapping) { } bool PixelSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy *proxy, qreal maxSnapDistance) { Q_ASSERT(std::isfinite(maxSnapDistance)); Q_UNUSED(proxy); - int col = static_cast(mousePosition.x()); - int row = static_cast(mousePosition.y()); - - qreal distToCol = qAbs(col - mousePosition.x()); - qreal distToNextCol = qAbs((col+1) - mousePosition.x()); - - if (distToCol > distToNextCol) { - col += 1; - distToCol = distToNextCol; - } - - qreal distToRow = qAbs(row - mousePosition.y()); - qreal distToNextRow = qAbs((row+1)- mousePosition.y()); - if (distToRow > distToNextRow) { - row += 1; - distToRow = distToNextRow; - } - - QPointF snappedPoint = mousePosition; - - bool pointIsSnapped = false; - - const qreal sqDistance = distToCol * distToCol + distToRow * distToRow; - const qreal maxSqDistance = maxSnapDistance * maxSnapDistance; - // now check if we are inside the snap distance - if (sqDistance < maxSqDistance) { - snappedPoint = QPointF(col, row); - pointIsSnapped = true; - } else if (distToRow < maxSnapDistance) { - snappedPoint.ry() = row; - pointIsSnapped = true; - } else if (distToCol < maxSnapDistance) { - snappedPoint.rx() = col; - pointIsSnapped = true; - } - - setSnappedPosition(snappedPoint); - - return pointIsSnapped; + setSnappedPosition(mousePosition.toPoint()); + return true; } QPainterPath PixelSnapStrategy::decoration(const KoViewConverter &converter) const { QSizeF unzoomedSize = converter.viewToDocument(QSizeF(5, 5)); QPainterPath decoration; decoration.moveTo(snappedPosition() - QPointF(unzoomedSize.width(), 0)); decoration.lineTo(snappedPosition() + QPointF(unzoomedSize.width(), 0)); decoration.moveTo(snappedPosition() - QPointF(0, unzoomedSize.height())); decoration.lineTo(snappedPosition() + QPointF(0, unzoomedSize.height())); return decoration; } // KoGuidesData has been moved into Krita. Please port this class! // LineGuideSnapStrategy::LineGuideSnapStrategy() // : KoSnapStrategy(KoSnapGuide::GuideLineSnapping) // { // } // bool LineGuideSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance) // { // Q_ASSERT(std::isfinite(maxSnapDistance)); // KoGuidesData * guidesData = proxy->canvas()->guidesData(); // if (!guidesData || !guidesData->showGuideLines()) // return false; // QPointF snappedPoint = mousePosition; // m_orientation = 0; // qreal minHorzDistance = maxSnapDistance; // Q_FOREACH (qreal guidePos, guidesData->horizontalGuideLines()) { // qreal distance = qAbs(guidePos - mousePosition.y()); // if (distance < minHorzDistance) { // snappedPoint.setY(guidePos); // minHorzDistance = distance; // m_orientation |= Qt::Horizontal; // } // } // qreal minVertSnapDistance = maxSnapDistance; // Q_FOREACH (qreal guidePos, guidesData->verticalGuideLines()) { // qreal distance = qAbs(guidePos - mousePosition.x()); // if (distance < minVertSnapDistance) { // snappedPoint.setX(guidePos); // minVertSnapDistance = distance; // m_orientation |= Qt::Vertical; // } // } // setSnappedPosition(snappedPoint); // return (minHorzDistance < maxSnapDistance || minVertSnapDistance < maxSnapDistance); // } // QPainterPath LineGuideSnapStrategy::decoration(const KoViewConverter &converter) const // { // QSizeF unzoomedSize = converter.viewToDocument(QSizeF(5, 5)); // Q_ASSERT(unzoomedSize.isValid()); // QPainterPath decoration; // if (m_orientation & Qt::Horizontal) { // decoration.moveTo(snappedPosition() - QPointF(unzoomedSize.width(), 0)); // decoration.lineTo(snappedPosition() + QPointF(unzoomedSize.width(), 0)); // } // if (m_orientation & Qt::Vertical) { // decoration.moveTo(snappedPosition() - QPointF(0, unzoomedSize.height())); // decoration.lineTo(snappedPosition() + QPointF(0, unzoomedSize.height())); // } // return decoration; // }