1
$\begingroup$

I am trying to find the amount to move an object so that, when it rotates and resizes, the resize would be smooth.

I have a Qt program, where I have to rotate objects around center, and resize based on top left anchor.
Unfortunately, built-in transformations combine anchors, so I can either do both transformations around center, or top left, or any unique point.

The item coordinates are based on top-left corner. To perform operations around center, I translate item by cx, cy, perform rotation, translate by -cx, -cy.

The transform used by the program is calculated by multiplying scale, then rotation then translation, is I think:

$$ t= \begin{bmatrix} sx & 0 & 0 \\ 0 & sy & 0 \\ 0 & 0 & 1 \\ \end{bmatrix} . \begin{bmatrix} cos(\theta) & sin(\theta) & 0 \\ -sin(\theta) & cos(\theta) & 0 \\ 0 & 0 & 1 \\ \end{bmatrix} . \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ tx & ty & 1 \\ \end{bmatrix} $$

(Based on documentation ... $$ t= \begin{bmatrix} scaleX& shearX & projX \\ shearY & scaleY & projY \\ transX & transY & 1 \\ \end{bmatrix} $$ )

To rotate around center, I translate item to its (scaled) center, rotate, translate back, then resize. The result is correct, but the item appears to move.

After much struggle, I came to the solution that I have to adjust the item position on resize (or include the shift in the transform, but seems a position change is better since it allows the user to revert it).
I just can't figure out by how much.

I have tried to determine the item top-left coordinates before the resize, apply the transformation (which involves replacing current item transform with the transform that has the new parameters), determine the item top-left coordinates again, and shift by the change. The result was... horrific. Item still moves on resize after rotate, but the rotation anchor changed to bottom-right... I don't understand why. (I have tried many other ways to offset the move, none worked).

Assume a rectangular object that has been rotated (perhaps also initially resized), around its center. (in image, the green text). If I resize it, I would like to keep the top left point fixed (like the blue text).
Because of the fact that the transformations are compounded, creating a transformation containing resize and rotation would first resize (yellow text) and then rotate around the new center - resulting in the red text.
Visually, there is a jump on resizing a rotated text...

enter image description here
Legend: green = initial, blue = desired, red = actual, yellow = intermediate step to get red

Note - I cannot apply rotation ater resize, because the way transforms work, I would end up with a skewed object if my scaling factors on x and y are different:

enter image description here

So, my only option is to determine the shift between the previously rotated (and perhaps stretched) item top left, and the resulting stretched item top left points.

How can I determine the dx and dy difference between the two points ? (in first image, top left of green text and top left of red text)

I have seen questions that seem similar, but they attempt transformation around a unique anchor and have identical x and y scale factors... It is the anchor change that gives me headaches.

Edit - I found a temporary solution - I am storing the "old" t31 and t32, and adjusting position by the difference between the "old" and "new" values.
I would prefer calculated values, since knowledge of the "old" item introduces more complications...

$\endgroup$
  • $\begingroup$ But at the beginning is your object horizontal? If not I don't understand why the yellow text is horizontal. $\endgroup$ – Aretino Sep 24 '15 at 16:41
  • $\begingroup$ @Aretino The yellow text shows how the transformation is applied to get between any intermediate position and the final - first scales, then rotates around the center of the scaled item - I only posted to show the center of rotation change. $\endgroup$ – Thalia Sep 24 '15 at 16:43
  • $\begingroup$ All objects start non-scaled non-rotated, there may be an unknown number of transformations applied at any time. Rotation doesn't give me trouble though - it is the scaled of a rotated (and maybe stretched) item that gives problem $\endgroup$ – Thalia Sep 24 '15 at 16:44
  • $\begingroup$ "First scales…" but if the result is horizontal I presume the text was horizontal even before scaling. $\endgroup$ – Aretino Sep 24 '15 at 16:44
  • $\begingroup$ Assume the input is the green text, and desired output, the blue text $\endgroup$ – Thalia Sep 24 '15 at 16:45
1
$\begingroup$

If you begin with a horizontal object whose initial dimensions are $L_x$ and $L_y$ (before scaling), then the offset between blue and red text should be $$ \begin{align} &\Delta x={K_x-1\over2}L_x(1-\cos\alpha)+{K_y-1\over2}L_y\sin\alpha,\cr &\Delta y=-{K_y-1\over2}L_y(1-\cos\alpha)+{K_x-1\over2}L_x\sin\alpha,\cr \end{align} $$ where $\alpha$ is the rotation angle with respect to the horizontal and $K_x$, $K_y$ are the scaling factors.

The sign of $\Delta x$ and $\Delta y$ depends on how you measure $\alpha$, so you may need to find the correct sign by trial and error. Hope that helps.

EDIT

To show how those formulas can be derived, consider the black rectangle in the diagram below. Scaling it (with respect to up-left vertex $P$) and then rotating around the center $O'$ of the scaled rectangle yields a final brown rectangle, whose up-left vertex is $P'$.

If the black rectangle is first rotated around its center $O$ and then scaled with respect to $P''$, then we get instead the blue rectangle below. We are interested in finding the "offset" vector $\vec{P'P''}$.

If we denote by $R$ the rotation operator ($R(x,y)=(\cos\alpha x-\sin\alpha y, \cos\alpha y+\sin\alpha x)$, if positive angles represent a counterclockwise rotation) and by $S$ the scaling operator ($S(x,y)=(K_x x,K_y y)$), then we have:

$$ \vec{P'P''}=\vec{P'O'}+\vec{O'O}+\vec{OP''}= R\vec{PO'}+(S-1)\vec{OP}+R\vec{OP}= -R(S\vec{OP})+(S-1)\vec{OP}+R\vec{OP}, $$ that is: $$ \vec{P'P''}= (S-1)\vec{OP}-R(S-1)\vec{OP}. $$ Inserting here $\vec{OP}=(-L_x/2,L_y/2)$ one gets the desired result.

In comparing with my old formulas above, I see that $\vec{P'P''}=(-\Delta x,-\Delta y)$. In addition, I used there the opposite convention for the sign of the angle, but I hope this explanation is clear enough.

enter image description here

$\endgroup$
  • $\begingroup$ I'll try it, will the vertical offset be based on height change and sin alpha ? does this not depend on the length of the previous object ? $\endgroup$ – Thalia Sep 24 '15 at 17:11
  • $\begingroup$ I don't know what you mean by "height change": my formula is based on the width $L$ of the initial text and scaling factor $K$. See my edited answer. $\endgroup$ – Aretino Sep 24 '15 at 17:26
  • $\begingroup$ the scaling factors are different on x and y; the item state "before" is not necessarily with scale (1, 1) - it may have scaling applied just a different scale than the final element. I imagine the height, affected by a scaling factor on y, would just be added... $\endgroup$ – Thalia Sep 24 '15 at 17:32
  • $\begingroup$ I see… Then I'm afraid I'll have to adjust my answer. $\endgroup$ – Aretino Sep 24 '15 at 17:46
  • 1
    $\begingroup$ @EricB See my edited answer. $\endgroup$ – Aretino Mar 13 '17 at 18:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.