1
$\begingroup$

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:

output1

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:

output2

Any help you can offer would be greatly appreciated.

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:

output3

$\endgroup$
  • $\begingroup$ 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. $\endgroup$ – Carl Woll Oct 11 '17 at 4:10
4
$\begingroup$

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}]&)
]

enter image description here

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
]

enter image description here

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
]

enter image description here

$\endgroup$
  • $\begingroup$ 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. $\endgroup$ – bill s Oct 10 '17 at 1:00
  • $\begingroup$ 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? $\endgroup$ – WorfSonOfMogh Oct 10 '17 at 2:40
  • $\begingroup$ @WorfSonOfMogh Yes, I agree. I don't know why that happens. $\endgroup$ – Carl Woll Oct 11 '17 at 16:01

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.