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

#include <kis_perspective_transform_strategy.h>

+ Inheritance diagram for KisPerspectiveTransformStrategy:

Classes

struct  Private
 

Signals

void requestCanvasUpdate ()
 
void requestImageRecalculation ()
 
void requestShowImageTooBig (bool value)
 

Public Member Functions

bool beginPrimaryAction (const QPointF &pt) override
 
virtual bool beginPrimaryAction (KoPointerEvent *event)=0
 
void continuePrimaryAction (const QPointF &pt, bool shiftModifierActive, bool altModifierActive) override
 
virtual void continuePrimaryAction (KoPointerEvent *event)=0
 
bool endPrimaryAction () override
 
virtual bool endPrimaryAction (KoPointerEvent *event)=0
 
void externalConfigChanged () override
 
QCursor getCurrentCursor () const override
 
 KisPerspectiveTransformStrategy (const KisCoordinatesConverter *converter, KoSnapGuide *snapGuide, ToolTransformArgs &currentArgs, TransformTransactionProperties &transaction)
 
void paint (QPainter &gc, const KoColorDisplayRendererInterface *displayRendererInterface) override
 
void setTransformFunction (const QPointF &mousePos, bool perspectiveModifierActive, bool shiftModifierActive, bool altModifierActive) override
 
 ~KisPerspectiveTransformStrategy () override
 
- Public Member Functions inherited from KisSimplifiedActionPolicyStrategy
void activateAlternateAction (KisTool::AlternateAction action) override
 
void activatePrimaryAction () override
 
bool beginAlternateAction (KoPointerEvent *event, KisTool::AlternateAction action) override
 
bool beginPrimaryAction (KoPointerEvent *event) override
 
void continueAlternateAction (KoPointerEvent *event, KisTool::AlternateAction action) override
 
void continuePrimaryAction (KoPointerEvent *event) override
 
void deactivateAlternateAction (KisTool::AlternateAction action) override
 
bool endAlternateAction (KoPointerEvent *event, KisTool::AlternateAction action) override
 
bool endPrimaryAction (KoPointerEvent *event) override
 
virtual QPointF handleSnapPoint (const QPointF &imagePos)
 
void hoverActionCommon (KoPointerEvent *event) override
 
 KisSimplifiedActionPolicyStrategy (const KisCoordinatesConverter *_converter, KoSnapGuide *snapGuide=0)
 
 ~KisSimplifiedActionPolicyStrategy () override
 
- Public Member Functions inherited from KisTransformStrategyBase
virtual bool acceptsClicks () const
 
virtual void deactivatePrimaryAction ()
 
virtual int decorationThickness () const
 
virtual void decreaseBrushSize (KoCanvasBase *canvas)
 
virtual QPainterPath getCursorOutline () const
 
virtual void increaseBrushSize (KoCanvasBase *canvas)
 
 KisTransformStrategyBase ()
 
QImage originalImage () const
 
virtual void setDecorationThickness (int thickness)
 
void setThumbnailImage (const QImage &image, QTransform thumbToImageTransform)
 
QTransform thumbToImageTransform () const
 
 ~KisTransformStrategyBase () override
 

Private Attributes

const QScopedPointer< Private > m_d
 

Additional Inherited Members

- Protected Member Functions inherited from KisSimplifiedActionPolicyStrategy
virtual void continuePrimaryAction (const QPointF &pt, bool shiftModifierActive, bool altModifierActive, bool hasOriginalModifiersSet)
 
virtual void hoverActionCommon (const QPointF &pt)
 
virtual bool shiftModifierIsUsed () const
 

Detailed Description

Definition at line 22 of file kis_perspective_transform_strategy.h.

Constructor & Destructor Documentation

◆ KisPerspectiveTransformStrategy()

KisPerspectiveTransformStrategy::KisPerspectiveTransformStrategy ( const KisCoordinatesConverter * converter,
KoSnapGuide * snapGuide,
ToolTransformArgs & currentArgs,
TransformTransactionProperties & transaction )

Definition at line 120 of file kis_perspective_transform_strategy.cpp.

124 : KisSimplifiedActionPolicyStrategy(converter, snapGuide),
125 m_d(new Private(this, converter, currentArgs, transaction))
126{
127}
KisSimplifiedActionPolicyStrategy(const KisCoordinatesConverter *_converter, KoSnapGuide *snapGuide=0)

◆ ~KisPerspectiveTransformStrategy()

KisPerspectiveTransformStrategy::~KisPerspectiveTransformStrategy ( )
override

Definition at line 129 of file kis_perspective_transform_strategy.cpp.

130{
131}

Member Function Documentation

◆ beginPrimaryAction() [1/2]

bool KisPerspectiveTransformStrategy::beginPrimaryAction ( const QPointF & pt)
overridevirtual

Implements KisSimplifiedActionPolicyStrategy.

Definition at line 331 of file kis_perspective_transform_strategy.cpp.

332{
333 if (m_d->function == NONE) return false;
334
335 m_d->clickPos = pt;
336 m_d->clickArgs = m_d->currentArgs;
337
338 return true;
339}
@ NONE

References m_d, and NONE.

◆ beginPrimaryAction() [2/2]

virtual bool KisTransformStrategyBase::beginPrimaryAction ( KoPointerEvent * event)
virtual

◆ continuePrimaryAction() [1/2]

void KisPerspectiveTransformStrategy::continuePrimaryAction ( const QPointF & pt,
bool shiftModifierActive,
bool altModifierActive )
overridevirtual

Implements KisSimplifiedActionPolicyStrategy.

Definition at line 479 of file kis_perspective_transform_strategy.cpp.

480{
481 Q_UNUSED(shiftModifierActive);
482 Q_UNUSED(altModifierActive);
483
484 m_d->isTransforming = true;
485
486 switch (m_d->function) {
487 case NONE:
488 break;
489 case MOVE: {
490 QPointF diff = mousePos - m_d->clickPos;
491 m_d->currentArgs.setTransformedCenter(
492 m_d->clickArgs.transformedCenter() + diff);
493 break;
494 }
495 case DRAG_HANDLE: {
496 KIS_ASSERT_RECOVER_RETURN(m_d->currentDraggingHandlePoint >= 0);
497 KIS_ASSERT_RECOVER_RETURN(m_d->currentDraggingHandlePoint < HANDLE_COUNT);
498 if (m_d->currentDraggingHandlePoint < HANDLE_MIDDLE_TOP) {
499 // Corner point, transform directly.
500 m_d->dstHandlePoints[m_d->currentDraggingHandlePoint] = mousePos;
501 } else {
502 // Middle point, move adjacent corners.
503 QPointF delta = mousePos - m_d->dstHandlePoints[m_d->currentDraggingHandlePoint];
504 switch(m_d->currentDraggingHandlePoint) {
505 case HANDLE_MIDDLE_TOP:
506 m_d->dstHandlePoints[HANDLE_TOP_LEFT] += delta;
507 m_d->dstHandlePoints[HANDLE_TOP_RIGHT] += delta;
508 break;
509 case HANDLE_MIDDLE_BOTTOM:
510 m_d->dstHandlePoints[HANDLE_BOTTOM_LEFT] += delta;
511 m_d->dstHandlePoints[HANDLE_BOTTOM_RIGHT] += delta;
512 break;
513 case HANDLE_MIDDLE_LEFT:
514 m_d->dstHandlePoints[HANDLE_TOP_LEFT] += delta;
515 m_d->dstHandlePoints[HANDLE_BOTTOM_LEFT] += delta;
516 break;
517 case HANDLE_MIDDLE_RIGHT:
518 m_d->dstHandlePoints[HANDLE_TOP_RIGHT] += delta;
519 m_d->dstHandlePoints[HANDLE_BOTTOM_RIGHT] += delta;
520 break;
521 }
522 }
523
524 Eigen::Matrix3f A = getTransitionMatrix(m_d->srcHandlePoints);
525 Eigen::Matrix3f B = getTransitionMatrix(m_d->dstHandlePoints);
526 Eigen::Matrix3f result = B * A.inverse();
527
528 // Points in dstHandlePoints are not arranged in an organized way, so if we used it directly as a polygon it
529 // will never be considered convex
530 QPolygonF poly;
531 poly << m_d->dstHandlePoints[HANDLE_TOP_LEFT] << m_d->dstHandlePoints[HANDLE_TOP_RIGHT]
532 << m_d->dstHandlePoints[HANDLE_BOTTOM_RIGHT] << m_d->dstHandlePoints[HANDLE_BOTTOM_LEFT];
533
534 //Don't apply the handle movement if it makes the transform area not convex
536 break;
537 }
538
539 m_d->transformIntoArgs(result);
540
541 break;
542 }
543 case DRAG_X_VANISHING_POINT:
544 case DRAG_Y_VANISHING_POINT: {
545
546 QMatrix4x4 m(m_d->transform);
547
548 QPointF tl = m_d->transaction.originalTopLeft();
549 QPointF tr = m_d->transaction.originalTopRight();
550 QPointF bl = m_d->transaction.originalBottomLeft();
551 QPointF br = m_d->transaction.originalBottomRight();
552
553 QVector4D v(1,0,0,0);
554 QVector4D otherV(0,1,0,0);
555
556 if (m_d->function == DRAG_X_VANISHING_POINT) {
557 v = QVector4D(1,0,0,0);
558 otherV = QVector4D(0,1,0,0);
559 } else {
560 v = QVector4D(0,1,0,0);
561 otherV = QVector4D(1,0,0,0);
562 }
563
564 QPointF tl_dst = toQPointF(m * fromQPointF(tl));
565 QPointF tr_dst = toQPointF(m * fromQPointF(tr));
566 QPointF bl_dst = toQPointF(m * fromQPointF(bl));
567 QPointF br_dst = toQPointF(m * fromQPointF(br));
568 QPointF v_dst = toQPointF(m * v);
569 QPointF otherV_dst = toQPointF(m * otherV);
570
571 QVector<QPointF> srcPoints;
572 QVector<QPointF> dstPoints;
573
574 QPointF far1_src;
575 QPointF far2_src;
576 QPointF near1_src;
577 QPointF near2_src;
578
579 QPointF far1_dst;
580 QPointF far2_dst;
581 QPointF near1_dst;
582 QPointF near2_dst;
583
584 if (m_d->function == DRAG_X_VANISHING_POINT) {
585
586 // topLeft (far) --- topRight (near) --- vanishing
587 if (kisSquareDistance(v_dst, tl_dst) > kisSquareDistance(v_dst, tr_dst)) {
588 far1_src = tl;
589 far2_src = bl;
590 near1_src = tr;
591 near2_src = br;
592
593 far1_dst = tl_dst;
594 far2_dst = bl_dst;
595 near1_dst = tr_dst;
596 near2_dst = br_dst;
597
598 // topRight (far) --- topLeft (near) --- vanishing
599 } else {
600 far1_src = tr;
601 far2_src = br;
602 near1_src = tl;
603 near2_src = bl;
604
605 far1_dst = tr_dst;
606 far2_dst = br_dst;
607 near1_dst = tl_dst;
608 near2_dst = bl_dst;
609 }
610
611 } else /* if (m_d->function == DRAG_Y_VANISHING_POINT) */{
612 // topLeft (far) --- bottomLeft (near) --- vanishing
613 if (kisSquareDistance(v_dst, tl_dst) > kisSquareDistance(v_dst, bl_dst)) {
614 far1_src = tl;
615 far2_src = tr;
616 near1_src = bl;
617 near2_src = br;
618
619 far1_dst = tl_dst;
620 far2_dst = tr_dst;
621 near1_dst = bl_dst;
622 near2_dst = br_dst;
623
624 // bottomLeft (far) --- topLeft (near) --- vanishing
625 } else {
626 far1_src = bl;
627 far2_src = br;
628 near1_src = tl;
629 near2_src = tr;
630
631 far1_dst = bl_dst;
632 far2_dst = br_dst;
633 near1_dst = tl_dst;
634 near2_dst = tr_dst;
635 }
636 }
637
638 QLineF l0(far1_dst, mousePos);
639 QLineF l1(far2_dst, mousePos);
640 QLineF l2(otherV_dst, near1_dst);
641 l0.intersects(l2, &near1_dst);
642 l1.intersects(l2, &near2_dst);
643
644 srcPoints << far1_src;
645 srcPoints << far2_src;
646 srcPoints << near1_src;
647 srcPoints << near2_src;
648
649 dstPoints << far1_dst;
650 dstPoints << far2_dst;
651 dstPoints << near1_dst;
652 dstPoints << near2_dst;
653
654 Eigen::Matrix3f A = getTransitionMatrix(srcPoints);
655 Eigen::Matrix3f B = getTransitionMatrix(dstPoints);
656 Eigen::Matrix3f result = B * A.inverse();
657
658 m_d->transformIntoArgs(result);
659 break;
660 }
661 }
662
663 m_d->recalculateTransformations();
664}
qreal v
#define KIS_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:75
qreal kisSquareDistance(const QPointF &pt1, const QPointF &pt2)
Definition kis_global.h:194
QVector4D fromQPointF(const QPointF &pt)
Eigen::Matrix3f getTransitionMatrix(const QVector< QPointF > &sp)
QPointF toQPointF(const ExpressionType &expr)
Definition kis_vec.h:29
bool isPolygonTrulyConvex(const QVector< T > &polygon, bool ensureNoLoops=true, qreal maxAngle=180.0)

References A, B, fromQPointF(), getTransitionMatrix(), KisAlgebra2D::isPolygonTrulyConvex(), KIS_ASSERT_RECOVER_RETURN, kisSquareDistance(), m_d, KisPerspectiveTransformStrategy::Private::MaxPolygonVertexAngle, MOVE, NONE, toQPointF(), and v.

◆ continuePrimaryAction() [2/2]

virtual void KisTransformStrategyBase::continuePrimaryAction ( KoPointerEvent * event)
virtual

◆ endPrimaryAction() [1/2]

bool KisPerspectiveTransformStrategy::endPrimaryAction ( )
overridevirtual

Implements KisSimplifiedActionPolicyStrategy.

Definition at line 666 of file kis_perspective_transform_strategy.cpp.

667{
668 bool shouldSave = !m_d->imageTooBig;
669 m_d->isTransforming = false;
670
671 if (m_d->imageTooBig) {
672 m_d->currentArgs = m_d->clickArgs;
673 m_d->recalculateTransformations();
674 }
675
676 return shouldSave;
677}

References m_d.

◆ endPrimaryAction() [2/2]

virtual bool KisTransformStrategyBase::endPrimaryAction ( KoPointerEvent * event)
virtual

◆ externalConfigChanged()

void KisPerspectiveTransformStrategy::externalConfigChanged ( )
overridevirtual

Implements KisTransformStrategyBase.

Definition at line 326 of file kis_perspective_transform_strategy.cpp.

327{
328 m_d->recalculateTransformations();
329}

References m_d.

◆ getCurrentCursor()

QCursor KisPerspectiveTransformStrategy::getCurrentCursor ( ) const
overridevirtual

Implements KisTransformStrategyBase.

Definition at line 199 of file kis_perspective_transform_strategy.cpp.

200{
201 QCursor cursor;
202
203 switch (m_d->function) {
204 case NONE:
205 cursor = KisCursor::arrowCursor();
206 break;
207 case MOVE:
208 cursor = KisCursor::moveCursor();
209 break;
210 case DRAG_HANDLE:
211 case DRAG_X_VANISHING_POINT:
212 case DRAG_Y_VANISHING_POINT:
214 break;
215 }
216
217 return cursor;
218}
static QCursor moveCursor()
static QCursor arrowCursor()
Definition kis_cursor.cc:24
static QCursor pointingHandCursor()

References KisCursor::arrowCursor(), m_d, MOVE, KisCursor::moveCursor(), NONE, and KisCursor::pointingHandCursor().

◆ paint()

void KisPerspectiveTransformStrategy::paint ( QPainter & gc,
const KoColorDisplayRendererInterface * displayRendererInterface )
overridevirtual

WARNING: we cannot install a transform to paint the handles here!

There is a bug in Qt that prevents painting of cosmetic-pen brushes in openGL mode when a TxProject matrix is active on a QPainter. So just convert it manually.

https://bugreports.qt-project.org/browse/QTBUG-42658

Implements KisTransformStrategyBase.

Definition at line 220 of file kis_perspective_transform_strategy.cpp.

221{
222 gc.save();
223
224 gc.setOpacity(m_d->transaction.basePreviewOpacity());
225 gc.setTransform(m_d->paintingTransform, true);
226 gc.drawImage(m_d->paintingOffset, originalImage());
227
228 gc.restore();
229
230 // Draw Handles
231 QPainterPath handles;
232
233 handles.moveTo(m_d->transaction.originalTopLeft());
234 handles.lineTo(m_d->transaction.originalTopRight());
235 handles.lineTo(m_d->transaction.originalBottomRight());
236 handles.lineTo(m_d->transaction.originalBottomLeft());
237 handles.lineTo(m_d->transaction.originalTopLeft());
238
239
240 auto addHandleRectFunc =
241 [&](const QPointF &pt) {
242 handles.addRect(
244 m_d->handlesTransform,
245 m_d->transaction.originalRect(), pt)
246 .translated(pt));
247 };
248
249 addHandleRectFunc(m_d->transaction.originalTopLeft());
250 addHandleRectFunc(m_d->transaction.originalTopRight());
251 addHandleRectFunc(m_d->transaction.originalBottomLeft());
252 addHandleRectFunc(m_d->transaction.originalBottomRight());
253 addHandleRectFunc(m_d->transaction.originalMiddleTop());
254 addHandleRectFunc(m_d->transaction.originalMiddleBottom());
255 addHandleRectFunc(m_d->transaction.originalMiddleLeft());
256 addHandleRectFunc(m_d->transaction.originalMiddleRight());
257
258 gc.save();
259
260 if (m_d->isTransforming) {
261 gc.setOpacity(0.1);
262 }
263
274 //gc.setTransform(m_d->handlesTransform, true); <-- don't do like this!
275
276 QPainterPath mappedHandles = m_d->handlesTransform.map(handles);
277
278 QPen pen[2];
279 pen[0].setWidth(decorationThickness());
280 pen[0].setCosmetic(true);
281 pen[1].setWidth(decorationThickness() * 2);
282 pen[1].setCosmetic(true);
283 pen[1].setColor(displayRendererInterface->convertColorToDisplayColorSpace(KoColor(Qt::lightGray, KoColorSpaceRegistry::instance()->rgb8())));
284
285 for (int i = 1; i >= 0; --i) {
286 gc.setPen(pen[i]);
287 gc.drawPath(mappedHandles);
288 }
289
290 gc.restore();
291
292 { // painting perspective handles
293 QPainterPath perspectiveHandles;
294
295 QRectF handleRect =
297 QTransform(),
298 m_d->transaction.originalRect(), 0, 0);
299
300 if (m_d->transformedHandles.xVanishingExists) {
301 QRectF rc = handleRect.translated(m_d->transformedHandles.xVanishing);
302 perspectiveHandles.addEllipse(rc);
303 }
304
305 if (m_d->transformedHandles.yVanishingExists) {
306 QRectF rc = handleRect.translated(m_d->transformedHandles.yVanishing);
307 perspectiveHandles.addEllipse(rc);
308 }
309
310 if (!perspectiveHandles.isEmpty()) {
311 gc.save();
312 gc.setTransform(m_d->converter->imageToWidgetTransform());
313
314 gc.setBrush(Qt::red);
315
316 for (int i = 1; i >= 0; --i) {
317 gc.setPen(pen[i]);
318 gc.drawPath(perspectiveHandles);
319 }
320
321 gc.restore();
322 }
323 }
324}
static const int handleVisualRadius
static QRectF handleRect(qreal radius, const QTransform &t, const QRectF &limitingRect, qreal *dOutX, qreal *dOutY)
virtual QColor convertColorToDisplayColorSpace(const KoColor color) const =0
convertColorToDisplayColorSpace
static KoColorSpaceRegistry * instance()

References KoColorDisplayRendererInterface::convertColorToDisplayColorSpace(), KisTransformStrategyBase::decorationThickness(), KisTransformUtils::handleRect(), KisTransformUtils::handleVisualRadius, KoColorSpaceRegistry::instance(), m_d, and KisTransformStrategyBase::originalImage().

◆ requestCanvasUpdate

void KisPerspectiveTransformStrategy::requestCanvasUpdate ( )
signal

◆ requestImageRecalculation

void KisPerspectiveTransformStrategy::requestImageRecalculation ( )
signal

◆ requestShowImageTooBig

void KisPerspectiveTransformStrategy::requestShowImageTooBig ( bool value)
signal

◆ setTransformFunction()

void KisPerspectiveTransformStrategy::setTransformFunction ( const QPointF & mousePos,
bool perspectiveModifierActive,
bool shiftModifierActive,
bool altModifierActive )
overridevirtual

Implements KisSimplifiedActionPolicyStrategy.

Definition at line 164 of file kis_perspective_transform_strategy.cpp.

165{
166 Q_UNUSED(perspectiveModifierActive);
167 Q_UNUSED(shiftModifierActive);
168 Q_UNUSED(altModifierActive);
169
170 QPolygonF transformedPolygon = m_d->transform.map(QPolygonF(m_d->transaction.originalRect()));
171 StrokeFunction defaultFunction = transformedPolygon.containsPoint(mousePos, Qt::OddEvenFill) ? MOVE : NONE;
173 handleChooser(mousePos, defaultFunction);
174
175 qreal handleRadius = KisTransformUtils::effectiveHandleGrabRadius(m_d->converter);
176
177 if (!m_d->transformedHandles.xVanishing.isNull()) {
178 handleChooser.addFunction(m_d->transformedHandles.xVanishing,
179 handleRadius, DRAG_X_VANISHING_POINT);
180 }
181
182 if (!m_d->transformedHandles.yVanishing.isNull()) {
183 handleChooser.addFunction(m_d->transformedHandles.yVanishing,
184 handleRadius, DRAG_Y_VANISHING_POINT);
185 }
186
187 m_d->currentDraggingHandlePoint = -1;
188 for (int i = 0; i < m_d->dstHandlePoints.size(); i++) {
189 if (handleChooser.addFunction(m_d->dstHandlePoints[i],
190 handleRadius, DRAG_HANDLE)) {
191
192 m_d->currentDraggingHandlePoint = i;
193 }
194 }
195
196 m_d->function = handleChooser.function();
197}
static qreal effectiveHandleGrabRadius(const KisCoordinatesConverter *converter)

References KisTransformUtils::HandleChooser< Function >::addFunction(), KisTransformUtils::effectiveHandleGrabRadius(), KisTransformUtils::HandleChooser< Function >::function(), m_d, MOVE, and NONE.

Member Data Documentation

◆ m_d

const QScopedPointer<Private> KisPerspectiveTransformStrategy::m_d
private

Definition at line 53 of file kis_perspective_transform_strategy.h.


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