File indexing completed on 2024-05-12 15:56:50

0001 /* This file is part of the KDE project
0002  * SPDX-FileCopyrightText: 2008-2009 Jan Hambrecht <jaham@gmx.net>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 
0007 #include "KoSnapProxy.h"
0008 #include "KoSnapGuide.h"
0009 #include "KoCanvasBase.h"
0010 #include "KoShapeManager.h"
0011 #include "KoPathShape.h"
0012 #include "KoPathPoint.h"
0013 #include <KoSnapData.h>
0014 #include <KoShapeLayer.h>
0015 
0016 KoSnapProxy::KoSnapProxy(KoSnapGuide * snapGuide)
0017         : m_snapGuide(snapGuide)
0018 {
0019 }
0020 
0021 QList<QPointF> KoSnapProxy::pointsInRect(const QRectF &rect, bool omitEditedShape)
0022 {
0023     QList<QPointF> points;
0024     QList<KoShape*> shapes = shapesInRect(rect, omitEditedShape);
0025     Q_FOREACH (KoShape * shape, shapes) {
0026         Q_FOREACH (const QPointF & point, pointsFromShape(shape)) {
0027             if (rect.contains(point))
0028                 points.append(point);
0029         }
0030     }
0031 
0032     return points;
0033 }
0034 
0035 QList<KoShape*> KoSnapProxy::shapesInRect(const QRectF &rect, bool omitEditedShape)
0036 {
0037     QList<KoShape*> shapes = m_snapGuide->canvas()->shapeManager()->shapesAt(rect);
0038     Q_FOREACH (KoShape * shape, m_snapGuide->ignoredShapes()) {
0039         const int index = shapes.indexOf(shape);
0040         if (index >= 0) {
0041             shapes.removeAt(index);
0042         }
0043     }
0044 
0045 
0046     if (omitEditedShape) {
0047         Q_FOREACH (KoPathPoint *point, m_snapGuide->ignoredPathPoints()) {
0048             const int index = shapes.indexOf(point->parent());
0049             if (index >= 0) {
0050                 shapes.removeAt(index);
0051             }
0052         }
0053     }
0054 
0055     if (!omitEditedShape && m_snapGuide->additionalEditedShape()) {
0056         QRectF bound = m_snapGuide->additionalEditedShape()->boundingRect();
0057         if (rect.intersects(bound) || rect.contains(bound))
0058             shapes.append(m_snapGuide->additionalEditedShape());
0059     }
0060     return shapes;
0061 }
0062 
0063 QList<QPointF> KoSnapProxy::pointsFromShape(KoShape * shape)
0064 {
0065     QList<QPointF> snapPoints;
0066     // no snapping to hidden shapes
0067     if (! shape->isVisible())
0068         return snapPoints;
0069 
0070     // return the special snap points of the shape
0071     snapPoints += shape->snapData().snapPoints();
0072 
0073     KoPathShape * path = dynamic_cast<KoPathShape*>(shape);
0074     if (path) {
0075         QTransform m = path->absoluteTransformation();
0076 
0077         QList<KoPathPoint*> ignoredPoints = m_snapGuide->ignoredPathPoints();
0078 
0079         int subpathCount = path->subpathCount();
0080         for (int subpathIndex = 0; subpathIndex < subpathCount; ++subpathIndex) {
0081             int pointCount = path->subpathPointCount(subpathIndex);
0082             for (int pointIndex = 0; pointIndex < pointCount; ++pointIndex) {
0083                 KoPathPoint * p = path->pointByIndex(KoPathPointIndex(subpathIndex, pointIndex));
0084                 if (! p || ignoredPoints.contains(p))
0085                     continue;
0086 
0087                 snapPoints.append(m.map(p->point()));
0088             }
0089         }
0090     }
0091     else
0092     {
0093         // add the bounding box corners as default snap points
0094         QRectF bbox = shape->boundingRect();
0095         snapPoints.append(bbox.topLeft());
0096         snapPoints.append(bbox.topRight());
0097         snapPoints.append(bbox.bottomRight());
0098         snapPoints.append(bbox.bottomLeft());
0099     }
0100 
0101     return snapPoints;
0102 }
0103 
0104 QList<KoPathSegment> KoSnapProxy::segmentsInRect(const QRectF &rect, bool omitEditedShape)
0105 {
0106     
0107     QList<KoShape*> shapes = shapesInRect(rect, omitEditedShape);
0108     QList<KoPathPoint*> ignoredPoints = m_snapGuide->ignoredPathPoints();
0109 
0110     QList<KoPathSegment> segments;
0111     Q_FOREACH (KoShape * shape, shapes) {
0112         QList<KoPathSegment> shapeSegments;
0113         QRectF rectOnShape = shape->documentToShape(rect);
0114         KoPathShape * path = dynamic_cast<KoPathShape*>(shape);
0115         if (path) {
0116             shapeSegments = path->segmentsAt(rectOnShape);
0117         } else {
0118             Q_FOREACH (const KoPathSegment & s, shape->snapData().snapSegments()) {
0119                 QRectF controlRect = s.controlPointRect();
0120                 if (! rect.intersects(controlRect) && ! controlRect.contains(rect))
0121                     continue;
0122                 QRectF bound = s.boundingRect();
0123                 if (! rect.intersects(bound) && ! bound.contains(rect))
0124                     continue;
0125                 shapeSegments.append(s);
0126             }
0127         }
0128 
0129         QTransform m = shape->absoluteTransformation();
0130         // transform segments to document coordinates
0131         Q_FOREACH (const KoPathSegment & s, shapeSegments) {
0132             if (ignoredPoints.contains(s.first()) || ignoredPoints.contains(s.second()))
0133                 continue;
0134             segments.append(s.mapped(m));
0135         }
0136     }
0137     return segments;
0138 }
0139 
0140 QList<KoShape*> KoSnapProxy::shapes(bool omitEditedShape)
0141 {
0142     QList<KoShape*> allShapes = m_snapGuide->canvas()->shapeManager()->shapes();
0143     QList<KoShape*> filteredShapes;
0144     QList<KoShape*> ignoredShapes = m_snapGuide->ignoredShapes();
0145 
0146     // filter all hidden and ignored shapes
0147     Q_FOREACH (KoShape * shape, allShapes) {
0148         if (shape->isVisible() &&
0149             !ignoredShapes.contains(shape) &&
0150             !dynamic_cast<KoShapeLayer*>(shape)) {
0151 
0152             filteredShapes.append(shape);
0153         }
0154     }
0155 
0156     if (omitEditedShape) {
0157         Q_FOREACH (KoPathPoint *point, m_snapGuide->ignoredPathPoints()) {
0158             const int index = filteredShapes.indexOf(point->parent());
0159             if (index >= 0) {
0160                 filteredShapes.removeAt(index);
0161             }
0162         }
0163     }
0164 
0165     if (!omitEditedShape && m_snapGuide->additionalEditedShape()) {
0166         filteredShapes.append(m_snapGuide->additionalEditedShape());
0167     }
0168 
0169     return filteredShapes;
0170 }
0171 
0172 KoCanvasBase * KoSnapProxy::canvas()
0173 {
0174     return m_snapGuide->canvas();
0175 }
0176