200 Q_UNUSED(shiftModifierActive);
202 if (perspectiveModifierActive && !
m_d->transaction.shouldAvoidPerspectiveTransform()) {
203 m_d->function = PERSPECTIVE;
207 QTransform boundsFullTransform =
m_d->boundsTransform *
m_d->transform;
208 QPolygonF transformedPolygon = boundsFullTransform.map(QPolygonF(
m_d->bounds));
213 StrokeFunction defaultFunction;
214 if (transformedPolygon.containsPoint(mousePos, Qt::OddEvenFill))
215 defaultFunction =
MOVE;
216 else if (
m_d->transaction.boundsRotationAllowed() && altModifierActive)
217 defaultFunction = ROTATEBOUNDS;
219 defaultFunction = ROTATE;
221 handleChooser(mousePos, defaultFunction);
224 handleRadius, TOPSCALE);
226 handleRadius, TOPRIGHTSCALE);
228 handleRadius, RIGHTSCALE);
231 handleRadius, BOTTOMRIGHTSCALE);
233 handleRadius, BOTTOMSCALE);
235 handleRadius, BOTTOMLEFTSCALE);
237 handleRadius, LEFTSCALE);
239 handleRadius, TOPLEFTSCALE);
241 rotationHandleRadius, MOVECENTER);
245 if (
m_d->function == ROTATE ||
m_d->function ==
MOVE) {
247 QPointF t = boundsFullTransform.inverted().map(mousePos);
249 if (t.x() >=
bounds.left() && t.x() <=
bounds.right()) {
250 if (fabs(t.y() -
bounds.top()) <= handleRadius)
251 m_d->function = TOPSHEAR;
252 if (fabs(t.y() -
bounds.bottom()) <= handleRadius)
253 m_d->function = BOTTOMSHEAR;
255 if (t.y() >=
bounds.top() && t.y() <=
bounds.bottom()) {
256 if (fabs(t.x() -
bounds.left()) <= handleRadius)
257 m_d->function = LEFTSHEAR;
258 if (fabs(t.x() -
bounds.right()) <= handleRadius)
259 m_d->function = RIGHTSHEAR;
451 bool shiftModifierActive,
452 bool altModifierActive)
457 m_d->isTransforming =
true;
458 const QPointF anchorPoint =
m_d->clickArgs.originalCenter() +
m_d->clickArgs.rotationCenterOffset();
460 switch (
m_d->function) {
462 QPointF diff = mousePos -
m_d->clickPos;
464 if (shiftModifierActive) {
468 QPointF originalDiff = t.inverted().map(diff);
470 if (qAbs(originalDiff.x()) >= qAbs(originalDiff.y())) {
471 originalDiff.setY(0);
473 originalDiff.setX(0);
476 diff = t.map(originalDiff);
480 m_d->currentArgs.setTransformedCenter(
m_d->clickArgs.transformedCenter() + diff);
489 const QPointF rotationCenter =
m_d->clickArgs.originalCenter() +
m_d->clickArgs.rotationCenterOffset();
490 const QPointF clickMouseImagePos = clickT.inverted().map(
m_d->clickPos) - rotationCenter;
491 const QPointF mouseImagePosClickSpace = clickT.inverted().map(mousePos) - rotationCenter;
493 const qreal a1 = atan2(clickMouseImagePos.y(), clickMouseImagePos.x());
494 const qreal a2 = atan2(mouseImagePosClickSpace.y(), mouseImagePosClickSpace.x());
496 const qreal theta = a2 - a1;
497 m_d->currentArgs.setBoundsRotation(
m_d->clickArgs.boundsRotation() + theta);
500 QTransform newBR; newBR.rotateRadians(
m_d->currentArgs.boundsRotation());
501 QTransform clickZ; clickZ.rotateRadians(
m_d->clickArgs.aZ());
504 QTransform desired = newBR * clickM.
BRI * clickM.
SC * clickM.
S * clickZ;
510 m_d->currentArgs.setShearY(0);
528 const QPointF rotationCenter =
m_d->clickArgs.originalCenter() +
m_d->clickArgs.rotationCenterOffset();
529 const QPointF clickMouseImagePos = clickT.inverted().map(
m_d->clickPos) - rotationCenter;
530 const QPointF mouseImagePosClickSpace = clickT.inverted().map(mousePos) - rotationCenter;
532 const qreal a1 = atan2(clickMouseImagePos.y(), clickMouseImagePos.x());
533 const qreal a2 = atan2(mouseImagePosClickSpace.y(), mouseImagePosClickSpace.x());
542 if (shiftModifierActive) {
543 const qreal snapAngle = M_PI_4 / 6.0;
544 qint32 thetaIndex =
static_cast<qint32
>((theta / snapAngle) + 0.5);
545 m_d->currentArgs.setAZ(thetaIndex * snapAngle);
548 const qreal clickAngle =
m_d->clickArgs.aZ();
549 const qreal targetAngle =
m_d->clickArgs.aZ() + theta;
551 const bool clockwise = (theta <= M_PI && theta >= 0) || (theta < -
M_PI);
552 shortestDistance = clockwise ? shortestDistance : shortestDistance * -1;
554 m_d->currentArgs.setAZ(
m_d->clickArgs.aZ() + shortestDistance);
559 QPointF newRotationCenter = t.map(
m_d->currentArgs.originalCenter() +
m_d->currentArgs.rotationCenterOffset());
560 QPointF oldRotationCenter = clickT.map(
m_d->clickArgs.originalCenter() +
m_d->clickArgs.rotationCenterOffset());
562 m_d->currentArgs.setTransformedCenter(
m_d->currentArgs.transformedCenter() + oldRotationCenter - newRotationCenter);
567 QPointF diff = mousePos -
m_d->clickPos;
568 double thetaX = - diff.y() *
M_PI /
m_d->transaction.originalHalfHeight() / 2 / fabs(
m_d->currentArgs.scaleY());
571 qreal
sign = qAbs(
m_d->currentArgs.aX() -
M_PI) <
M_PI / 2 ? -1.0 : 1.0;
572 double thetaY =
sign * diff.x() *
M_PI /
m_d->transaction.originalHalfWidth() / 2 / fabs(
m_d->currentArgs.scaleX());
577 QPointF newRotationCenter = t.map(
m_d->currentArgs.originalCenter() +
m_d->currentArgs.rotationCenterOffset());
581 QPointF oldRotationCenter = clickT.map(
m_d->clickArgs.originalCenter() +
m_d->clickArgs.rotationCenterOffset());
583 m_d->currentArgs.setTransformedCenter(
m_d->currentArgs.transformedCenter() + oldRotationCenter - newRotationCenter);
591 if (
m_d->function == TOPSCALE) {
592 staticPoint =
m_d->boundsTransform.map(bottomMiddle(
m_d->bounds));
593 movingPoint =
m_d->boundsTransform.map(topMiddle(
m_d->bounds));
595 staticPoint =
m_d->boundsTransform.map(topMiddle(
m_d->bounds));
596 movingPoint =
m_d->boundsTransform.map(bottomMiddle(
m_d->bounds));
599 QPointF staticPointInView =
m_d->clickTransform.map(staticPoint);
600 const QPointF movingPointInView =
m_d->clickTransform.map(movingPoint);
602 const QPointF projNormVector =
605 const qreal projLength =
608 const QPointF targetMovingPointInView = staticPointInView + projNormVector * projLength;
611 if ((
m_d->clickArgs.transformAroundRotationCenter() ^ altModifierActive) &&
612 !qFuzzyCompare(anchorPoint.y(), movingPoint.y())) {
614 staticPoint = anchorPoint;
615 staticPointInView =
m_d->clickTransform.map(staticPoint);
623 targetMovingPointInView);
629 if (shiftModifierActive ||
m_d->currentArgs.keepAspectRatio()) {
630 qreal aspectRatio =
m_d->clickArgs.scaleX() /
m_d->clickArgs.scaleY();
631 m_d->currentArgs.setScaleX(aspectRatio * result.
scale);
634 m_d->currentArgs.setScaleY(result.
scale);
644 if (
m_d->function == LEFTSCALE) {
645 staticPoint =
m_d->boundsTransform.map(middleRight(
m_d->bounds));
646 movingPoint =
m_d->boundsTransform.map(middleLeft(
m_d->bounds));
648 staticPoint =
m_d->boundsTransform.map(middleLeft(
m_d->bounds));
649 movingPoint =
m_d->boundsTransform.map(middleRight(
m_d->bounds));
652 QPointF staticPointInView =
m_d->clickTransform.map(staticPoint);
653 const QPointF movingPointInView =
m_d->clickTransform.map(movingPoint);
655 const QPointF projNormVector =
658 const qreal projLength =
661 const QPointF targetMovingPointInView = staticPointInView + projNormVector * projLength;
664 if ((
m_d->currentArgs.transformAroundRotationCenter() ^ altModifierActive) &&
665 !qFuzzyCompare(anchorPoint.x(), movingPoint.x())) {
667 staticPoint = anchorPoint;
668 staticPointInView =
m_d->clickTransform.map(staticPoint);
676 targetMovingPointInView);
682 if (shiftModifierActive ||
m_d->currentArgs.keepAspectRatio()) {
683 qreal aspectRatio =
m_d->clickArgs.scaleY() /
m_d->clickArgs.scaleX();
684 m_d->currentArgs.setScaleY(aspectRatio * result.
scale);
687 m_d->currentArgs.setScaleX(result.
scale);
692 case BOTTOMRIGHTSCALE:
694 case BOTTOMLEFTSCALE: {
698 if (
m_d->function == TOPRIGHTSCALE) {
699 staticPoint =
m_d->boundsTransform.map(
m_d->bounds.bottomLeft());
700 movingPoint =
m_d->boundsTransform.map(
m_d->bounds.topRight());
701 }
else if (
m_d->function == BOTTOMRIGHTSCALE) {
702 staticPoint =
m_d->boundsTransform.map(
m_d->bounds.topLeft());
703 movingPoint =
m_d->boundsTransform.map(
m_d->bounds.bottomRight());
704 }
else if (
m_d->function == TOPLEFTSCALE) {
705 staticPoint =
m_d->boundsTransform.map(
m_d->bounds.bottomRight());
706 movingPoint =
m_d->boundsTransform.map(
m_d->bounds.topLeft());
708 staticPoint =
m_d->boundsTransform.map(
m_d->bounds.topRight());
709 movingPoint =
m_d->boundsTransform.map(
m_d->bounds.bottomLeft());
713 if ((
m_d->currentArgs.transformAroundRotationCenter() ^ altModifierActive) &&
714 !(qFuzzyCompare(anchorPoint.x(), movingPoint.x()) ||
715 qFuzzyCompare(anchorPoint.y(), movingPoint.y()))) {
717 staticPoint = anchorPoint;
720 QPointF staticPointInView =
m_d->clickTransform.map(staticPoint);
721 QPointF movingPointInView = mousePos;
723 if (shiftModifierActive ||
m_d->currentArgs.keepAspectRatio()) {
724 QPointF refDiff =
m_d->clickTransform.map(movingPoint) - staticPointInView;
725 QPointF realDiff = mousePos - staticPointInView;
728 movingPointInView = staticPointInView + realDiff;
731 const bool isAffine =
749 m_d->currentArgs.setScaleX(result.
scaleX);
750 m_d->currentArgs.setScaleY(result.
scaleY);
759 if (altModifierActive) {
760 pt = (
m_d->boundsTransform *
m_d->transform).inverted().map(mousePos);
762 pt =
m_d->boundsTransform.map(pt);
764 pt =
m_d->transform.inverted().map(mousePos);
767 QPointF newRotationCenterOffset = pt -
m_d->currentArgs.originalCenter();
769 if (shiftModifierActive) {
770 if (qAbs(newRotationCenterOffset.x()) > qAbs(newRotationCenterOffset.y())) {
771 newRotationCenterOffset.ry() = 0;
773 newRotationCenterOffset.rx() = 0;
777 m_d->currentArgs.setRotationCenterOffset(newRotationCenterOffset);
785 QPointF oldStaticPoint = m.
finalTransform().map(
m_d->clickArgs.originalCenter() +
m_d->clickArgs.rotationCenterOffset());
787 QTransform backwardT = (m.
S * m.
projectedP).inverted();
788 QPointF diff = backwardT.map(mousePos -
m_d->clickPos);
790 qreal
sign =
m_d->function == BOTTOMSHEAR ? 1.0 : -1.0;
793 qreal dx =
sign *
m_d->clickArgs.shearX() *
m_d->clickArgs.scaleY() * (
m_d->bounds.height() / 2.0);
797 m_d->currentArgs.setShearX(
sign * dx /
m_d->currentArgs.scaleY() / (
m_d->bounds.height() / 2.0));
801 QPointF newStaticPoint = t.map(
m_d->clickArgs.originalCenter() +
m_d->clickArgs.rotationCenterOffset());
802 m_d->currentArgs.setTransformedCenter(
m_d->currentArgs.transformedCenter() + oldStaticPoint - newStaticPoint);
810 QPointF oldStaticPoint = m.
finalTransform().map(
m_d->clickArgs.originalCenter() +
m_d->clickArgs.rotationCenterOffset());
812 QTransform backwardT = (m.
S * m.
projectedP).inverted();
813 QPointF diff = backwardT.map(mousePos -
m_d->clickPos);
815 qreal
sign =
m_d->function == RIGHTSHEAR ? 1.0 : -1.0;
818 qreal dy =
sign *
m_d->clickArgs.shearY() *
m_d->clickArgs.scaleX() * (
m_d->bounds.width() / 2.0);
822 m_d->currentArgs.setShearY(
sign * dy /
m_d->clickArgs.scaleX() / (
m_d->bounds.width() / 2.0));
826 QPointF newStaticPoint = t.map(
m_d->clickArgs.originalCenter() +
m_d->clickArgs.rotationCenterOffset());
827 m_d->currentArgs.setTransformedCenter(
m_d->currentArgs.transformedCenter() + oldStaticPoint - newStaticPoint);
832 m_d->recalculateTransformations();