Simple ways to implement vector dilation

Suppose we have a singly connected but not necessarily convex polygon. Something like shape = CountryData["Chad", "Coordinates"].

Is there a simple way to implement an approximate dilation for this shape, and obtain the result as vector data (lists of coordinates) just like the input?

Here's what dilation does to images:

img = ImagePad[ColorNegate@Image@Graphics[Polygon[shape]], 30];
ImageCompose[Dilation[img, DiskMatrix[30]], {img, .5}]


What I need is the outline of the gray area, but as vector (not bitmap) data.

One way is to rasterize, dilate the image, then vectorize the outline again. This seems complicated, especially since I need to preserve the original coordinate system.

Is there a better way?

The result will be used for visualization purposes, so it need not be perfect. Approximations are okay.

• Something along the lines of ImplicitRegion[RegionDistance[polygon, {x, y}] <= r, {x, y}]?
– user484
Jun 30 '15 at 15:55
• @Rahul Sounds like a great idea! The problem is that actually plotting or discretizing region specifications fails very often. It seems that for Chad it does work well, and what's better, it even gives me the (approximately) equidistant points along the perimeter. I'm going to try it for my actual use case and hope for the best ... RegionBoundary@DiscretizeRegion[ImplicitRegion[RegionDistance[reg, {x, y}] <= 0.05, {x, y}], MaxCellMeasure -> 0.0001]. Why don't you post an answer? Jun 30 '15 at 16:39
• @Rahul Unfortunately for my actual use case it just gives up :( I'll post a better example tomorrow, no internet connection at home and I need to leave :( Jun 30 '15 at 17:32
• I didn't post an answer because I don't have access to Mathematica right now, so I had no idea if my suggestion would actually work!
– user484
Jun 30 '15 at 19:30
• @Rahul Thanks again, I managed to come up with a robust solution by making some minor modifications to your line. I'll post later tonight when I get the time. Jul 1 '15 at 16:07

From 2016 and Version 11.0 we can use ImageMesh.

img = ImagePad[ColorNegate@Image@Graphics[Polygon[shape]], 30];
imgD = Dilation[img, DiskMatrix[30]];
mesh0 = ImageMesh@img; meshD = ImageMesh@imgD;
Graphics[{Green,
Arrow[Flatten[pts0 = MeshPrimitives[mesh0, 1][[All, 1]], 1]], Red,
Arrow@Flatten[ptsD = MeshPrimitives[meshD, 1][[All, 1]], 1]}]


shape = First @ CountryData["Chad", "Coordinates"];
poly = Polygon @ shape;
srd = SignedRegionDistance @ poly;

ranges = Flatten /@ Transpose[{{x, y},
CoordinateBounds[ScalingTransform[1.4 {1, 1}, Mean @ shape] @ shape]}];

ContourPlot[srd[{x, y}], ranges[[1]], ranges[[2]],
Contours -> Thread[{{-1, -.5, -.25, .25, .5, 1},
ColorData["Rainbow"] /@ Subdivide[5]}],
Frame -> False, ImageSize -> 500,
Prolog -> {EdgeForm[Black], FaceForm[LightBlue], poly},
PlotLegends -> Placed[LineLegend[Automatic,
LegendLabel -> SignedRegionDistance], Top]]


For visualization purposes only I propose a simple and robust approach using a thick boundary line:

shape = CountryData["Chad", "Coordinates"];
r = 2;

xmin = Min[shape[[1, ;; , 1]]] - r;
xmax = Max[shape[[1, ;; , 1]]] + r;
ymin = Min[shape[[1, ;; , 2]]] - r;
ymax = Max[shape[[1, ;; , 2]]] + r;

Graphics[{{FaceForm[Blue],
EdgeForm[{JoinForm["Round"], Thickness[2 r/(xmax - xmin)], Blue}],
Polygon[shape]},
{Red, Polygon[shape]},
Circle[shape[[1, 1]], r]
}, PlotRange -> {{xmin, xmax}, {ymin, ymax}}, Axes -> True]


There are two drawbacks:

• The dilated polygon is not given by an explicit set of points
• We should specify the plot range to obtain the thickness in terms of original coordinates. The circle is drawn to check the thickness.