23
$\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$

3 Answers 3

24
$\begingroup$

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

enter image description here

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

enter image description here

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$
6
  • $\begingroup$ I need vector hatching. $\endgroup$ Oct 27, 2014 at 2:18
  • $\begingroup$ @Alexey, would something like Texture[ImportString[ ExportString[hatchingF["cross", {{1, 1}, {1, 1}}, 100], "PNG"]]] work? $\endgroup$
    – kglr
    Oct 27, 2014 at 2:30
  • $\begingroup$ Texture works only with raster fills. I think that raster hatching is not appropriate for generating publication quality graphics. $\endgroup$ Oct 27, 2014 at 2:33
  • $\begingroup$ @Alexey, so Texture is out; that still leaves Mesh/MeshFunctions/MeshShading? :) $\endgroup$
    – kglr
    Oct 27, 2014 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$ Oct 27, 2014 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$
11
  • $\begingroup$ The goal is to have vector hatching, not raster. $\endgroup$ Oct 27, 2014 at 2:13
  • $\begingroup$ @AlexeyPopkov Perhaps that should be specified in the Q? $\endgroup$
    – Michael E2
    Oct 27, 2014 at 2:29
  • $\begingroup$ I have updated the Q. $\endgroup$ Oct 27, 2014 at 2:31
  • $\begingroup$ It seems that you have accidentally deleted your ContourPlot-based solution. $\endgroup$ Oct 27, 2014 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, 2014 at 10:42

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.