12#include <QPainterPath>
30 DRAG_X_VANISHING_POINT,
31 DRAG_Y_VANISHING_POINT,
125 m_d(new
Private(this, converter, currentArgs, transaction))
153 v = QVector4D(1, 0, 0, 0);
158 v = QVector4D(0, 1, 0, 0);
166 Q_UNUSED(perspectiveModifierActive);
167 Q_UNUSED(shiftModifierActive);
168 Q_UNUSED(altModifierActive);
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);
177 if (!
m_d->transformedHandles.xVanishing.isNull()) {
179 handleRadius, DRAG_X_VANISHING_POINT);
182 if (!
m_d->transformedHandles.yVanishing.isNull()) {
184 handleRadius, DRAG_Y_VANISHING_POINT);
187 m_d->currentDraggingHandlePoint = -1;
188 for (
int i = 0; i <
m_d->dstHandlePoints.size(); i++) {
190 handleRadius, DRAG_HANDLE)) {
192 m_d->currentDraggingHandlePoint = i;
203 switch (
m_d->function) {
211 case DRAG_X_VANISHING_POINT:
212 case DRAG_Y_VANISHING_POINT:
224 gc.setOpacity(
m_d->transaction.basePreviewOpacity());
225 gc.setTransform(
m_d->paintingTransform,
true);
231 QPainterPath handles;
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());
240 auto addHandleRectFunc =
241 [&](
const QPointF &pt) {
244 m_d->handlesTransform,
245 m_d->transaction.originalRect(), pt)
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());
260 if (
m_d->isTransforming) {
276 QPainterPath mappedHandles =
m_d->handlesTransform.map(handles);
280 pen[0].setCosmetic(
true);
282 pen[1].setCosmetic(
true);
285 for (
int i = 1; i >= 0; --i) {
287 gc.drawPath(mappedHandles);
293 QPainterPath perspectiveHandles;
298 m_d->transaction.originalRect(), 0, 0);
300 if (
m_d->transformedHandles.xVanishingExists) {
301 QRectF rc = handleRect.translated(
m_d->transformedHandles.xVanishing);
302 perspectiveHandles.addEllipse(rc);
305 if (
m_d->transformedHandles.yVanishingExists) {
306 QRectF rc = handleRect.translated(
m_d->transformedHandles.yVanishing);
307 perspectiveHandles.addEllipse(rc);
310 if (!perspectiveHandles.isEmpty()) {
312 gc.setTransform(
m_d->converter->imageToWidgetTransform());
314 gc.setBrush(Qt::red);
316 for (
int i = 1; i >= 0; --i) {
318 gc.drawPath(perspectiveHandles);
328 m_d->recalculateTransformations();
333 if (
m_d->function ==
NONE)
return false;
336 m_d->clickArgs =
m_d->currentArgs;
346 A << sp[HANDLE_TOP_LEFT].x() , sp[HANDLE_TOP_RIGHT].x() , sp[HANDLE_BOTTOM_LEFT].x()
347 ,sp[HANDLE_TOP_LEFT].y() , sp[HANDLE_TOP_RIGHT].y() , sp[HANDLE_BOTTOM_LEFT].y()
350 v3 << sp[HANDLE_BOTTOM_RIGHT].x() , sp[HANDLE_BOTTOM_RIGHT].y() , 1;
352 Eigen::Vector3f coeffs =
A.colPivHouseholderQr().solve(v3);
354 A.col(0) *= coeffs(0);
355 A.col(1) *= coeffs(1);
356 A.col(2) *= coeffs(2);
363 return QTransform(m(0,0), m(1,0), m(2,0),
364 m(0,1), m(1,1), m(2,1),
365 m(0,2), m(1,2), m(2,2));
372 m << t.m11() , t.m21() , t.m31()
373 ,t.m12() , t.m22() , t.m32()
374 ,t.m13() , t.m23() , t.m33();
414 Eigen::Matrix3f TS =
fromTranslate(-currentArgs.originalCenter());
416 Eigen::Matrix3f m = t * TS.inverse();
418 qreal tX = m(0,2) / m(2,2);
419 qreal tY = m(1,2) / m(2,2);
443 currentArgs.setScaleX(dm.
scaleX);
444 currentArgs.setScaleY(dm.
scaleY);
446 currentArgs.setShearX(dm.
shearXY);
447 currentArgs.setShearY(0.0);
454 currentArgs.setScaleX(1.0);
455 currentArgs.setScaleY(1.0);
456 currentArgs.setShearX(0.0);
457 currentArgs.setShearY(0.0);
458 currentArgs.setAZ(0.0);
461 currentArgs.setTransformedCenter(QPointF(tX, tY));
462 currentArgs.setFlattenedPerspectiveTransform(
toQTransform(m));
472 return QVector4D(pt.x(), pt.y(), 0, 1.0);
476 return v.toVector2DAffine().toPointF();
481 Q_UNUSED(shiftModifierActive);
482 Q_UNUSED(altModifierActive);
484 m_d->isTransforming =
true;
486 switch (
m_d->function) {
490 QPointF diff = mousePos -
m_d->clickPos;
491 m_d->currentArgs.setTransformedCenter(
492 m_d->clickArgs.transformedCenter() + diff);
498 if (
m_d->currentDraggingHandlePoint < HANDLE_MIDDLE_TOP) {
500 m_d->dstHandlePoints[
m_d->currentDraggingHandlePoint] = mousePos;
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;
509 case HANDLE_MIDDLE_BOTTOM:
510 m_d->dstHandlePoints[HANDLE_BOTTOM_LEFT] += delta;
511 m_d->dstHandlePoints[HANDLE_BOTTOM_RIGHT] += delta;
513 case HANDLE_MIDDLE_LEFT:
514 m_d->dstHandlePoints[HANDLE_TOP_LEFT] += delta;
515 m_d->dstHandlePoints[HANDLE_BOTTOM_LEFT] += delta;
517 case HANDLE_MIDDLE_RIGHT:
518 m_d->dstHandlePoints[HANDLE_TOP_RIGHT] += delta;
519 m_d->dstHandlePoints[HANDLE_BOTTOM_RIGHT] += delta;
526 Eigen::Matrix3f result =
B *
A.inverse();
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];
539 m_d->transformIntoArgs(result);
543 case DRAG_X_VANISHING_POINT:
544 case DRAG_Y_VANISHING_POINT: {
546 QMatrix4x4 m(
m_d->transform);
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();
553 QVector4D
v(1,0,0,0);
554 QVector4D otherV(0,1,0,0);
556 if (
m_d->function == DRAG_X_VANISHING_POINT) {
557 v = QVector4D(1,0,0,0);
558 otherV = QVector4D(0,1,0,0);
560 v = QVector4D(0,1,0,0);
561 otherV = QVector4D(1,0,0,0);
569 QPointF otherV_dst =
toQPointF(m * otherV);
584 if (
m_d->function == DRAG_X_VANISHING_POINT) {
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);
644 srcPoints << far1_src;
645 srcPoints << far2_src;
646 srcPoints << near1_src;
647 srcPoints << near2_src;
649 dstPoints << far1_dst;
650 dstPoints << far2_dst;
651 dstPoints << near1_dst;
652 dstPoints << near2_dst;
656 Eigen::Matrix3f result =
B *
A.inverse();
658 m_d->transformIntoArgs(result);
663 m_d->recalculateTransformations();
668 bool shouldSave = !
m_d->imageTooBig;
669 m_d->isTransforming =
false;
671 if (
m_d->imageTooBig) {
672 m_d->currentArgs =
m_d->clickArgs;
673 m_d->recalculateTransformations();
681 transform = transformFromArgs();
683 QTransform viewScaleTransform = converter->imageToDocumentTransform() * converter->documentToFlakeTransform();
684 handlesTransform = transform * viewScaleTransform;
686 QTransform tl = QTransform::fromTranslate(transaction.originalTopLeft().x(), transaction.originalTopLeft().y());
687 paintingTransform = tl.inverted() * q->thumbToImageTransform() * tl * transform * viewScaleTransform;
688 paintingOffset = transaction.originalTopLeft();
694 points << transaction.originalRect().topLeft();
695 points << transaction.originalRect().topRight();
696 points << transaction.originalRect().bottomRight();
697 points << transaction.originalRect().bottomLeft();
699 for (
int i = 0; i < points.size(); i++) {
700 points[i] = transform.map(points[i]);
703 QPolygonF poly (points);
708 const QRectF transformedRect = poly.boundingRect();
710 if (!limitRect.contains(transformedRect)) {
716 recalculateTransformedHandles();
718 Q_EMIT q->requestShowImageTooBig(imageTooBig);
719 Q_EMIT q->requestImageRecalculation();
static QCursor moveCursor()
static QCursor arrowCursor()
static QCursor pointingHandCursor()
virtual QColor convertColorToDisplayColorSpace(const KoColor color) const =0
convertColorToDisplayColorSpace
static bool qFuzzyCompare(half p1, half p2)
#define KIS_ASSERT_RECOVER_RETURN(cond)
T kisDegreesToRadians(T degrees)
qreal kisSquareDistance(const QPointF &pt1, const QPointF &pt2)
QPointF toQPointF(const ExpressionType &expr)
Rect blowRect(const Rect &rect, qreal coeff)
bool isPolygonTrulyConvex(const QVector< T > &polygon, bool ensureNoLoops=true, qreal maxAngle=180.0)
QTransform shearTransform() const
QTransform rotateTransform() const
QTransform scaleTransform() const
static KoColorSpaceRegistry * instance()