# Generating hatched filling using Region functionality

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:

GraphicsMeshMeshInit[];
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]


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.

Update 2: Finally ... in version 12.1 you can use the new directives HatchFilling and PatternFilling:

 Graphics[{EdgeForm[{Thick, Black}], #, blob}, ImageSize -> 300] & /@
{HatchFilling[], Directive[Red, HatchFilling[Pi/2, 2, 10]]} // Row


Graphics[{EdgeForm[{Thick, Black}], PatternFilling[#, ImageScaled[1/20]], blob},
ImageSize -> 300] & /@ {"Diamond", "XGrid"} // Row


Update: Using MeshFunctions and Mesh in RegionPlot:

RegionPlot[Evaluate[RegionRegionProperty[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}]]


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

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

Update 2: Mesh specifications

rpF = RegionPlot[
Evaluate[RegionRegionProperty[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}}]


Change the MeshFunctions specification to

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


to get

Use the option

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


to get

Original version:

GraphicsMeshMeshInit[];
blob = PolygonData["Blob", "Polygon"];

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


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


where hatched textures texturea and textureb

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


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


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,
Axes -> False, PlotStyle -> pltstyle]]


More examples:

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


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


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"]


• I need vector hatching. Oct 27, 2014 at 2:18
• @Alexey, would something like Texture[ImportString[ ExportString[hatchingF["cross", {{1, 1}, {1, 1}}, 100], "PNG"]]] work?
– kglr
Oct 27, 2014 at 2:30
• Texture works only with raster fills. I think that raster hatching is not appropriate for generating publication quality graphics. Oct 27, 2014 at 2:33
• @Alexey, so Texture is out; that still leaves Mesh/MeshFunctions/MeshShading? :)
– kglr
Oct 27, 2014 at 2:50
• 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? Oct 27, 2014 at 3:14

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]


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


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"}]]]


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]


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]]


• The goal is to have vector hatching, not raster. Oct 27, 2014 at 2:13
• @AlexeyPopkov Perhaps that should be specified in the Q? Oct 27, 2014 at 2:29
• I have updated the Q. Oct 27, 2014 at 2:31
• It seems that you have accidentally deleted your ContourPlot-based solution. Oct 27, 2014 at 7:58
• @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. Oct 27, 2014 at 10:42