TransWikia.com

How to texturize a Disk/Circle/Rectangle?

Mathematica Asked on June 25, 2021

The documentation for Texture states that “other filled objects” can be texturized:

Texture[obj] is a graphics directive that specifies that obj should be
used as a texture on faces of polygons and other filled graphics
objects.

And also:

Texture can be used in FaceForm to texture front and back faces
differently.

Though I fail to apply a simple texture to any of the following objects. It seems like that “other filled objects” only include Polygons and FilledPolygons, and FaceForm does not work with those.

img = Rasterize@
   DensityPlot[Sin@x Sin@y, {x, -4, 4}, {y, -3, 3}, 
    ColorFunction -> "BlueGreenYellow", Frame -> None, 
    ImageSize -> 100, PlotRangePadding -> 0];
{
 Graphics[{Texture@img, Disk[]}],
 Graphics[{FaceForm@Texture@img, Disk[]}],
 Graphics[{Texture@img, Rectangle[]}],
 Graphics[{FaceForm@Texture@img, Rectangle[]}],

 (* Only this one works *)
 Graphics[{Texture@img, 
   Polygon[{{0, 0}, {1, 0}, {1, 1}, {0, 1}}, 
    VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}]}],
 Graphics[{FaceForm@Texture@img, 
   Polygon[{{0, 0}, {1, 0}, {1, 1}, {0, 1}}, 
    VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}]}]
 }

Mathematica graphics

Edit:

It turns out that “Applying Texture to a disk directly isn’t possible” (according to Heike, thanks s.s.o. for the link). This unfortunately means that:

  1. the official documentation of Texture is wrong (or at least is misleading, as graphics objects usually include primitives);
  2. either Texture is not fully integrated with the system, as it is not applicable for such primitives as a Rectangle, which seems to be just a very specific Polygon; or Rectangle is something else and is defined some other way at the lowest level than a Polygon (maybe it is some OS-dependent object).

Frankly, it is quite hard to imagine what kept developers to include this functionality, but I must assume they had a good reason.

7 Answers

I noticed an example in the document of Texture which used the alpha channel. So I think a disk-shape primitive may be simulated to a limited degree by mapping the image img, which has been set to 100% transparent outside of the circle, onto a rectangle-shape Polygon.

My code:

img = Rasterize[
                DensityPlot[Sin[x] Sin[y],
                            {x, -4, 4}, {y, -3, 3},
                            ColorFunction -> "BlueGreenYellow",
                            Frame -> None, ImageSize -> 100, PlotRangePadding -> 0
              ]];

imgdim = ImageDimensions[img]

alphamask = Array[
                  If[
                     Norm[{#1, #2} - imgdim/2] < imgdim[[1]]/2,
                     1,0]&,
                  imgdim];

alphaimg = MapThread[Append, {img // ImageData, alphamask}, 2];

Graphics[{
          Polygon[{{0, 0}, {1, 0}, {1, 1}, {0, 1}} + .3],
          Texture[alphaimg],
          Polygon[{{0, 0}, {1, 0}, {1, 1}, {0, 1}}, 
                  VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}
                 ],
          Gray, Disk[{0, 0}, .5]
         }]

which gives result like this:

result graph

Correct answer by Silvia on June 25, 2021

Like RM, I've not been able to texture a Disk primitive. We can create a textured disk using ParametricPlot, however.

ParametricPlot[{r*Cos[t], r*Sin[t]}, {r, 0, 1}, {t, 0, 2 Pi},
  Mesh -> False, BoundaryStyle -> None, Axes -> False,
  PlotStyle -> {Opacity[1], 
   Texture[ExampleData[{"ColorTexture", "LightCherry"}]]}]

enter image description here

Answered by Mark McClure on June 25, 2021

If you click the disk and check Drawing tools from the menu there is only color fill options no texture options available. Also see Heike's related answers: in math group or mathematica group mainly she states "Applying Texture to a disk directly isn't possible, but you could for example use RegionPlot with the TextureCoordinateFunction option, e.g"

img = Rasterize@
   DensityPlot[Sin@x Sin@y, {x, -4, 4}, {y, -3, 3}, 
    ColorFunction -> "BlueGreenYellow", Frame -> None, 
    ImageSize -> 100, PlotRangePadding -> 0];

RegionPlot[x^2 + y^2 < 1, {x, -1, 1}, {y, -1, 1}, 
 BoundaryStyle -> None, 
 Axes -> False, Frame -> False, 
 PlotStyle -> Directive[Opacity[1], Texture[img]], 
 TextureCoordinateFunction -> ({#1, #2} &)] 

Answered by s.s.o on June 25, 2021

My fallback method for the moment is the following: approximate a circle with a polygon, fill the latter with the texture and finally conceal the angular edge with an overlaid Circle. If the whole image is small, the number of nodes of the polygon can be further reduced. One annoying sideeffect is though that the Circle is not antialiased...

img = Rasterize@
   DensityPlot[Sin@x Sin@y, {x, -4, 4}, {y, -3, 3}, 
    ColorFunction -> "BlueGreenYellow", Frame -> None, 
    ImageSize -> 200, PlotRangePadding -> 0];
coord = Block[{n = 100}, 
   Table[{Cos[2 [Pi] k/n], Sin[2 [Pi] k/n]}, {k, 0, n - 1}]];
Graphics[{Texture@img, EdgeForm@None, 
  Polygon[coord, VertexTextureCoordinates -> (coord/2 + .5)], Black, 
  Thick, Circle[]}, ImageSize -> 200, Background -> [email protected]]

Mathematica graphics

Answered by István Zachar on June 25, 2021

Here's an extension of Silvia's method of setting an alpha channel in the texture. The alpha mask is obtained directly from the shape using Rasterize, allowing the code to work with ellipses, rectangles, etc.

img = Rasterize@
   DensityPlot[Sin@x Sin@y, {x, -4, 4}, {y, -3, 3}, 
    ColorFunction -> "BlueGreenYellow", Frame -> None, 
    ImageSize -> 300, PlotRangePadding -> 0];

texturedShape[img_, shape_] := Module[{g, p, ar, i},
  g = Graphics[shape, PlotRangePadding -> 0];
  p = Polygon[
    AbsoluteOptions[g, PlotRange][[1, 
       2]] /. {{l_, r_}, {b_, t_}} :> {{l, b}, {l, t}, {r, t}, {r, 
        b}}, VertexTextureCoordinates -> {{0, 0}, {0, 1}, {1, 1}, {1, 
       0}}];
  ar = AbsoluteOptions[g, AspectRatio][[1, 2]];
  i = SetAlphaChannel[img, 
    ColorNegate@Rasterize[g, ImageSize -> ImageDimensions@img]];
  i = ImageCrop[i, 
    Round[If[ar > 1, {1/ar, 1}, {1, ar}] ImageDimensions@img]];
  {Texture[ImageData@i], p}]

The Rasterize gets its ImageDimensions from the original texture image, so I've increased the size of that to 300 to get cleaner edges.

Examples:

Graphics[{texturedShape[img,Disk[{0,0},2]],Red,Disk[{0,1},1]}]

enter image description here

Graphics[{texturedShape[img,Disk[{0,0},{2,1}]],Red,Disk[{0,1},1]}]

enter image description here

Graphics[{Red,Disk[{0,0},0.5],texturedShape[img,Rectangle[]]}]

enter image description here

Answered by Simon Woods on June 25, 2021

Mathematica 10 introduced Regions which make this kind of operation much easier.

img = Rasterize@
   DensityPlot[Sin@x Sin@y, {x, -4, 4}, {y, -3, 3}, 
    ColorFunction -> "BlueGreenYellow", Frame -> None, ImageSize -> 100, 
    PlotRangePadding -> 0];

RegionPlot[
  RegionUnion[Disk[{0, 0}, {2, 2}], Disk[{0, 0}, {3.5, 0.7}]]
  , PlotStyle -> Texture[img]
][[{1}]]

enter image description here

Answered by Mr.Wizard on June 25, 2021

As of version 12.1, we can use (yet undocumented) SurfaceAppearance["TextureShading", Texture[img]] to texturize 2D primitives such as Disk, Rectangle as well as 3D primitives like Sphere, Tube etc.

lena = ExampleData[{"TestImage", "Lena"}];
mandrill = ExampleData[{"TestImage", "Mandrill"}];

Graphics[{SurfaceAppearance["TextureShading", Texture[ImageMultiply[lena, Green]]], 
  Disk[], 
  SurfaceAppearance["TextureShading", Texture[mandrill]], 
  Rectangle[{2, -3/2}, {4, 1/2}], 
  BoundaryDiscretizeRegion @ RegionUnion[Disk[{1, 1}], Rectangle[{3/2, 1}]]}] 

enter image description here

Answered by kglr on June 25, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP