21
$\begingroup$

Before v.10 came out there were several Q&A on generating hatched filling for Plot, ListPlot etc.

In v.10 we have new Region functionality and I wonder: Does it allow a straightforward way to produce vector hatched filling for arbitrary 2D Polygon?

Here is my first attempt to use Region functionality which produces ugly result in extremely inefficient way:

Graphics`Mesh`MeshInit[];
blob = PolygonData["Blob", "Polygon"];
Show[DiscretizeRegion[
  RegionIntersection[
   RegionUnion @@ 
    Table[InfiniteLine[{-3, y}, {1, 1}], {y, -7, 2, .2}], 
   blob], {{-3, 3}, {-3, 3}}], Prolog -> blob, 
 PlotRange -> {{-3, 3}, {-3, 3}}, Frame -> True]

plot

Is it a good idea to use Region for such purposes? Can anyone suggest an efficient solution?

P.S. I think that raster texture is not appropriate for hatching filling because it is not scalable. The goal is to have vector hatching.

$\endgroup$
23
$\begingroup$

Update: Using MeshFunctions and Mesh in RegionPlot:

RegionPlot[Evaluate[Region`RegionProperty[Rationalize /@ blob, {x, y}, 
    "FastDescription"][[1, 2]]], {x, -3, 3}, {y, -3, 3}, Mesh -> 50, 
 MeshFunctions -> {#1 + #2 &, #1 - #2 &}, MeshStyle -> White, 
 PlotStyle -> Directive[{Thick, Blue}]]

enter image description here

With settings MeshStyle -> GrayLevel[.3], PlotStyle -> Directive[{Thick, LightBlue}] enter image description here

With settings Mesh -> {40, 20}, MeshFunctions -> {# #2 &, Norm[{#, #2}] &}, MeshStyle -> White, MeshShading -> Dynamic@{{Hue@RandomReal[], Hue@RandomReal[]}, {Hue@RandomReal[], Hue@RandomReal[]}}, we get

Mathematica graphics

Update 2: Mesh specifications

rpF = RegionPlot[
    Evaluate[Region`RegionProperty[Rationalize /@ blob, {x, y}, 
       "FastDescription"][[1, 2]]], {x, -3, 3}, {y, -3, 3}, Mesh -> #,
     MeshFunctions -> {#1 + #2 &, #1 - #2 &}, 
    MeshStyle -> GrayLevel[.3], 
    PlotStyle -> Directive[{Thick, LightBlue}]] &;

rp1 = rpF@{20, 75};
rp2 = rpF@{List /@ {-5, -4, -2.5, -2., -1.9, -1.8, -1.7, -1., -.5, Sequence @@ Range[0, 5, .2]}, 
  List /@ {Sequence @@ Range[-5., -1, .3], Sequence @@ Range[-1., 1, .1], 1.5, 2., 2.5, 3.}};
rp3 = rpF@RandomReal[{-5, 5}, {2, 50, 1}];
rp4 = rpF@{Transpose[{RandomReal[{-5, 5}, 25], Table[Hue[RandomReal[]], {25}]}], 
  Transpose[{RandomReal[{-5, 5}, 50], Table[Directive[{Thick, Hue[RandomReal[]]}], {50}]}]};

Grid[{{rp1, rp2}, {rp3, rp4}}]

enter image description here

Change the MeshFunctions specification to

MeshFunctions -> {#1 &, #2 &}

to get

enter image description here

Use the option

MeshShading -> Dynamic@{{Hue@RandomReal[], Hue@RandomReal[]}, 
                        {Hue@RandomReal[], Hue@RandomReal[]}}

to get enter image description here


Original version:

Graphics`Mesh`MeshInit[];
blob = PolygonData["Blob", "Polygon"];

RegionPlot[Evaluate[Region`RegionProperty[Rationalize /@ blob, {x, y}, 
    "FastDescription"][[1, 2]]], {x, -3, 3}, {y, -3, 3}, PlotStyle -> texturea]

enter image description here

RegionPlot[Evaluate[Region`RegionProperty[Rationalize /@ blob, {x, y}, 
    "FastDescription"][[1, 2]]], {x, -3, 3}, {y, -3, 3}, PlotStyle -> textureb]

enter image description here

where hatched textures texturea and textureb

texturea = Texture[Rasterize@hatchingF["cross", {{1, 1}, {1, 1}}, 100]]

enter image description here

textureb = Texture@Rasterize@hatchingF["cross", {{1, 1}, {1, 1}}, 100, 
           Dynamic@Directive[{Thick, Hue[RandomReal[]]}]]

enter image description here

are obtained using the function

ClearAll[hatchingF];
hatchingF[dir : ("single" | "cross") : "single", 
  slope : ({{_, _} ..}) : {{1, 1}}, mesh_Integer: 100, 
  style_: GrayLevel[.5], pltstyle_: None, opts : OptionsPattern[]] := 
 Module[{meshf = Switch[dir, "single", {slope[[1, 1]] #1 + slope[[1, -1]] #2 &}, 
     "cross", {slope[[1, 1]] #1 - slope[[1, -1]] #2 &, 
      slope[[-1, 1]] #1 + slope[[-1, -1]] #2 &}]}, 
  ParametricPlot[{x, y}, {x, 0, 1}, {y, 0, 1}, Mesh -> mesh,
   MeshFunctions -> meshf, MeshStyle -> style, BoundaryStyle -> None, 
   opts, Frame -> False, PlotRangePadding -> 0, ImagePadding -> 0, 
   Axes -> False, PlotStyle -> pltstyle]]

More examples:

hatchingF["cross", {{1, 0}, {0, 1}}, 50, Red]

enter image description here

hatchingF["single", {{1, 1}, {0, 1}}, 50, Directive[{Thick,Green}]]

enter image description here

texture2 = Texture[Rasterize@ hatchingF["cross", {{1, 1}, {1, 1}}, 50, Directive[{Thick, Red}]]];
Plot3D[Sin[x y], {x, 0, 3}, {y, 0, 3}, PlotStyle -> texture2, Mesh -> None, Lighting -> "Neutral"]

enter image description here

$\endgroup$
  • $\begingroup$ I need vector hatching. $\endgroup$ – Alexey Popkov Oct 27 '14 at 2:18
  • $\begingroup$ @Alexey, would something like Texture[ImportString[ ExportString[hatchingF["cross", {{1, 1}, {1, 1}}, 100], "PNG"]]] work? $\endgroup$ – kglr Oct 27 '14 at 2:30
  • $\begingroup$ Texture works only with raster fills. I think that raster hatching is not appropriate for generating publication quality graphics. $\endgroup$ – Alexey Popkov Oct 27 '14 at 2:33
  • $\begingroup$ @Alexey, so Texture is out; that still leaves Mesh/MeshFunctions/MeshShading? :) $\endgroup$ – kglr Oct 27 '14 at 2:50
  • $\begingroup$ Yes, MeshFunctions is a solution. There is an extremely simple way to optimize the mesh: % /. Line[{{f_, __}, __, {__, l_}}] :> Line[{f, l}]. The only drawback is that Mesh does not allow to specify the distance between the hatches, only the number of hatches. Is there a way to generate completely customizable hatching? $\endgroup$ – Alexey Popkov Oct 27 '14 at 3:14
8
$\begingroup$

Here is a solution which combines kguler's and MichaelE2's approaches:

ParametricPlot[{x, y}, {x, y} ∈ blob, Mesh -> 20, 
 MeshFunctions -> {#1 - #2 &}, MeshStyle -> Black, 
 BoundaryStyle -> Black, PlotStyle -> None, Axes -> False]

plot

Note however that the syntax form ParametricPlot[{x, y}, {x, y} ∈ region] seems to be undocumented.


It is worth to mention that in a usual situation when only the hatching is needed there is straightforward way to optimize it by joining the adjacent line segments:

simplifyHatches = # /. Line[{f_Integer, __, l_Integer}] :> Line[{f, l}] &;

ParametricPlot[{x, y}, {x, y} ∈ blob, Mesh -> 20, 
  MeshFunctions -> {#1 - #2 &}, MeshStyle -> Black, 
  BoundaryStyle -> None, PlotStyle -> None, 
  Axes -> False] // simplifyHatches

optimized plot

$\endgroup$
7
$\begingroup$

Edit 2: Updated with a non-convex polygon

reg = With[{pts = RandomReal[{-3, 3}, {15, 2}]},
   Polygon@SortBy[pts, Apply[ArcTan, # - Mean[pts]] &]];

You could make a texture and use RegionPlot:

RegionPlot[
 reg,
 PlotStyle -> Texture[ExampleData[{"ColorTexture", "MultiSpiralsPattern"}]]]

Mathematica graphics

Update

Vector graphics through ContourShading:

ClearAll[f];
f[x_, y_] := x - y;
ContourPlot[f[x, y], {x, y} ∈ reg,
 Contours -> 20, ContourShading -> {Blue, LightRed}, 
 ContourStyle -> None]

Mathematica graphics

A self-intersecting polygon:

reg = Polygon[RandomReal[{-3, 3}, {15, 2}]];
ContourPlot[f[x, y], {x, y} ∈ reg,,
 Contours -> Flatten[Table[{c, c + 0.05}, {c, -6, 6, 0.3}]],
 ContourShading -> {Blue, LightRed}, ContourStyle -> None]]

Mathematica graphics

$\endgroup$
  • $\begingroup$ The goal is to have vector hatching, not raster. $\endgroup$ – Alexey Popkov Oct 27 '14 at 2:13
  • $\begingroup$ @AlexeyPopkov Perhaps that should be specified in the Q? $\endgroup$ – Michael E2 Oct 27 '14 at 2:29
  • $\begingroup$ I have updated the Q. $\endgroup$ – Alexey Popkov Oct 27 '14 at 2:31
  • $\begingroup$ It seems that you have accidentally deleted your ContourPlot-based solution. $\endgroup$ – Alexey Popkov Oct 27 '14 at 7:58
  • $\begingroup$ @AlexeyPopkov I was going to think about it, but I seem to have really deleted it. It was late and I couldn't figure out the difference between hatching and stripes. Also, I was running out of energy to address the main question of how to use the new Region functionality to make hatching. The answers so far don't really use it in the way you were trying. $\endgroup$ – Michael E2 Oct 27 '14 at 10:42

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.