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.
Step1. Reorganize your data a bit. Let us store the coordinates $(x_j, y_j)$ of the vertices of the polygon your points in a $2 \times n$ array called $P$, like this
$$ P =
\begin{bmatrix}
x_1 & x_2 & x_{3} & \dots & x_{n} \\
y_1 & y_2 & y_{3} & \dots & y_{n} \\
\end{bmatrix}$$
Step2. Compute the centroid $(a,b)$ that you need. If you are looking for the centroid of the vertices of the polygon you can do it as follows
$$\begin{bmatrix}
a \\
b \\
\end{bmatrix} = \frac{1}{n} \, \left( \, \, \begin{bmatrix}
x_1 \\
y_1 \\
\end{bmatrix} + \begin{bmatrix}
x_2 \\
y_2 \\
\end{bmatrix} + \begin{bmatrix}
x_3 \\
y_3 \\
\end{bmatrix} + ... + \begin{bmatrix}
x_n \\
y_n \\
\end{bmatrix} \, \, \right)$$
Note that there are various notions of centroid, depending on how you view your polygon -- a finite set of mass-points, a frame (a set of points and struts) or as a whole object with equally distributed mass inside the polygon. You can check the formulas on the net.
Step 3. Fill up another $2 \times n$ array
$$ C =
\begin{bmatrix}
a & a & a & \dots & a \\
b & b & b & \dots & b \\
\end{bmatrix}$$
Step 4. Define the $2 \times 2$ rotation matrix of angle $\theta$ (the angle of rotation you choose)
$$ R =
\begin{bmatrix}
\cos{\theta} & - \sin{\theta} \\
\sin{\theta} & \cos{\theta} \\
\end{bmatrix}$$
Step 5. The rotated polygon around the centroid $(a,b)$ with rotation angle $\theta$ as follows
$$P_{new} = R\cdot \left( P - C \right) + C$$
where $\,\, \cdot \,\,$ is matrix multiplication and $-$ and $+$ are matrix subtraction and addition (basically component-wise).
$P_{new}$ contains the vertices of the rotated polygon.
import numpy as np
def R(angle):
cos_a = np.cos(angle)
sin_a = np.sin(angle)
return np.array([[cos_a, -sin_a],
[sin_a, cos_a]])
def rotate(poly, angle, Center):
poly_new = (poly - Center).dot(R(angle).T) + Center
return poly_new
def organize(poly):
P = np.empty(( len(poly), 2), dtype=float)
for i in range(len(poly)):
P[i,0] = poly[i]['x']
P[i,1] = poly[i]['y']
return P
Poly = [{"x":301.1848472789287,"y":216.523742955658},
{"x":299.92410285162424,"y":241.37037128550003},
{"x":296.227787218953,"y":264.523742955658},
{"x":290.347798182831,"y":284.40599394956655},
{"x":282.68484727892877,"y":299.6621817189641},
{"x":273.761151947722,"y":309.25262227940857},
{"x":264.18484727892877,"y":312.523742955658},
{"x":254.60854261013552,"y":309.25262227940857},
{"x":245.6848472789288,"y":299.6621817189641},
{"x":238.02189637502653,"y":284.40599394956655},
{"x":232.14190733890456,"y":264.523742955658},
{"x":228.44559170623327,"y":241.37037128550003},
{"x":227.1848472789288,"y":216.52374295565804},
{"x":228.44559170623327,"y":191.67711462581605},
{"x":232.14190733890456,"y":168.52374295565807},
{"x":238.02189637502653,"y":148.64149196174952},
{"x":245.68484727892877,"y":133.38530419235195},
{"x":254.60854261013552,"y":123.79486363190748},
{"x":264.18484727892877,"y":120.52374295565804},
{"x":273.761151947722,"y":123.79486363190746},
{"x":282.68484727892877,"y":133.38530419235192},
{"x":290.347798182831,"y":148.64149196174947},
{"x":296.2277872189529,"y":168.52374295565798},
{"x":299.92410285162424,"y":191.67711462581596}]
P = organize(Poly)
Cntr = np.array([0., 0.])
P_new = rotate(P, np.pi/3, Cntr)
Best Answer
As you state in your question, you require the transformation matrix. You will need the concept of homogeneous coordinates to perform the translation components in matrix form. You also need to know how to construct a rotation matrix and scaling matrix in two dimensions.
Rotation and scaling matrices are usually defined around the origin. To perform these transformations about an arbitrary point, you would translate the point about which the transformation is to occur to the origin, perform the transformation as normal, and then undo the translation. This process is then repeated for each transformation required.
The counter-clockwise rotation of a point $p=(x,y)$ to its image $p^\prime$ by an angle of $\theta$ around the point $(a,b)$ is $$ p^\prime=Rp=\overbrace{\underbrace{\begin{bmatrix}1&0&a\\0&1&b\\0&0&1\end{bmatrix}}_{\text{Translate back}} \underbrace{\begin{bmatrix}\cos\theta&-\sin\theta&0\\\sin\theta&\cos\theta&0\\0&0&1\end{bmatrix}}_{\text{Normal rotation matrix}} \underbrace{\begin{bmatrix}1&0&-a\\0&1&-b\\0&0&1\end{bmatrix}}_{\text{Translate}}}^{\text{Complete rotation matrix $R$}} \underbrace{\begin{bmatrix}x\\y\\1\end{bmatrix}}_{p}. $$
Similarly, to scale a point $p=(x,y)$ to its image $p^\prime$ in the $x$ direction by $s_x$ and $y$ direction by $s_y$ from the point $(a,b)$ is $$ p^\prime=Sp=\overbrace{\underbrace{\begin{bmatrix}1&0&a\\0&1&b\\0&0&1\end{bmatrix}}_{\text{Translate back}} \underbrace{\begin{bmatrix}s_x&0&0\\0&s_y&0\\0&0&1\end{bmatrix}}_{\text{Normal scalingmatrix}} \underbrace{\begin{bmatrix}1&0&-a\\0&1&-b\\0&0&1\end{bmatrix}}_{\text{Translate}}}^{\text{Complete scaling matrix $S$}} \underbrace{\begin{bmatrix}x\\y\\1\end{bmatrix}}_{p}. $$
The combined transformation matrix I will denote $T$ to perform the complete transformation will be either $T=SR$, if the rotation is performed first, followed by the scaling, or $T=RS$, if the scaling is performed first, followed by the rotation. The complete transformation of a point $p$ to its image $p^\prime$ is then $p^\prime=Tp$.
Edit: In response to comments below, the point about which the transformation is performed can give different resulting outcomes. Compare scaling the rectangle with bounding box $(2,2)$, $(4,6)$ by a factor of $2$ about the points $(4,6)$ and $(3,5)$. The distances from the scaled point are doubled, which produces the same size rectangle, but it is positioned differently as the centre of the transformation was different.
Result from scaling the rectangle about the point $(4,6)$
Result from scaling the rectangle about the point $(3,5)$