emacs-devel
[Top][All Lists]

Re: Image transformations

 From: Richard Copley Subject: Re: Image transformations Date: Thu, 13 Jun 2019 20:00:49 +0100

On Thu, 13 Jun 2019 at 18:57, Eli Zaretskii <address@hidden> wrote:

> From: Alp Aker <address@hidden>
> Date: Thu, 13 Jun 2019 11:57:34 -0400
> Cc: Alan Third <address@hidden>, Emacs devel <address@hidden>
>
> > Maybe that's the problem: if the rotation is counter-clockwise, then
> > the translation should indeed be along the Y axis.
>
> The translation doesn't depend on the rotation in any way.

I think the final value of translation does depend on the rotation,
because the center of the image's position after the rotation depends
on the rotation angle.

> The general form of an affine transformation is F(x) + b, where F is
> a linear transformation (rotation, shear, scaling) and addition by b
> is translation.

Yes, but our transformation includes translation, rotation, and
another translation.  Not just one translation.  IOW, it isn't the
transformation matrix that is given; it's the operation on the image.

XRender uses homogeneous matrices. In this system a 3x3 projective matrix can
represent any affine transformation as one matrix. The matrix representing a
translation, then a rotation, then a translation, can then be calculated by
multiplying three matrices. (It is in fact again a rotation followed by a single
translation.)

The 9-coordinate homogeneous matrix can represent any projective transformation.
Simplifying to the case of affine transformations, the matrix is of the form

[Fxx  Fxy  Tx]
[Fyx  Fyy  Ty]
[  0    0   1]

Fij represent the scale/rotation/shear and Ti represent the translation.
Multiplying two matrices of this form gives another matrix of the same form.

To transform coordinates (X Y) you multiply the matrix (on the left) by
a column vector (on the right) as follows.

[Fxx  Fxy  Tx] [X]     [Fxx * X + Fxy * Y + Tz]
[Fyx  Fyy  Ty] [Y]  =  [Fyx * X + Fyy * Y + Ty]
[  0    0   1]      [                     1]

A pure translation goes like this:

[1   0  Tx] [X]   [X + Tx]
[0   1  Ty] [Y] = [Y + Ty]
[0   0   1]    [     1]

The transformation matrix surely depends on whether the rotation is
clockwise or counter-clockwise.

The origin is at the top left so a pure rotation clockwise about the origin
through angle a goes like this:

[cos(a)  -sin(a)  0] [X]   [cos(a) * X - sin(a) * Y]
[sin(a)   cos(a)  0] [Y] = [sin(a) * X + cos(a) * Y]
[     0        0  1]    [                      1]

To combine several transformations (e.g., to get a matrix that does a
transformation, then a rotation, then a transformation) you multiply the
matrices of the transformations together. The matrix for the last transformation
goes furthest left.

Anyway, until we agree on the equations that convert (x,y) into
(x',y'), it is IMO pointless to argue about details.  So can anyone
tell where the meaning of the matrix passed to XRender is described?

The documentation is here:
<https://www.x.org/releases/X11R7.7/doc/libXrender/libXrender.txt>

What is not specified is the memory layout of the matrix.
Some more details are here:
<http://www.talisman.org/~erlkonig/misc/x11-composite-tutorial/>.

From the tutorial, I guess the memory layout is

XTransform xform = {{
{ XDoubleToFixed(Fxx), XDoubleToFixed(Fyx), XDoubleToFixed(0) },
{ XDoubleToFixed(Fxy), XDoubleToFixed(Fyy), XDoubleToFixed(0) },
{ XDoubleToFixed(Tx),  XDoubleToFixed(Ty),  XDoubleToFixed(1) }
}};

It could equally be

XTransform xform = {{
{ XDoubleToFixed(Fxx), XDoubleToFixed(Fxy), XDoubleToFixed(Tx) },
{ XDoubleToFixed(Fyx), XDoubleToFixed(Fyy), XDoubleToFixed(Ty) },
{ XDoubleToFixed(0),   XDoubleToFixed(0),   XDoubleToFixed(1) }
}};

Someone can work out which through experimenation.

Here I have fixed three of the matrix entries to 0, 0, 1; this is the
simplification to the case of affine transformations only that I mentioned.
The full 3x3 matrix represents an arbitrary projective transformation.
We don't need that.

For example, the tutorial mentions representing a scale factor W as

[1   0   0 ]
[0   1   0 ]
[0   0  1/W]

which implies that there is a perspective-division step, the X and Y coordinates
being divided by the Z (depth) coordinate. I don't know at what stage of the
pipeline this happens. We can sidestep the issue by setting W = Z = 1 and
representing a scale factor of W using the matrix

[W   0   0]
[0   W   0]
[0   0   1]

reply via email to