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