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) 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 QPainterPath getCursorOutline () const
 
 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< Privatem_d
 

Additional Inherited Members

- Protected Member Functions inherited from KisSimplifiedActionPolicyStrategy
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 117 of file kis_perspective_transform_strategy.cpp.

121 : KisSimplifiedActionPolicyStrategy(converter, snapGuide),
122 m_d(new Private(this, converter, currentArgs, transaction))
123{
124}
KisSimplifiedActionPolicyStrategy(const KisCoordinatesConverter *_converter, KoSnapGuide *snapGuide=0)

◆ ~KisPerspectiveTransformStrategy()

KisPerspectiveTransformStrategy::~KisPerspectiveTransformStrategy ( )
override

Definition at line 126 of file kis_perspective_transform_strategy.cpp.

127{
128}

Member Function Documentation

◆ beginPrimaryAction() [1/2]

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

Implements KisSimplifiedActionPolicyStrategy.

Definition at line 328 of file kis_perspective_transform_strategy.cpp.

329{
330 Q_UNUSED(pt);
331
332 if (m_d->function == NONE) return false;
333
334 m_d->clickPos = pt;
335 m_d->clickArgs = m_d->currentArgs;
336
337 return true;
338}
@ 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 478 of file kis_perspective_transform_strategy.cpp.

479{
480 Q_UNUSED(shiftModifierActive);
481 Q_UNUSED(altModifierActive);
482
483 m_d->isTransforming = true;
484
485 switch (m_d->function) {
486 case NONE:
487 break;
488 case MOVE: {
489 QPointF diff = mousePos - m_d->clickPos;
490 m_d->currentArgs.setTransformedCenter(
491 m_d->clickArgs.transformedCenter() + diff);
492 break;
493 }
494 case DRAG_HANDLE: {
495 KIS_ASSERT_RECOVER_RETURN(m_d->currentDraggingHandlePoint >= 0);
496 KIS_ASSERT_RECOVER_RETURN(m_d->currentDraggingHandlePoint < HANDLE_COUNT);
497 if (m_d->currentDraggingHandlePoint < HANDLE_MIDDLE_TOP) {
498 // Corner point, transform directly.
499 m_d->dstHandlePoints[m_d->currentDraggingHandlePoint] = mousePos;
500 } else {
501 // Middle point, move adjacent corners.
502 QPointF delta = mousePos - m_d->dstHandlePoints[m_d->currentDraggingHandlePoint];
503 switch(m_d->currentDraggingHandlePoint) {
504 case HANDLE_MIDDLE_TOP:
505 m_d->dstHandlePoints[HANDLE_TOP_LEFT] += delta;
506 m_d->dstHandlePoints[HANDLE_TOP_RIGHT] += delta;
507 break;
508 case HANDLE_MIDDLE_BOTTOM:
509 m_d->dstHandlePoints[HANDLE_BOTTOM_LEFT] += delta;
510 m_d->dstHandlePoints[HANDLE_BOTTOM_RIGHT] += delta;
511 break;
512 case HANDLE_MIDDLE_LEFT:
513 m_d->dstHandlePoints[HANDLE_TOP_LEFT] += delta;
514 m_d->dstHandlePoints[HANDLE_BOTTOM_LEFT] += delta;
515 break;
516 case HANDLE_MIDDLE_RIGHT:
517 m_d->dstHandlePoints[HANDLE_TOP_RIGHT] += delta;
518 m_d->dstHandlePoints[HANDLE_BOTTOM_RIGHT] += delta;
519 break;
520 }
521 }
522
523 Eigen::Matrix3f A = getTransitionMatrix(m_d->srcHandlePoints);
524 Eigen::Matrix3f B = getTransitionMatrix(m_d->dstHandlePoints);
525 Eigen::Matrix3f result = B * A.inverse();
526
527 m_d->transformIntoArgs(result);
528
529 break;
530 }
531 case DRAG_X_VANISHING_POINT:
532 case DRAG_Y_VANISHING_POINT: {
533
534 QMatrix4x4 m(m_d->transform);
535
536 QPointF tl = m_d->transaction.originalTopLeft();
537 QPointF tr = m_d->transaction.originalTopRight();
538 QPointF bl = m_d->transaction.originalBottomLeft();
539 QPointF br = m_d->transaction.originalBottomRight();
540
541 QVector4D v(1,0,0,0);
542 QVector4D otherV(0,1,0,0);
543
544 if (m_d->function == DRAG_X_VANISHING_POINT) {
545 v = QVector4D(1,0,0,0);
546 otherV = QVector4D(0,1,0,0);
547 } else {
548 v = QVector4D(0,1,0,0);
549 otherV = QVector4D(1,0,0,0);
550 }
551
552 QPointF tl_dst = toQPointF(m * fromQPointF(tl));
553 QPointF tr_dst = toQPointF(m * fromQPointF(tr));
554 QPointF bl_dst = toQPointF(m * fromQPointF(bl));
555 QPointF br_dst = toQPointF(m * fromQPointF(br));
556 QPointF v_dst = toQPointF(m * v);
557 QPointF otherV_dst = toQPointF(m * otherV);
558
559 QVector<QPointF> srcPoints;
560 QVector<QPointF> dstPoints;
561
562 QPointF far1_src;
563 QPointF far2_src;
564 QPointF near1_src;
565 QPointF near2_src;
566
567 QPointF far1_dst;
568 QPointF far2_dst;
569 QPointF near1_dst;
570 QPointF near2_dst;
571
572 if (m_d->function == DRAG_X_VANISHING_POINT) {
573
574 // topLeft (far) --- topRight (near) --- vanishing
575 if (kisSquareDistance(v_dst, tl_dst) > kisSquareDistance(v_dst, tr_dst)) {
576 far1_src = tl;
577 far2_src = bl;
578 near1_src = tr;
579 near2_src = br;
580
581 far1_dst = tl_dst;
582 far2_dst = bl_dst;
583 near1_dst = tr_dst;
584 near2_dst = br_dst;
585
586 // topRight (far) --- topLeft (near) --- vanishing
587 } else {
588 far1_src = tr;
589 far2_src = br;
590 near1_src = tl;
591 near2_src = bl;
592
593 far1_dst = tr_dst;
594 far2_dst = br_dst;
595 near1_dst = tl_dst;
596 near2_dst = bl_dst;
597 }
598
599 } else /* if (m_d->function == DRAG_Y_VANISHING_POINT) */{
600 // topLeft (far) --- bottomLeft (near) --- vanishing
601 if (kisSquareDistance(v_dst, tl_dst) > kisSquareDistance(v_dst, bl_dst)) {
602 far1_src = tl;
603 far2_src = tr;
604 near1_src = bl;
605 near2_src = br;
606
607 far1_dst = tl_dst;
608 far2_dst = tr_dst;
609 near1_dst = bl_dst;
610 near2_dst = br_dst;
611
612 // bottomLeft (far) --- topLeft (near) --- vanishing
613 } else {
614 far1_src = bl;
615 far2_src = br;
616 near1_src = tl;
617 near2_src = tr;
618
619 far1_dst = bl_dst;
620 far2_dst = br_dst;
621 near1_dst = tl_dst;
622 near2_dst = tr_dst;
623 }
624 }
625
626 QLineF l0(far1_dst, mousePos);
627 QLineF l1(far2_dst, mousePos);
628 QLineF l2(otherV_dst, near1_dst);
629 l0.intersects(l2, &near1_dst);
630 l1.intersects(l2, &near2_dst);
631
632 srcPoints << far1_src;
633 srcPoints << far2_src;
634 srcPoints << near1_src;
635 srcPoints << near2_src;
636
637 dstPoints << far1_dst;
638 dstPoints << far2_dst;
639 dstPoints << near1_dst;
640 dstPoints << near2_dst;
641
642 Eigen::Matrix3f A = getTransitionMatrix(srcPoints);
643 Eigen::Matrix3f B = getTransitionMatrix(dstPoints);
644 Eigen::Matrix3f result = B * A.inverse();
645
646 m_d->transformIntoArgs(result);
647 break;
648 }
649 }
650
651 m_d->recalculateTransformations();
652}
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

References A, B, fromQPointF(), getTransitionMatrix(), KIS_ASSERT_RECOVER_RETURN, kisSquareDistance(), m_d, 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 654 of file kis_perspective_transform_strategy.cpp.

655{
656 bool shouldSave = !m_d->imageTooBig;
657 m_d->isTransforming = false;
658
659 if (m_d->imageTooBig) {
660 m_d->currentArgs = m_d->clickArgs;
661 m_d->recalculateTransformations();
662 }
663
664 return shouldSave;
665}

References m_d.

◆ endPrimaryAction() [2/2]

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

◆ externalConfigChanged()

void KisPerspectiveTransformStrategy::externalConfigChanged ( )
overridevirtual

Implements KisTransformStrategyBase.

Definition at line 323 of file kis_perspective_transform_strategy.cpp.

324{
325 m_d->recalculateTransformations();
326}

References m_d.

◆ getCurrentCursor()

QCursor KisPerspectiveTransformStrategy::getCurrentCursor ( ) const
overridevirtual

Implements KisTransformStrategyBase.

Definition at line 196 of file kis_perspective_transform_strategy.cpp.

197{
198 QCursor cursor;
199
200 switch (m_d->function) {
201 case NONE:
202 cursor = KisCursor::arrowCursor();
203 break;
204 case MOVE:
205 cursor = KisCursor::moveCursor();
206 break;
207 case DRAG_HANDLE:
208 case DRAG_X_VANISHING_POINT:
209 case DRAG_Y_VANISHING_POINT:
211 break;
212 }
213
214 return cursor;
215}
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)
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 217 of file kis_perspective_transform_strategy.cpp.

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

References KisTransformStrategyBase::decorationThickness(), KisTransformUtils::handleRect(), KisTransformUtils::handleVisualRadius, 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 161 of file kis_perspective_transform_strategy.cpp.

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