Krita Source Code Documentation
Loading...
Searching...
No Matches
CutThroughShapeStrategy Class Reference

#include <CutThroughShapeStrategy.h>

+ Inheritance diagram for CutThroughShapeStrategy:

Public Member Functions

KUndo2CommandcreateCommand () override
 
 CutThroughShapeStrategy (KoToolBase *tool, KoSelection *selection, const QList< KoShape * > &allShapes, QPointF startPoint, const GutterWidthsConfig &width)
 
void finishInteraction (Qt::KeyboardModifiers modifiers) override
 
void handleMouseMove (const QPointF &mouseLocation, Qt::KeyboardModifiers modifiers) override
 
void paint (QPainter &painter, const KoViewConverter &converter, const KoColorDisplayRendererInterface *displayRendererInterface) override
 
 ~CutThroughShapeStrategy () override
 
- Public Member Functions inherited from KoInteractionStrategy
virtual void cancelInteraction ()
 
 KoInteractionStrategy (KoToolBase *parent)
 constructor
 
KoToolBasetool () const
 
virtual ~KoInteractionStrategy ()
 Destructor.
 

Private Member Functions

qreal calculateLineAngle (QPointF start, QPointF end)
 
qreal gutterWidthInDocumentCoordinates (qreal lineAngle)
 

Static Private Member Functions

static void initializeGapShapes (QRectF outlineRect, QLineF leftLine, QLineF rightLine, QPainterPath &outLeft, QPainterPath &outRight, QRectF &outGapLineRect, QPolygonF &outGapLinePolygon)
 
static void initializeOutlineObjects (const QTransform &booleanWorkaroundTransform, QList< KoShape * > allShapes, QList< QPainterPath > &outSrcOutlines, QRectF &outOutlineRect)
 
static bool willShapeBeCutGeneral (KoShape *referenceShape, const QPainterPath &srcOutline, bool checkGapLineRect, const QRectF &gapLineRect)
 
static bool willShapeBeCutPrecise (const QPainterPath &srcOutline, const QLineF gapLine, const QLineF &leftLine, const QLineF &rightLine, const QPolygonF &gapLinePolygon)
 

Private Attributes

QList< KoShape * > m_allShapes
 
QPointF m_endPoint = QPointF()
 
QRectF m_previousLineDirtyRect = QRectF()
 
QList< KoShape * > m_selectedShapes
 
QPointF m_startPoint = QPointF()
 
GutterWidthsConfig m_width
 

Friends

class CutThroughShapeStrategyTest
 

Additional Inherited Members

- Protected Member Functions inherited from KoInteractionStrategy
uint decorationThickness () const
 
uint grabSensitivity () const
 Convenience function to get the global grab sensitivity.
 
uint handleRadius () const
 Convenience function to get the global handle radius.
 
 KoInteractionStrategy (KoInteractionStrategyPrivate &)
 constructor
 
- Protected Attributes inherited from KoInteractionStrategy
KoInteractionStrategyPrivated_ptr
 

Detailed Description

Definition at line 23 of file CutThroughShapeStrategy.h.

Constructor & Destructor Documentation

◆ CutThroughShapeStrategy()

CutThroughShapeStrategy::CutThroughShapeStrategy ( KoToolBase * tool,
KoSelection * selection,
const QList< KoShape * > & allShapes,
QPointF startPoint,
const GutterWidthsConfig & width )

Definition at line 31 of file CutThroughShapeStrategy.cpp.

33 , m_startPoint(startPoint)
34 , m_endPoint(startPoint)
35 , m_width(width)
36{
38 m_allShapes = shapes;
39}
QList< KoShape * > m_selectedShapes
KoInteractionStrategy(KoToolBase *parent)
constructor
const QList< KoShape * > selectedEditableShapes() const

References m_allShapes, m_selectedShapes, and KoSelection::selectedEditableShapes().

◆ ~CutThroughShapeStrategy()

CutThroughShapeStrategy::~CutThroughShapeStrategy ( )
override

Definition at line 41 of file CutThroughShapeStrategy.cpp.

42{
43
44}

Member Function Documentation

◆ calculateLineAngle()

qreal CutThroughShapeStrategy::calculateLineAngle ( QPointF start,
QPointF end )
private

Definition at line 412 of file CutThroughShapeStrategy.cpp.

413{
414 QPointF vec = end - start;
415 qreal angleDegrees = KisAlgebra2D::wrapValue(kisRadiansToDegrees(std::atan2(vec.y(), vec.x())), 0.0, 360.0);
416 return angleDegrees;
417}
T kisRadiansToDegrees(T radians)
Definition kis_global.h:181
T wrapValue(T value, T wrapBounds)

References kisRadiansToDegrees(), and KisAlgebra2D::wrapValue().

◆ createCommand()

KUndo2Command * CutThroughShapeStrategy::createCommand ( )
overridevirtual

For interactions that are undo-able this method should be implemented to return such a command. Implementations should return 0 otherwise.

Returns
a command, or 0.

Implements KoInteractionStrategy.

Definition at line 46 of file CutThroughShapeStrategy.cpp.

47{
48 // TODO: undoing
49 return 0;
50}

◆ finishInteraction()

void CutThroughShapeStrategy::finishInteraction ( Qt::KeyboardModifiers modifiers)
overridevirtual

Override to make final changes to the data on the end of an interaction.

Implements KoInteractionStrategy.

Definition at line 189 of file CutThroughShapeStrategy.cpp.

190{
192
193
194 KisCanvas2 *kisCanvas = static_cast<KisCanvas2 *>(tool()->canvas());
196 const QTransform booleanWorkaroundTransform = KritaUtils::pathShapeBooleanSpaceWorkaround(kisCanvas->image());
197
198 QList<QPainterPath> srcOutlines;
199 QRectF outlineRect;
200
201 if (m_allShapes.length() == 0) {
202 qCritical() << "No shapes are available";
203 return;
204 }
205
206 initializeOutlineObjects(booleanWorkaroundTransform, m_allShapes, srcOutlines, outlineRect);
207
208
209
210 if (outlineRect.isEmpty()) {
211 //qCritical() << "The outline rect is empty";
212 return;
213 }
214
215
216 QLineF gapLine = QLineF(m_startPoint, m_endPoint);
217 qreal eps = 0.0000001;
218 if (gapLine.length() < eps) {
219 return;
220 }
221
223
224 QList<QLineF> gapLines = KisAlgebra2D::getParallelLines(gapLine, gutterWidth/2);
225
226 gapLine = booleanWorkaroundTransform.map(gapLine);
227 gapLines[0] = booleanWorkaroundTransform.map(gapLines[0]);
228 gapLines[1] = booleanWorkaroundTransform.map(gapLines[1]);
229
230 QLineF leftLine = gapLines[0];
231 QLineF rightLine = gapLines[1];
232
233
234 if (leftLine.length() == 0 || rightLine.length() == 0) {
235 KIS_SAFE_ASSERT_RECOVER_RETURN(gapLine.length() != 0 && gapLines[0].length() != 0 && gapLines[1].length() != 0 && "Original gap lines shouldn't be empty at this point");
236 return;
237 }
238
239 // -------------
240
241 QPainterPath left, right;
242
243 QRectF gapLineRect;
244 QPolygonF gapLinePolygon;
245 initializeGapShapes(outlineRect, leftLine, rightLine, left, right, gapLineRect, gapLinePolygon);
246
247
248 bool checkGapLineRect = !gapLineRect.isEmpty();
249
250 QList<KoShape*> newSelectedShapes;
251 QList<KoShape*> shapesToRemove;
252 int affectedShapes = 0;
253 QTransform booleanWorkaroundTransformInverted = booleanWorkaroundTransform.inverted();
254
255
256 std::unique_ptr<KUndo2Command> cmd = std::unique_ptr<KUndo2Command>(new KUndo2Command(kundo2_i18n("Knife tool: cut through shapes")));
257 new KoKeepShapesSelectedCommand(m_selectedShapes, {}, kisCanvas->selectedShapesProxy(), false, cmd.get());
258
259
260 for (int i = 0; i < srcOutlines.size(); i++) {
261
262 KoShape* referenceShape = m_allShapes[i];
263 bool wasSelected = m_selectedShapes.contains(referenceShape);
264
265 bool skipThisShape = !willShapeBeCutGeneral(referenceShape, srcOutlines[i], checkGapLineRect, gapLineRect);
266 skipThisShape = skipThisShape || !willShapeBeCutPrecise(srcOutlines[i], gapLine, leftLine, rightLine, gapLinePolygon);
267
268 if (skipThisShape) {
269 if (wasSelected) {
270 newSelectedShapes << referenceShape;
271 }
272 continue;
273 }
274
275 affectedShapes++;
276
277
278 QPainterPath leftPath = srcOutlines[i] & left;
279 QPainterPath rightPath = srcOutlines[i] & right;
280
281 QList<QPainterPath> bothSides;
282 bothSides << leftPath << rightPath;
283
284
285 Q_FOREACH(QPainterPath path, bothSides) {
286 if (path.isEmpty()) {
287 continue;
288 }
289
290 // comment copied from another place:
291 // there is a bug in Qt, sometimes it leaves the resulting
292 // outline open, so just close it explicitly.
293 path.closeSubpath();
294 // this is needed because Qt linearize curves; this allows for a
295 // "sane" linearization instead of a very blocky appearance
296 path = booleanWorkaroundTransformInverted.map(path);
297 std::unique_ptr<KoPathShape> shape = std::unique_ptr<KoPathShape>(KoPathShape::createShapeFromPainterPath(path));
298 shape->closeMerge();
299
300 if (shape->boundingRect().isEmpty()) {
301 continue;
302 }
303
304 shape->setBackground(referenceShape->background());
305 shape->setStroke(referenceShape->stroke());
306 shape->setZIndex(referenceShape->zIndex());
307
308 KoShapeContainer *parent = referenceShape->parent();
309
310 if (wasSelected) {
311 newSelectedShapes << shape.get();
312 }
313
314 tool()->canvas()->shapeController()->addShapeDirect(shape.release(), parent, cmd.get());
315
316 }
317
318 // that happens no matter if there was any non-empty shape
319 // because if there is none, maybe they just were underneath the gap
320 shapesToRemove << m_allShapes[i];
321
322 }
323
324 if (affectedShapes > 0) {
325 tool()->canvas()->shapeController()->removeShapes(shapesToRemove, cmd.get());
326 new KoKeepShapesSelectedCommand({}, newSelectedShapes, tool()->canvas()->selectedShapesProxy(), true, cmd.get());
327 tool()->canvas()->addCommand(cmd.release());
328 }
329
330
331
332}
static void initializeGapShapes(QRectF outlineRect, QLineF leftLine, QLineF rightLine, QPainterPath &outLeft, QPainterPath &outRight, QRectF &outGapLineRect, QPolygonF &outGapLinePolygon)
qreal calculateLineAngle(QPointF start, QPointF end)
static void initializeOutlineObjects(const QTransform &booleanWorkaroundTransform, QList< KoShape * > allShapes, QList< QPainterPath > &outSrcOutlines, QRectF &outOutlineRect)
static bool willShapeBeCutPrecise(const QPainterPath &srcOutline, const QLineF gapLine, const QLineF &leftLine, const QLineF &rightLine, const QPolygonF &gapLinePolygon)
static bool willShapeBeCutGeneral(KoShape *referenceShape, const QPainterPath &srcOutline, bool checkGapLineRect, const QRectF &gapLineRect)
qreal gutterWidthInDocumentCoordinates(qreal lineAngle)
KisSelectedShapesProxy selectedShapesProxy
KisImageWSP image() const
QPointer< KoShapeController > shapeController
virtual void updateCanvas(const QRectF &rc)=0
virtual void addCommand(KUndo2Command *command)=0
virtual KoSelectedShapesProxy * selectedShapesProxy() const =0
selectedShapesProxy() is a special interface for keeping a persistent connections to selectionChanged...
static KoPathShape * createShapeFromPainterPath(const QPainterPath &path)
Creates path shape from given QPainterPath.
virtual KoShapeStrokeModelSP stroke() const
Definition KoShape.cpp:885
KoShapeContainer * parent() const
Definition KoShape.cpp:857
virtual QSharedPointer< KoShapeBackground > background() const
Definition KoShape.cpp:754
qint16 zIndex() const
Definition KoShape.cpp:524
KoCanvasBase * canvas() const
Returns the canvas the tool is working on.
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
const qreal eps
KUndo2MagicString kundo2_i18n(const char *text)
QList< QLineF > getParallelLines(const QLineF &line, const qreal distance)
ChildIterator< value_type, is_const > parent(const ChildIterator< value_type, is_const > &it)
Definition KisForest.h:327
QTransform pathShapeBooleanSpaceWorkaround(KisImageSP image)

References KoCanvasBase::addCommand(), KoShape::background(), calculateLineAngle(), KoToolBase::canvas(), KoPathShape::createShapeFromPainterPath(), eps, KisAlgebra2D::getParallelLines(), gutterWidthInDocumentCoordinates(), KisCanvas2::image(), initializeGapShapes(), initializeOutlineObjects(), KIS_SAFE_ASSERT_RECOVER_RETURN, kundo2_i18n(), m_allShapes, m_endPoint, m_previousLineDirtyRect, m_selectedShapes, m_startPoint, KoShape::parent(), KritaUtils::pathShapeBooleanSpaceWorkaround(), KoCanvasBase::selectedShapesProxy(), KisCanvas2::selectedShapesProxy, KoCanvasBase::shapeController, KoShape::stroke(), KoInteractionStrategy::tool(), KoCanvasBase::updateCanvas(), willShapeBeCutGeneral(), willShapeBeCutPrecise(), and KoShape::zIndex().

◆ gutterWidthInDocumentCoordinates()

qreal CutThroughShapeStrategy::gutterWidthInDocumentCoordinates ( qreal lineAngle)
private

Definition at line 403 of file CutThroughShapeStrategy.cpp.

404{
405 KisCanvas2 *kisCanvas = static_cast<KisCanvas2 *>(tool()->canvas());
407 QLineF helperGapWidthLine = QLineF(QPointF(0, 0), QPointF(0, m_width.widthForAngleInPixels(lineAngle)));
408 QLineF helperGapWidthLineTransformed = kisCanvas->coordinatesConverter()->imageToDocument(helperGapWidthLine);
409 return helperGapWidthLineTransformed.length();
410}
qreal widthForAngleInPixels(qreal lineAngleDegrees)
KisCoordinatesConverter * coordinatesConverter
_Private::Traits< T >::Result imageToDocument(const T &obj) const
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129

References KoToolBase::canvas(), KisCanvas2::coordinatesConverter, KisCoordinatesConverter::imageToDocument(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, m_width, KoInteractionStrategy::tool(), and GutterWidthsConfig::widthForAngleInPixels().

◆ handleMouseMove()

void CutThroughShapeStrategy::handleMouseMove ( const QPointF & mouseLocation,
Qt::KeyboardModifiers modifiers )
overridevirtual

Extending classes should implement this method to update the selectedShapes based on the new mouse position.

Parameters
mouseLocationthe new location in pt
modifiersOR-ed set of keys pressed.

Implements KoInteractionStrategy.

Definition at line 74 of file CutThroughShapeStrategy.cpp.

75{
76 m_endPoint = snapEndPoint(m_startPoint, mouseLocation, modifiers);
77 QRectF dirtyRect;
80 dirtyRect = kisGrowRect(dirtyRect, gutterWidthInDocumentCoordinates(calculateLineAngle(m_startPoint, m_endPoint))); // twice as much as it should need to account for lines showing the effect
81
82 QRectF accumulatedWithPrevious = m_previousLineDirtyRect | dirtyRect;
83
84 if (tool() && tool()->canvas()) {
85 tool()->canvas()->updateCanvas(accumulatedWithPrevious);
86 }
87 m_previousLineDirtyRect = dirtyRect;
88
89}
QPointF snapEndPoint(const QPointF &startPoint, const QPointF &mouseLocation, Qt::KeyboardModifiers modifiers)
T kisGrowRect(const T &rect, U offset)
Definition kis_global.h:186
void accumulateBounds(const Point &pt, Rect *bounds)

References KisAlgebra2D::accumulateBounds(), calculateLineAngle(), KoToolBase::canvas(), gutterWidthInDocumentCoordinates(), kisGrowRect(), m_endPoint, m_previousLineDirtyRect, m_startPoint, snapEndPoint(), KoInteractionStrategy::tool(), and KoCanvasBase::updateCanvas().

◆ initializeGapShapes()

void CutThroughShapeStrategy::initializeGapShapes ( QRectF outlineRect,
QLineF leftLine,
QLineF rightLine,
QPainterPath & outLeft,
QPainterPath & outRight,
QRectF & outGapLineRect,
QPolygonF & outGapLinePolygon )
staticprivate

Definition at line 165 of file CutThroughShapeStrategy.cpp.

167{
168
169
170 QRect outlineRectBiggerInt = kisGrowRect(outlineRect, 10).toRect();
171 QLineF leftLineLong = leftLine;
172 QLineF rightLineLong = rightLine;
173
174
175 KisAlgebra2D::cropLineToRect(leftLineLong, outlineRectBiggerInt, true, true);
176 KisAlgebra2D::cropLineToRect(rightLineLong, outlineRectBiggerInt, true, true);
177
178
179 QList<QPainterPath> paths = KisAlgebra2D::getPathsFromRectangleCutThrough(QRectF(outlineRectBiggerInt), leftLineLong, rightLineLong);
180 outLeft = paths[0];
181 outRight = paths[1];
182
183 outGapLineRect = KisAlgebra2D::createRectFromCorners(leftLine) | KisAlgebra2D::createRectFromCorners(rightLine); // will not be empty if the gutterWidth > 0
184
185 outGapLinePolygon = QPolygonF({leftLine.p1(), leftLine.p2(), rightLine.p2(), rightLine.p1(), leftLine.p1()});
186
187}
QList< QPainterPath > getPathsFromRectangleCutThrough(const QRectF &rect, const QLineF &leftLine, const QLineF &rightLine)
getPathsFromRectangleCutThrough get paths defining both sides of a rectangle cut through using two (s...
void cropLineToRect(QLineF &line, const QRect rect, bool extendFirst, bool extendSecond)
Crop line to rect; if it doesn't intersect, just return an empty line (QLineF()).
PointTypeTraits< Point >::rect_type createRectFromCorners(Point corner1, Point corner2)

References KisAlgebra2D::createRectFromCorners(), KisAlgebra2D::cropLineToRect(), KisAlgebra2D::getPathsFromRectangleCutThrough(), and kisGrowRect().

◆ initializeOutlineObjects()

void CutThroughShapeStrategy::initializeOutlineObjects ( const QTransform & booleanWorkaroundTransform,
QList< KoShape * > allShapes,
QList< QPainterPath > & outSrcOutlines,
QRectF & outOutlineRect )
staticprivate

Definition at line 151 of file CutThroughShapeStrategy.cpp.

152{
153 Q_FOREACH (KoShape *shape, allShapes) {
154
155 QPainterPath outlineHere =
156 booleanWorkaroundTransform.map(
157 shape->absoluteTransformation().map(
158 shape->outline()));
159
160 outSrcOutlines << outlineHere;
161 outOutlineRect |= outlineHere.boundingRect();
162 }
163}
virtual QPainterPath outline() const
Definition KoShape.cpp:554
QTransform absoluteTransformation() const
Definition KoShape.cpp:330

References KoShape::absoluteTransformation(), and KoShape::outline().

◆ paint()

void CutThroughShapeStrategy::paint ( QPainter & painter,
const KoViewConverter & converter,
const KoColorDisplayRendererInterface * displayRendererInterface )
overridevirtual

Reimplement this if the action needs to draw a "blob" on the canvas; that is, a transient decoration like a rubber band.

Reimplemented from KoInteractionStrategy.

Definition at line 334 of file CutThroughShapeStrategy.cpp.

335{
336 painter.save();
337
338 KoColor c;
339 c.fromQColor(Qt::darkGray);
340 QColor semitransparentGray = displayRendererInterface->convertColorToDisplayColorSpace(c);
341 semitransparentGray.setAlphaF(0.6);
342 QPen pen = QPen(QBrush(semitransparentGray), 2);
343 painter.setPen(pen);
344
345 painter.setRenderHint(QPainter::RenderHint::Antialiasing, true);
346
348
349 QLineF gutterCenterLine = QLineF(m_startPoint, m_endPoint);
350 gutterCenterLine = converter.documentToView().map(gutterCenterLine);
351 QLineF gutterWidthHelperLine = QLineF(QPointF(0, 0), QPointF(gutterWidth, 0));
352 gutterWidthHelperLine = converter.documentToView().map(gutterWidthHelperLine);
353
354 gutterWidth = gutterWidthHelperLine.length();
355
356 QList<QLineF> gutterLines = KisAlgebra2D::getParallelLines(gutterCenterLine, gutterWidth/2);
357
358 QLineF gutterLine1 = gutterLines.length() > 0 ? gutterLines[0] : gutterCenterLine;
359 QLineF gutterLine2 = gutterLines.length() > 1 ? gutterLines[1] : gutterCenterLine;
360
361
362 painter.drawLine(gutterLine1);
363 painter.drawLine(gutterLine2);
364
365 QRectF arcRect1 = QRectF(gutterCenterLine.p1() - QPointF(gutterWidth/2, gutterWidth/2), gutterCenterLine.p1() + QPointF(gutterWidth/2, gutterWidth/2));
366 QRectF arcRect2 = QRectF(gutterCenterLine.p2() - QPointF(gutterWidth/2, gutterWidth/2), gutterCenterLine.p2() + QPointF(gutterWidth/2, gutterWidth/2));
367
368 int qtAngleFactor = 16;
369 int qtHalfCircle = qtAngleFactor*180;
370
371 painter.drawArc(arcRect1, -qtAngleFactor*kisRadiansToDegrees(KisAlgebra2D::directionBetweenPoints(gutterCenterLine.p1(), gutterLine1.p1(), 0)), qtHalfCircle);
372 painter.drawArc(arcRect2, -qtAngleFactor*kisRadiansToDegrees(KisAlgebra2D::directionBetweenPoints(gutterCenterLine.p2(), gutterLine1.p2(), 0)), -qtHalfCircle);
373
374
375 int xLength = 3;
376 qreal xLengthEllipse = 2*qSqrt(2);
377
378 if (false) { // drawing X
379 painter.drawLine({QLineF(gutterCenterLine.p1() - QPointF(xLength, xLength), gutterCenterLine.p1() + QPointF(xLength, xLength))});
380 painter.drawLine({QLineF(gutterCenterLine.p2() - QPointF(xLength, xLength), gutterCenterLine.p2() + QPointF(xLength, xLength))});
381
382 painter.drawLine({QLineF(gutterCenterLine.p1() - QPointF(xLength, -xLength), gutterCenterLine.p1() + QPointF(xLength, -xLength))});
383 painter.drawLine({QLineF(gutterCenterLine.p2() - QPointF(xLength, -xLength), gutterCenterLine.p2() + QPointF(xLength, -xLength))});
384 }
385
386 // ellipse at the both ends of the gutter center line
387 painter.drawEllipse(gutterCenterLine.p1(), xLengthEllipse, xLengthEllipse);
388 painter.drawEllipse(gutterCenterLine.p2(), xLengthEllipse, xLengthEllipse);
389
390
391
392 pen.setWidth(1);
393 semitransparentGray.setAlphaF(0.2);
394 pen.setColor(semitransparentGray);
395
396 painter.setPen(pen);
397
398 painter.drawLine(gutterCenterLine);
399
400 painter.restore();
401}
virtual QColor convertColorToDisplayColorSpace(const KoColor color) const =0
convertColorToDisplayColorSpace
void fromQColor(const QColor &c)
Convenient function for converting from a QColor.
Definition KoColor.cpp:213
virtual QPointF documentToView(const QPointF &documentPoint) const
qreal directionBetweenPoints(const QPointF &p1, const QPointF &p2, qreal defaultAngle)

References calculateLineAngle(), KoColorDisplayRendererInterface::convertColorToDisplayColorSpace(), KisAlgebra2D::directionBetweenPoints(), KoViewConverter::documentToView(), KoColor::fromQColor(), KisAlgebra2D::getParallelLines(), gutterWidthInDocumentCoordinates(), kisRadiansToDegrees(), m_endPoint, and m_startPoint.

◆ willShapeBeCutGeneral()

bool CutThroughShapeStrategy::willShapeBeCutGeneral ( KoShape * referenceShape,
const QPainterPath & srcOutline,
bool checkGapLineRect,
const QRectF & gapLineRect )
staticprivate

Definition at line 92 of file CutThroughShapeStrategy.cpp.

93{
94 if (dynamic_cast<KoSvgTextShape*>(referenceShape)) {
95 // skip all text
96 return false;
97 }
98
99
100 if (checkGapLineRect && (srcOutline.boundingRect() & gapLineRect).isEmpty()) {
101 // the gap lines can't cross the shape since their bounding rects don't cross it
102 return false;
103 }
104
105 return true;
106}

◆ willShapeBeCutPrecise()

bool CutThroughShapeStrategy::willShapeBeCutPrecise ( const QPainterPath & srcOutline,
const QLineF gapLine,
const QLineF & leftLine,
const QLineF & rightLine,
const QPolygonF & gapLinePolygon )
staticprivate

Definition at line 108 of file CutThroughShapeStrategy.cpp.

109{
110 bool containsGapLinePointStart = srcOutline.contains(gapLine.p1());
111 bool containsGapLinePointEnd = srcOutline.contains(gapLine.p2());
112
113 // if should skip if there is exactly one gap line point inside the shape
114 bool exactlyOneGapLinePointInside = (containsGapLinePointStart != containsGapLinePointEnd);
115 bool bothGapLinePointsInside = containsGapLinePointStart && containsGapLinePointEnd;
116
117 if (exactlyOneGapLinePointInside) {
118 return false;
119 }
120
121 bool crossesGapLine = KisAlgebra2D::getLineSegmentCrossingLineIndexes(leftLine, srcOutline).count() > 0
122 || KisAlgebra2D::getLineSegmentCrossingLineIndexes(rightLine, srcOutline).count() > 0;
123
124
125 // it doesn't contain exactly one point, therefore it contains either both or none.
126 // if it contains both, it will be true.
127 // if it contains none:
128 // if it crosses either gap line, it will be true
129 // if any of the shape points are inside the gap, it will be true
130 // otherwise it's false
131
132 if (bothGapLinePointsInside) {
133 return true;
134 }
135
136 if (crossesGapLine) {
137 return true;
138 }
139
140 Q_FOREACH(QPointF p, srcOutline.toFillPolygon()) {
141 if (gapLinePolygon.containsPoint(p, Qt::WindingFill)) {
142 // a shape point is inside the gap shape
143 return true;
144 }
145 }
146
147 return false;
148
149}
const Params2D p
QList< int > getLineSegmentCrossingLineIndexes(const QLineF &line, const QPainterPath &shape)

References KisAlgebra2D::getLineSegmentCrossingLineIndexes(), and p.

Friends And Related Symbol Documentation

◆ CutThroughShapeStrategyTest

friend class CutThroughShapeStrategyTest
friend

Definition at line 51 of file CutThroughShapeStrategy.h.

Member Data Documentation

◆ m_allShapes

QList<KoShape *> CutThroughShapeStrategy::m_allShapes
private

Definition at line 57 of file CutThroughShapeStrategy.h.

◆ m_endPoint

QPointF CutThroughShapeStrategy::m_endPoint = QPointF()
private

Definition at line 54 of file CutThroughShapeStrategy.h.

◆ m_previousLineDirtyRect

QRectF CutThroughShapeStrategy::m_previousLineDirtyRect = QRectF()
private

Definition at line 55 of file CutThroughShapeStrategy.h.

◆ m_selectedShapes

QList<KoShape *> CutThroughShapeStrategy::m_selectedShapes
private

Definition at line 56 of file CutThroughShapeStrategy.h.

◆ m_startPoint

QPointF CutThroughShapeStrategy::m_startPoint = QPointF()
private

Definition at line 53 of file CutThroughShapeStrategy.h.

◆ m_width

GutterWidthsConfig CutThroughShapeStrategy::m_width
private

Definition at line 58 of file CutThroughShapeStrategy.h.


The documentation for this class was generated from the following files: