From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED.blaine.gmane.org!not-for-mail From: Richard Copley Newsgroups: gmane.emacs.devel Subject: Re: Image transformations Date: Thu, 13 Jun 2019 20:00:49 +0100 Message-ID: References: <9A21DE14-BB5F-426E-BBB2-19C87930E733@gnu.org> <20190611200233.GA80199@breton.holly.idiocy.org> <83imta95z0.fsf@gnu.org> <20190612220746.GA89208@breton.holly.idiocy.org> <835zpa11qp.fsf@gnu.org> <83pnnhzlcp.fsf@gnu.org> <83imt9zcbr.fsf@gnu.org> Mime-Version: 1.0 Content-Type: multipart/alternative; boundary="000000000000876c57058b392752" Injection-Info: blaine.gmane.org; posting-host="blaine.gmane.org:195.159.176.226"; logging-data="30616"; mail-complaints-to="usenet@blaine.gmane.org" Cc: Alp Aker , alan@idiocy.org, Emacs Development To: Eli Zaretskii Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Thu Jun 13 21:39:58 2019 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([209.51.188.17]) by blaine.gmane.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.89) (envelope-from ) id 1hbVZk-0007jc-CM for ged-emacs-devel@m.gmane.org; Thu, 13 Jun 2019 21:39:56 +0200 Original-Received: from localhost ([::1]:45100 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbVZj-0002if-EK for ged-emacs-devel@m.gmane.org; Thu, 13 Jun 2019 15:39:55 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:40909) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hbUyj-0005pY-Is for emacs-devel@gnu.org; Thu, 13 Jun 2019 15:01:43 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hbUyg-0005v1-SW for emacs-devel@gnu.org; Thu, 13 Jun 2019 15:01:40 -0400 Original-Received: from mail-ot1-x32d.google.com ([2607:f8b0:4864:20::32d]:39018) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1hbUya-0005fe-Hl; Thu, 13 Jun 2019 15:01:32 -0400 Original-Received: by mail-ot1-x32d.google.com with SMTP id r21so215904otq.6; Thu, 13 Jun 2019 12:01:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=+8lpkcqK5SVuVMnshMOctFm8METcYm2+N7GZn2ppN48=; b=lEt8l1Wnf00airJkk3Hqjxg8zZbBq1erS/LdeE/P8erAg3RbduafbhvBeSy4RbwtCh Ydj5iDjrPniqsjXM5RkgytmSLJPCpcXsbrtnD9/RmpJMlLkmctHgB+DCdLn/GExxCglo plYhC6E4VlhCEU6jNOTfR0QORJuSSRhrosNDKo4SDPSzRNtHVg9wM7mObueEW5SH/xfx VC87J17MiqGaic5FS1z2XNQOhxJQmPlDwE+mVE/2AJZ0ll0qYB13Td7gVDC4DpnjQQoo jMx2/9DiINUSCVBlPwUP703tfMMHSVA68XJwARe0nO88jIAieXB0rD8nUd31BnNEYON0 ZsGw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=+8lpkcqK5SVuVMnshMOctFm8METcYm2+N7GZn2ppN48=; b=IadLDuP5PbiGaChABzJBH0xEJDU2P1SoHCX7oHBZdPNegJ5o01+zsbxaoIbgUf7DPW AoumuIVOXZ4+ZETQbW5KqeGgzaFKjBW3hoITmBsbWiIWa5Kc1+mV+kJM6upBERGuvY2J U4zxT9piWfFCVBvsx9U4ebGtngLVukMpeMOemg7/MOWnZphFTPf7qd7tJcP7koutF2ba gostKFbupOmTtTekztIi9ow9bv1Uq7jQQSdZphd+X1TWcc84IV+3Kg0diJRb+d80oJpr SoxyTT3RIBULsLtRa8Eq3NH5pADYvgbalUzYplDW0/UwnNAvcxe02i8L9Jh+lBnfRRhI ek6Q== X-Gm-Message-State: APjAAAXvlqCydFQYTE+Liqp0zVejTukBxQ1tqqpi8ijKgFYW6jbt1YqK d8772RuxkRtfiR1rTIPBELvGVOygUVCn24wEA4OqL1qNvgc= X-Google-Smtp-Source: APXvYqynxybM4mRrEH6+sH5q7TPffuGdEcDAomsCxdsH9KLV7v6VQmgCw62QSRKvoMosu1LDLtF7AFNK7AyFSes3rg4= X-Received: by 2002:a9d:77c2:: with SMTP id w2mr2528984otl.192.1560452476135; Thu, 13 Jun 2019 12:01:16 -0700 (PDT) In-Reply-To: <83imt9zcbr.fsf@gnu.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::32d X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:237550 Archived-At: --000000000000876c57058b392752 Content-Type: text/plain; charset="UTF-8" On Thu, 13 Jun 2019 at 18:57, Eli Zaretskii wrote: > From: Alp Aker > Date: Thu, 13 Jun 2019 11:57:34 -0400 > Cc: Alan Third , Emacs devel > > > 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] [ 1] A pure translation goes like this: [1 0 Tx] [X] [X + Tx] [0 1 Ty] [Y] = [Y + Ty] [0 0 1] [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] [ 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: What is not specified is the memory layout of the matrix. Some more details are here: . >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] --000000000000876c57058b392752 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
On Thu, 13 Jun 2019 at 18:57, Eli Zaretskii <eliz@gnu.org> wrote:

=C2=A0 =C2=A0 >= From: Alp Aker <alptekin.ake= r@gmail.com>
=C2=A0 =C2=A0 > Date: Thu, 13 Jun 2019 11:57:34 -= 0400
=C2=A0 =C2=A0 > Cc: Alan Third <alan@idiocy.org>, Emacs devel <emacs-devel@gnu.org>
=C2=A0 =C2=A0 >
=C2=A0 =C2= =A0 > > Maybe that's the problem: if the rotation is counter-cloc= kwise, then
=C2=A0 =C2=A0 > > the translation should indeed be alo= ng the Y axis.
=C2=A0 =C2=A0 >
=C2=A0 =C2=A0 > The translation = doesn't depend on the rotation in any way.

=C2=A0 =C2=A0 I think= the final value of translation does depend on the rotation,
=C2=A0 =C2= =A0 because the center of the image's position after the rotation depen= ds
=C2=A0 =C2=A0 on the rotation angle.

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

=C2=A0 =C2=A0 Yes, but o= ur transformation includes translation, rotation, and
=C2=A0 =C2=A0 anot= her translation.=C2=A0 Not just one translation.=C2=A0 IOW, it isn't th= e
=C2=A0 =C2=A0 transformation matrix that is given; it's the operat= ion on the image.

XRender uses homogeneous matrices. In this system = a 3x3 projective matrix can
represent any affine transformation as one m= atrix. The matrix representing a
translation, then a rotation, then a tr= anslation, 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 =C2=A0Fxy =C2=A0Tx]
[Fyx =C2=A0Fyy =C2=A0Ty]
[ =C2= =A00 =C2=A0 =C2=A00 =C2=A0 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 righ= t) as follows.

[Fxx =C2=A0Fxy =C2=A0Tx] [X] =C2=A0 =C2=A0 [Fxx * X += Fxy * Y + Tz]
[Fyx =C2=A0Fyy =C2=A0Ty] [Y] =C2=A0=3D =C2=A0[Fyx * X + F= yy * Y + Ty]
[ =C2=A00 =C2=A0 =C2=A00 =C2=A0 1] [1] =C2=A0 =C2=A0 [ =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 1]
A pure translation goes like this:

[1 =C2=A0 0 =C2=A0Tx] [X] =C2= =A0 [X + Tx]
[0 =C2=A0 1 =C2=A0Ty] [Y] =3D [Y + Ty]
[0 =C2=A0 0 =C2= =A0 1] [1] =C2=A0 [ =C2=A0 =C2=A0 1]

=C2=A0 =C2=A0 The transformatio= n matrix surely depends on whether the rotation is
=C2=A0 =C2=A0 clockwi= se or counter-clockwise.

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

= [cos(a) =C2=A0-sin(a) =C2=A00] [X] =C2=A0 [cos(a) * X - sin(a) * Y]
[sin= (a) =C2=A0 cos(a) =C2=A00] [Y] =3D [sin(a) * X + cos(a) * Y]
[ =C2=A0 = =C2=A0 0 =C2=A0 =C2=A0 =C2=A0 =C2=A00 =C2=A01] [1] =C2=A0 [ =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A01]

To = combine several transformations (e.g., to get a matrix that does a
trans= formation, then a rotation, then a transformation) you multiply the
matr= ices of the transformations together. The matrix for the last transformatio= n
goes furthest left.

=C2=A0 =C2=A0 Anyway, until we agree on the= equations that convert (x,y) into
=C2=A0 =C2=A0 (x',y'), it is = IMO pointless to argue about details.=C2=A0 So can anyone
=C2=A0 =C2=A0 = 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 memo= ry layout of the matrix.
Some more details are here:
<http://www.t= alisman.org/~erlkonig/misc/x11-composite-tutorial/>.

From the= tutorial, I guess the memory layout is

XTransform xform =3D {{
= =C2=A0 { XDoubleToFixed(Fxx), XDoubleToFixed(Fyx), XDoubleToFixed(0) },
= =C2=A0 { XDoubleToFixed(Fxy), XDoubleToFixed(Fyy), XDoubleToFixed(0) },
= =C2=A0 { XDoubleToFixed(Tx), =C2=A0XDoubleToFixed(Ty), =C2=A0XDoubleToFixed= (1) }
}};

It could equally be

XTransform xform =3D {{
= =C2=A0 { XDoubleToFixed(Fxx), XDoubleToFixed(Fxy), XDoubleToFixed(Tx) },=C2=A0 { XDoubleToFixed(Fyx), XDoubleToFixed(Fyy), XDoubleToFixed(Ty) },=C2=A0 { XDoubleToFixed(0), =C2=A0 XDoubleToFixed(0), =C2=A0 XDoubleToFix= ed(1) }
}};

Someone can work out which through experimenation.
Here I have fixed three of the matrix entries to 0, 0, 1; this is the<= br>simplification to the case of affine transformations only that I mention= ed.
The full 3x3 matrix represents an arbitrary projective transformatio= n.
We don't need that.

For example, the tutorial mentions rep= resenting a scale factor W as

[1 =C2=A0 0 =C2=A0 0 ]
[0 =C2=A0 1 = =C2=A0 0 ]
[0 =C2=A0 0 =C2=A01/W]

which implies that there is a p= erspective-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 =3D Z =3D 1 and
represe= nting a scale factor of W using the matrix

[W =C2=A0 0 =C2=A0 0]
= [0 =C2=A0 W =C2=A0 0]
[0 =C2=A0 0 =C2=A0 1]
--000000000000876c57058b392752--