# How to apply a linear transformation to a parametrically-plotted disk with a texture?

Short version: I would like to apply a linear transformation to a parametrically-plotted surface with a texture and get an output with the correct texture.

First, I used ParametricPlot[ to plot the unit disk with a texture (in this case, the Wolfram Language logo):

ParametricPlot[{r Cos[t], r Sin[t]}, {t, 0, 2 Pi}, {r, 0, 1},
PlotStyle -> {Texture[Import["https://i.stack.imgur.com/Uqcj8.png"]],
Opacity[1]},TextureCoordinateFunction -> ({#1, #2} &)]


The output looks like this:

Next, I defined a simple linear transformation. In this case, just a counterclockwise rotation:

s0 = Pi/3
rot[s_] = {{Cos[s], -Sin[s]}, {Sin[s], Cos[s]}};


In theory, I should be able to apply this linear transformation to my unit disk and see the same image rotated by s = Pi/3 (with the texture correctly applied):

ParametricPlot[rot[s0].{r Cos[t], r Sin[t]}, {t, 0, 2 Pi}, {r, 0, 1}, PlotStyle -> {Texture[Import["https://tinyurl.com/y8t8r5fj"]], Opacity[1]}, TextureCoordinateFunction -> (rot[s0].{#1, #2} &), TextureCoordinateScaling -> True]


But instead I get the following:

It seems like I am applying the linear transformation correctly in the TextureCoordinateFunction, but somehow the TextureCoordinateScaling -> True option is not being applied.

Note: I know that there are ways of achieving the desired behavior using graphics primitives and Rotate[, but this is for a beginner-level linear algebra exploration so I want to use the machinery of linear algebra.

Update: While the example above only has a rotation, I'm hoping to appropriately transform the texture for any non-singular linear transformation. For example, I'm hoping to have the texture applied appropriately even if I replace rot[Pi/3] with rot[Pi/3].{{2, 0}, {0, 1}} (a scaling matrix and a rotation) or any matrix such as A = RandomReal[{-3,3},{2,2}] where det[A] is nonzero.

The top answer notes that the texture coordinate system scales coordinates to run from 0 to 1 when using TextureCoordinateScaling, so the clever fix for applying a rotation correctly is to translate from the texture coordinates system's center of (1/2,1/2) to the origin, perform the rotation, then translate back to (1/2,1/2). However, a scaling matrix will still cause problems even with the translation:

• As I said in my answer, you need to use TextureCoordinateFunction->(toTransform[Inverse[A]][{#1,#2}]&) so that the texture and the disk are transformed in the same way. – Carl Woll Oct 11 '17 at 4:10

The texture coordinate system runs from $(0, 1)$ for each coordinate when using TextureCoordinateScaling. To rotate the image, you need to rotate around the coordinate $(1/2, 1/2)$, not the origin. So, I think the following does what you want:

texture = Texture @ Import["https://tinyurl.com/y8t8r5fj"];
ParametricPlot[
{r Cos[t], r Sin[t]}, {t, 0, 2 Pi}, {r, 0, 1},
PlotStyle->{texture, Opacity[1]},
TextureCoordinateFunction->(RotationTransform[Pi/3, {1/2, 1/2}][{#1,#2}]&)
]


Update

The OP wants to use a matrix instead of a TransformationFunction. Here is a way to convert a matrix into a TransformationFunction suitable for transforming the texture:

toTransform[m_] := Composition[
TranslationTransform[{1/2,1/2}],
AffineTransform[m],
TranslationTransform[-{1/2,1/2}]
]


Here I use toTransform along with your rot function, where I've adjusted the direction of rotation so that the disk and the texture are rotated in the same direction.

ParametricPlot[
rot[Pi/3].{r Cos[t],r Sin[t]}, {t,0,2 Pi}, {r,0,1},
PlotStyle->{texture,Opacity[1]},
TextureCoordinateFunction->(toTransform[Inverse@rot[Pi/3]][{#1,#2}]&),
BoundaryStyle->None
]


Update 2

Here is the transformation matrix from the update to the question:

A = rot[Pi/3].{{2,0},{0,1}};


And here is the ParametricPlot using the transformation matrix A (note that the Inverse is used in the toTransform function so that the disk and the texture are both transformed in the same way):

ParametricPlot[
A . {r Cos[t], r Sin[t]}, {t,0,2 Pi}, {r,0,1},
PlotStyle->{texture,Opacity[1]},
TextureCoordinateFunction->(toTransform[Inverse@A][{#1,#2}]&),
BoundaryStyle->None
]


• And if you want to do it directly with the linear algebraic formulation, look at RotationTransform[Pi/3, {1/2, 1/2}] alone, which gives the correct matrix and translation-offset to use. – bill s Oct 10 '17 at 1:00
• Thank you! This is a great start. And it is certainly possible to do it directly with linear algebra with some homogeneous coordinates (i.imgur.com/DHUE1Yb.png). Unfortunately, I'm trying to get this working for any non-singular linear transformation, A. For example, I should be able to define A = RandomReal[{-3,3},{2,2}] as long as Det[A] does not equal 0. Any ideas for generalizing this technique with a fairly random looking linear transformation that can be decomposed into A = U.D.V* where U, V are unitary matrices, V* is the transpose of V and D is a scaling matrix? – WorfSonOfMogh Oct 10 '17 at 2:40
• @WorfSonOfMogh Yes, I agree. I don't know why that happens. – Carl Woll Oct 11 '17 at 16:01