9
$\begingroup$

Background: consider the following snippet:

 gp := Graphics
 bill = Import["https://i.stack.imgur.com/FyojA.jpg"];
 poly1 = {{1, 0}, {.5, .86}, {-.5, .86}, {-1, 0}, {-.5, -.86}, {.5, -.86}};
 g1 = {Texture[bill], Polygon[poly1, VertexTextureCoordinates -> poly1]};
 poly2 = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
 g2 = {Texture[bill], Polygon[poly2, VertexTextureCoordinates -> poly2]};
 g1 // gp
 g2 // gp

example of output

The option VertexTextureCoordinates isn't entirely clear to me. I want to put an image with the correct ratios in the hexagon left. So for example on {{-.5,-.5},{.5,-.5},{.5,5},{-.5,.5}}. (I have not been able to get this to work although I have tried all sort of possibilities) However with the restriction that if I rescale the (coordinates of the) hexagon the image should be scaled accordingly.

EDIT-1: enter image description here Image as requested.

EDIT-2: This nicely sums up and demonstrates the answer by Heike:

 rescale1[poly_, p1_, p2_] := 
  Transpose[{Rescale[poly[[All, 1]], {p1[[1]], p2[[1]]}, {0, 1}], 
    Rescale[poly[[All, 2]], {p1[[2]], p2[[2]]}, {0, 1}]}]
 Manipulate[
  g = {Texture[bill], 
     Polygon[poly, 
      VertexTextureCoordinates -> rescale1[poly, leftbot, righttop]]} //
     Graphics,
  {leftbot, {0, 0}, {1, 1}}, {righttop, {0, 0}, {1, 1}}, 
  Initialization :> {righttop = {1, 1}}, ControlPlacement -> Bottom]

Key is the mapping between the image and vertextexture coordinates.

$\endgroup$
5
  • $\begingroup$ Could you please use an image that is available to anyone, e.g. ExampleData[{"TestImage", "Lena"}]? Otherwise good question. $\endgroup$ Jun 30, 2012 at 10:51
  • $\begingroup$ Yes, you can use that image as well. Doesn't really matter. $\endgroup$ Jun 30, 2012 at 10:55
  • 2
    $\begingroup$ Yes, of course it does not matter, it is simply easier for everyone else to copy & run your example without having to manually edit it. $\endgroup$ Jun 30, 2012 at 11:36
  • $\begingroup$ Point taken @IstvánZachar $\endgroup$ Jun 30, 2012 at 12:22
  • $\begingroup$ @ndroock: You could... I don't know, upload the image you have (captain-bill.jpg) using the built-in image uploader, and then everybody else can execute Import[(* URL for captain-bill.jpg *)]... $\endgroup$ Jun 30, 2012 at 13:02

3 Answers 3

6
$\begingroup$

As a generalisation of kguler and Verbeia's answers, you could do something like this

rescale[poly_] :=
  Module[{xrange, yrange, ratio, midp},
   xrange = Through[{Min, Max}[poly[[All, 1]]]];
   yrange = Through[{Min, Max}[poly[[All, 2]]]];
   midp = {Total[xrange], Total[yrange]}/2;
   Rescale[(# - midp) & /@ poly, 
    Max[yrange[[2]] - yrange[[1]], xrange[[2]] - xrange[[1]]]/2 {-1, 1}, {0, 1}]
   ];

Graphics[{Texture[bill], Polygon[poly1, VertexTextureCoordinates -> rescale[poly1]]}]

Mathematica graphics

rescale is basically doing the same thing as the line Rescale[poly1,{-1,1},{0,1}] in the answers above except that the range over which to rescale is calculated automatically. This means that you can use it to rescale the vertex coordinates of any polygon without having to figure out the minimum and maximum values of the coordinates first, e.g.

SeedRandom[];
poly3 = (2 # + BlockRandom[RandomReal[{-1, 1}, 2]]) & /@ poly1;
Graphics[{Texture[bill], 
  Polygon[poly1, VertexTextureCoordinates -> rescale[poly1]],
  Polygon[poly3, VertexTextureCoordinates -> rescale[poly3]]}]

Mathematica graphics

Edit

Concerning your comment, in the coordinate system used for specifying VertexTextureCoordinates, {0, 0} corresponds to the lower left corner of the image used for the texture and {1, 1} to the upper right corner. This coordinate system is cyclic with period 1 which means that for example the point {2.3, -0.8} corresponds to the same point in the image as the points {0.3, 0.2}. To align the texture with the polygon such that the points p1 and p2 (in the coordinate system of the polygon) correspond to the lower left and upper right corners of the image, you need to rescale the coordinates of the vertices of the polygon so that p1 will be mapped to {0, 0} and p2 to {1, 1}, for example by doing something like

rescale1[poly_, p1_, p2_] := Transpose[{Rescale[poly[[All, 1]], {p1[[1]], p2[[1]]}, {0, 1}],
  Rescale[poly[[All, 2]], {p1[[2]], p2[[2]]}, {0, 1}]}]

Graphics[{Texture[bill], 
  Polygon[poly1, 
   VertexTextureCoordinates -> rescale1[poly1, {-.5, -.5}, {.5, .5}]]}]

Mathematica graphics

Here I've chosen p1 == {-.5, -.5} and p2 == {.5, .5} which will centre the texture.

$\endgroup$
4
  • $\begingroup$ How do the VertexTextureCoordinates exactly relate to the coordinates of the image? I want to put the bottom left point of the image to the bottom left vertex of the hexagon. Leave the ratio intact. Tile from there. - If that's possible of course. $\endgroup$ Jun 30, 2012 at 12:40
  • $\begingroup$ @ndroock1 I've updated my answer $\endgroup$
    – Heike
    Jun 30, 2012 at 14:53
  • $\begingroup$ Per request in the Meta section I wait at least 24h with my accept. Once again great help. $\endgroup$ Jun 30, 2012 at 18:09
  • $\begingroup$ Your rescale1 function and explanation deserve a place in the documentation. $\endgroup$ Jul 1, 2012 at 16:11
7
$\begingroup$

kguler's answer is perfectly correct but I thought it worth mentioning that rescaling the Polygon itself is not necessary, only the vertices:

gp := Graphics
bill = ExampleData[{"TestImage", "Lena"}];

rawpoly = {{1, 0}, {.5, .86}, {-.5, .86}, {-1, 
    0}, {-.5, -.86}, {.5, -.86}};

poly1 = Rescale[rawpoly, {-1, 1}, {0, 1}];
g1 = {Texture[ExampleData[{"TestImage", "Lena"}]], 
   Polygon[rawpoly, VertexTextureCoordinates -> poly1]};

g1 // gp

enter image description here

The important point is that, regardless of the coordinates of the enclosing graphic, the VertexTextureCoordinates fall in a naturally rescaled unit square ({0,0} to {1,1}), and if the coordinates in this option fall outside this region, you end up with multiple tiles of the graphic, as seen in your question. If on the other hand, you rescale to a range that is smaller than the unit square, you will only show a portion of the picture but you can center the picture somewhere else in the graphic. Notice how the picture is displaced here relative to the first version.

rawpoly = {{1, 0}, {.5, .86}, {-.5, .86}, {-1, 
    0}, {-.5, -.86}, {.5, -.86}};

poly1 = Rescale[{{1, 0}, {.5, .86}, {-.5, .86}, {-1, 
     0}, {-.5, -.86}, {.5, -.86}}, {-0.5, 0.9}, {0.4, 1}];
g2 = {Texture[ExampleData[{"TestImage", "Lena"}]], 
   Polygon[rawpoly, VertexTextureCoordinates -> poly1]};
g2 // gp

enter image description here

Just for fun, proof that it was the scaling of the vertices, not the ordering, that was the issue:

g2 = {Texture[ExampleData[{"TestImage", "Lena"}]], 
   Polygon[rawpoly, 
    VertexTextureCoordinates -> RotateRight[poly1, 2]]};

enter image description here

$\endgroup$
5
  • $\begingroup$ This already helps but I want it on {{-.5,-.5},{.5,-.5},{.5,5},{-.5,.5}} in the hexagon. Or any set of coordinates for that matter. I still don't get it how the option works. $\endgroup$ Jun 30, 2012 at 11:37
  • $\begingroup$ Ok. I am now so far that I understand that the key lies in the right application of Rescale. The doc is rather thin on that function. A lot of trial- and error-ing required I suppose. $\endgroup$ Jun 30, 2012 at 11:46
  • $\begingroup$ good point. (+1) @ndroock1, I too am unclear about "on {{-.5,-.5},{.5,-.5},{.5,5},{-.5,.5}} in the hexagon"; perhaps a textured rectangle inside a hexagon? $\endgroup$
    – kglr
    Jun 30, 2012 at 11:56
  • $\begingroup$ @kugler The example, clearly, isn't of a major importance. I do want to understand the VertexTextureCoordinates. I read the docs of course, but they are not clear to me. I want to map imported pics to tilings. $\endgroup$ Jun 30, 2012 at 12:35
  • $\begingroup$ in the docs it says:Texture[obj] is equivalent to Texture[Rasterize[obj]] and will rasterize obj at the size and resolution it would normally be displayed in a notebook. The texture is rasterized before fit to the shape. You can adjust it. $\endgroup$
    – s.s.o
    Jun 30, 2012 at 13:26
6
$\begingroup$

Does this work?

lena=ExampleData[{"TestImage", "Lena"}];
poly1 = {{1, 0}, {.5, .86}, {-.5, .86}, {-1, 0}, {-.5, -.86}, {.5, -.86}};
scldpoly1=Rescale[poly1,{-1,1},{0,1}];
g1 = {Texture[lena],Polygon[scldpoly1,VertexTextureCoordinates -> scldpoly1]};

Graphics[g1]

enter image description here

or something like:

poly2 = {{-.5, -.5}, {.5, -.5}, {.5, .5}, {-.5, .5}}; 
Graphics[{Brown, Polygon[poly1], Texture[lena], 
Polygon[poly2, VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}]}]

enter image description here

EDIT 3: For centered tiling shifting the polygon corrdinates by .5 does the centered tiling without having to use Rescale:

poly1X = poly1 - .5;
g1 = {Texture[ExampleData[{"TestImage", "Lena"}]], 
Polygon[poly1, VertexTextureCoordinates -> poly1X]};

enter image description here

Row[Graphics[{Texture[lena],Polygon[poly1, VertexTextureCoordinates -> # poly1X]}] & /@ Range[2, 5]]

enter image description here

$\endgroup$
4
  • $\begingroup$ This already helps but I want it on {{-.5,-.5},{.5,-.5},{.5,5},{-.5,.5}} in the hexagon. $\endgroup$ Jun 30, 2012 at 11:36
  • $\begingroup$ @ndroock1 I don't understand what you are trying to get - do you want a single copy of the picture, centered on that coordinate? In that case, you need Inset. I can do up another answer if that's what you wanted. $\endgroup$
    – Verbeia
    Jun 30, 2012 at 11:38
  • $\begingroup$ I want to know how the function works, basically. But to be specific about the case I submitted. No not a single copy. I want it tiled with the initial copy at the given coordinates. $\endgroup$ Jun 30, 2012 at 12:25
  • $\begingroup$ @ndroock1, thanks... now I see.. $\endgroup$
    – kglr
    Jun 30, 2012 at 12:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.