199 Q_UNUSED(shiftModifierActive);
201 if (perspectiveModifierActive && !
m_d->transaction.shouldAvoidPerspectiveTransform()) {
202 m_d->function = PERSPECTIVE;
206 QTransform boundsFullTransform =
m_d->boundsTransform *
m_d->transform;
207 QPolygonF transformedPolygon = boundsFullTransform.map(QPolygonF(
m_d->bounds));
212 StrokeFunction defaultFunction;
213 if (transformedPolygon.containsPoint(mousePos, Qt::OddEvenFill))
214 defaultFunction =
MOVE;
215 else if (
m_d->transaction.boundsRotationAllowed() && altModifierActive)
216 defaultFunction = ROTATEBOUNDS;
218 defaultFunction = ROTATE;
220 handleChooser(mousePos, defaultFunction);
223 handleRadius, TOPSCALE);
225 handleRadius, TOPRIGHTSCALE);
227 handleRadius, RIGHTSCALE);
230 handleRadius, BOTTOMRIGHTSCALE);
232 handleRadius, BOTTOMSCALE);
234 handleRadius, BOTTOMLEFTSCALE);
236 handleRadius, LEFTSCALE);
238 handleRadius, TOPLEFTSCALE);
240 rotationHandleRadius, MOVECENTER);
244 if (
m_d->function == ROTATE ||
m_d->function ==
MOVE) {
246 QPointF t = boundsFullTransform.inverted().map(mousePos);
248 if (t.x() >=
bounds.left() && t.x() <=
bounds.right()) {
249 if (fabs(t.y() -
bounds.top()) <= handleRadius)
250 m_d->function = TOPSHEAR;
251 if (fabs(t.y() -
bounds.bottom()) <= handleRadius)
252 m_d->function = BOTTOMSHEAR;
254 if (t.y() >=
bounds.top() && t.y() <=
bounds.bottom()) {
255 if (fabs(t.x() -
bounds.left()) <= handleRadius)
256 m_d->function = LEFTSHEAR;
257 if (fabs(t.x() -
bounds.right()) <= handleRadius)
258 m_d->function = RIGHTSHEAR;
450 bool shiftModifierActive,
451 bool altModifierActive)
456 m_d->isTransforming =
true;
457 const QPointF anchorPoint =
m_d->clickArgs.originalCenter() +
m_d->clickArgs.rotationCenterOffset();
459 switch (
m_d->function) {
461 QPointF diff = mousePos -
m_d->clickPos;
463 if (shiftModifierActive) {
467 QPointF originalDiff = t.inverted().map(diff);
469 if (qAbs(originalDiff.x()) >= qAbs(originalDiff.y())) {
470 originalDiff.setY(0);
472 originalDiff.setX(0);
475 diff = t.map(originalDiff);
479 m_d->currentArgs.setTransformedCenter(
m_d->clickArgs.transformedCenter() + diff);
488 const QPointF rotationCenter =
m_d->clickArgs.originalCenter() +
m_d->clickArgs.rotationCenterOffset();
489 const QPointF clickMouseImagePos = clickT.inverted().map(
m_d->clickPos) - rotationCenter;
490 const QPointF mouseImagePosClickSpace = clickT.inverted().map(mousePos) - rotationCenter;
492 const qreal a1 = atan2(clickMouseImagePos.y(), clickMouseImagePos.x());
493 const qreal a2 = atan2(mouseImagePosClickSpace.y(), mouseImagePosClickSpace.x());
495 const qreal theta = a2 - a1;
496 m_d->currentArgs.setBoundsRotation(
m_d->clickArgs.boundsRotation() + theta);
499 QTransform newBR; newBR.rotateRadians(
m_d->currentArgs.boundsRotation());
500 QTransform clickZ; clickZ.rotateRadians(
m_d->clickArgs.aZ());
503 QTransform desired = newBR * clickM.
BRI * clickM.
SC * clickM.
S * clickZ;
509 m_d->currentArgs.setShearY(0);
527 const QPointF rotationCenter =
m_d->clickArgs.originalCenter() +
m_d->clickArgs.rotationCenterOffset();
528 const QPointF clickMouseImagePos = clickT.inverted().map(
m_d->clickPos) - rotationCenter;
529 const QPointF mouseImagePosClickSpace = clickT.inverted().map(mousePos) - rotationCenter;
531 const qreal a1 = atan2(clickMouseImagePos.y(), clickMouseImagePos.x());
532 const qreal a2 = atan2(mouseImagePosClickSpace.y(), mouseImagePosClickSpace.x());
541 if (shiftModifierActive) {
542 const qreal snapAngle = M_PI_4 / 6.0;
543 qint32 thetaIndex =
static_cast<qint32
>((theta / snapAngle) + 0.5);
544 m_d->currentArgs.setAZ(thetaIndex * snapAngle);
547 const qreal clickAngle =
m_d->clickArgs.aZ();
548 const qreal targetAngle =
m_d->clickArgs.aZ() + theta;
550 const bool clockwise = (theta <= M_PI && theta >= 0) || (theta < -
M_PI);
551 shortestDistance = clockwise ? shortestDistance : shortestDistance * -1;
553 m_d->currentArgs.setAZ(
m_d->clickArgs.aZ() + shortestDistance);
558 QPointF newRotationCenter = t.map(
m_d->currentArgs.originalCenter() +
m_d->currentArgs.rotationCenterOffset());
559 QPointF oldRotationCenter = clickT.map(
m_d->clickArgs.originalCenter() +
m_d->clickArgs.rotationCenterOffset());
561 m_d->currentArgs.setTransformedCenter(
m_d->currentArgs.transformedCenter() + oldRotationCenter - newRotationCenter);
566 QPointF diff = mousePos -
m_d->clickPos;
567 double thetaX = - diff.y() *
M_PI /
m_d->transaction.originalHalfHeight() / 2 / fabs(
m_d->currentArgs.scaleY());
570 qreal
sign = qAbs(
m_d->currentArgs.aX() -
M_PI) <
M_PI / 2 ? -1.0 : 1.0;
571 double thetaY =
sign * diff.x() *
M_PI /
m_d->transaction.originalHalfWidth() / 2 / fabs(
m_d->currentArgs.scaleX());
576 QPointF newRotationCenter = t.map(
m_d->currentArgs.originalCenter() +
m_d->currentArgs.rotationCenterOffset());
580 QPointF oldRotationCenter = clickT.map(
m_d->clickArgs.originalCenter() +
m_d->clickArgs.rotationCenterOffset());
582 m_d->currentArgs.setTransformedCenter(
m_d->currentArgs.transformedCenter() + oldRotationCenter - newRotationCenter);
590 if (
m_d->function == TOPSCALE) {
591 staticPoint =
m_d->boundsTransform.map(bottomMiddle(
m_d->bounds));
592 movingPoint =
m_d->boundsTransform.map(topMiddle(
m_d->bounds));
594 staticPoint =
m_d->boundsTransform.map(topMiddle(
m_d->bounds));
595 movingPoint =
m_d->boundsTransform.map(bottomMiddle(
m_d->bounds));
598 QPointF staticPointInView =
m_d->clickTransform.map(staticPoint);
599 const QPointF movingPointInView =
m_d->clickTransform.map(movingPoint);
601 const QPointF projNormVector =
604 const qreal projLength =
607 const QPointF targetMovingPointInView = staticPointInView + projNormVector * projLength;
610 if ((
m_d->clickArgs.transformAroundRotationCenter() ^ altModifierActive) &&
611 !qFuzzyCompare(anchorPoint.y(), movingPoint.y())) {
613 staticPoint = anchorPoint;
614 staticPointInView =
m_d->clickTransform.map(staticPoint);
622 targetMovingPointInView);
628 if (shiftModifierActive ||
m_d->currentArgs.keepAspectRatio()) {
629 qreal aspectRatio =
m_d->clickArgs.scaleX() /
m_d->clickArgs.scaleY();
630 m_d->currentArgs.setScaleX(aspectRatio * result.
scale);
633 m_d->currentArgs.setScaleY(result.
scale);
643 if (
m_d->function == LEFTSCALE) {
644 staticPoint =
m_d->boundsTransform.map(middleRight(
m_d->bounds));
645 movingPoint =
m_d->boundsTransform.map(middleLeft(
m_d->bounds));
647 staticPoint =
m_d->boundsTransform.map(middleLeft(
m_d->bounds));
648 movingPoint =
m_d->boundsTransform.map(middleRight(
m_d->bounds));
651 QPointF staticPointInView =
m_d->clickTransform.map(staticPoint);
652 const QPointF movingPointInView =
m_d->clickTransform.map(movingPoint);
654 const QPointF projNormVector =
657 const qreal projLength =
660 const QPointF targetMovingPointInView = staticPointInView + projNormVector * projLength;
663 if ((
m_d->currentArgs.transformAroundRotationCenter() ^ altModifierActive) &&
664 !qFuzzyCompare(anchorPoint.x(), movingPoint.x())) {
666 staticPoint = anchorPoint;
667 staticPointInView =
m_d->clickTransform.map(staticPoint);
675 targetMovingPointInView);
681 if (shiftModifierActive ||
m_d->currentArgs.keepAspectRatio()) {
682 qreal aspectRatio =
m_d->clickArgs.scaleY() /
m_d->clickArgs.scaleX();
683 m_d->currentArgs.setScaleY(aspectRatio * result.
scale);
686 m_d->currentArgs.setScaleX(result.
scale);
691 case BOTTOMRIGHTSCALE:
693 case BOTTOMLEFTSCALE: {
697 if (
m_d->function == TOPRIGHTSCALE) {
698 staticPoint =
m_d->boundsTransform.map(
m_d->bounds.bottomLeft());
699 movingPoint =
m_d->boundsTransform.map(
m_d->bounds.topRight());
700 }
else if (
m_d->function == BOTTOMRIGHTSCALE) {
701 staticPoint =
m_d->boundsTransform.map(
m_d->bounds.topLeft());
702 movingPoint =
m_d->boundsTransform.map(
m_d->bounds.bottomRight());
703 }
else if (
m_d->function == TOPLEFTSCALE) {
704 staticPoint =
m_d->boundsTransform.map(
m_d->bounds.bottomRight());
705 movingPoint =
m_d->boundsTransform.map(
m_d->bounds.topLeft());
707 staticPoint =
m_d->boundsTransform.map(
m_d->bounds.topRight());
708 movingPoint =
m_d->boundsTransform.map(
m_d->bounds.bottomLeft());
712 if ((
m_d->currentArgs.transformAroundRotationCenter() ^ altModifierActive) &&
713 !(qFuzzyCompare(anchorPoint.x(), movingPoint.x()) ||
714 qFuzzyCompare(anchorPoint.y(), movingPoint.y()))) {
716 staticPoint = anchorPoint;
719 QPointF staticPointInView =
m_d->clickTransform.map(staticPoint);
720 QPointF movingPointInView = mousePos;
722 if (shiftModifierActive ||
m_d->currentArgs.keepAspectRatio()) {
723 QPointF refDiff =
m_d->clickTransform.map(movingPoint) - staticPointInView;
724 QPointF realDiff = mousePos - staticPointInView;
727 movingPointInView = staticPointInView + realDiff;
730 const bool isAffine =
748 m_d->currentArgs.setScaleX(result.
scaleX);
749 m_d->currentArgs.setScaleY(result.
scaleY);
758 if (altModifierActive) {
759 pt = (
m_d->boundsTransform *
m_d->transform).inverted().map(mousePos);
761 pt =
m_d->boundsTransform.map(pt);
763 pt =
m_d->transform.inverted().map(mousePos);
766 QPointF newRotationCenterOffset = pt -
m_d->currentArgs.originalCenter();
768 if (shiftModifierActive) {
769 if (qAbs(newRotationCenterOffset.x()) > qAbs(newRotationCenterOffset.y())) {
770 newRotationCenterOffset.ry() = 0;
772 newRotationCenterOffset.rx() = 0;
776 m_d->currentArgs.setRotationCenterOffset(newRotationCenterOffset);
784 QPointF oldStaticPoint = m.
finalTransform().map(
m_d->clickArgs.originalCenter() +
m_d->clickArgs.rotationCenterOffset());
786 QTransform backwardT = (m.
S * m.
projectedP).inverted();
787 QPointF diff = backwardT.map(mousePos -
m_d->clickPos);
789 qreal
sign =
m_d->function == BOTTOMSHEAR ? 1.0 : -1.0;
792 qreal dx =
sign *
m_d->clickArgs.shearX() *
m_d->clickArgs.scaleY() * (
m_d->bounds.height() / 2.0);
796 m_d->currentArgs.setShearX(
sign * dx /
m_d->currentArgs.scaleY() / (
m_d->bounds.height() / 2.0));
800 QPointF newStaticPoint = t.map(
m_d->clickArgs.originalCenter() +
m_d->clickArgs.rotationCenterOffset());
801 m_d->currentArgs.setTransformedCenter(
m_d->currentArgs.transformedCenter() + oldStaticPoint - newStaticPoint);
809 QPointF oldStaticPoint = m.
finalTransform().map(
m_d->clickArgs.originalCenter() +
m_d->clickArgs.rotationCenterOffset());
811 QTransform backwardT = (m.
S * m.
projectedP).inverted();
812 QPointF diff = backwardT.map(mousePos -
m_d->clickPos);
814 qreal
sign =
m_d->function == RIGHTSHEAR ? 1.0 : -1.0;
817 qreal dy =
sign *
m_d->clickArgs.shearY() *
m_d->clickArgs.scaleX() * (
m_d->bounds.width() / 2.0);
821 m_d->currentArgs.setShearY(
sign * dy /
m_d->clickArgs.scaleX() / (
m_d->bounds.width() / 2.0));
825 QPointF newStaticPoint = t.map(
m_d->clickArgs.originalCenter() +
m_d->clickArgs.rotationCenterOffset());
826 m_d->currentArgs.setTransformedCenter(
m_d->currentArgs.transformedCenter() + oldStaticPoint - newStaticPoint);
831 m_d->recalculateTransformations();