# How can I enclose a closed curve with another identical slightly bigger closed curve?

I have a closed curve. I am trying to enclose this closed curve with another closed curve, which looks identical in the shape of the first closed curve, but slightly bigger. How to do this?

pts = {{-1, 0}, {-1, 1}, {0, 0}, {1, 1}, {1, 0}};
Graphics[{Thick, BSplineCurve[pts, SplineClosed -> True]}]

• Your question is unclearly formulated: what do do you mean by 'bigger"? how about pts = {{-1, 0}, {-1, 1}, {0, 0}, {1, 1}, {1, 0}}; Graphics[{Thick, BSplineCurve[pts, SplineClosed -> True], BSplineCurve[1.1*pts, SplineClosed -> True]}]? Commented Aug 14, 2020 at 15:34
• Similar to the situation of this, enclosing a small rectangle by a bigger rectangle, all the side of the smaller rectangle is equal distance from the bigger rectangle Commented Aug 14, 2020 at 15:37
• So in short, you wanted a parallel curve / offset curve of your original curve. Commented Aug 14, 2020 at 23:15

1. You can use BSplineFunction as follows:

pts = {{-1, 0}, {-1, 1}, {0, 0}, {1, 1}, {1, 0}};

ClearAll[explode, bsf]
explode[f_] := f[#] + #2 Cross @ Normalize[f'[#]] &;

bsf = BSplineFunction[pts, SplineClosed -> True];

Graphics[{Thick, BSplineCurve[pts, SplineClosed -> True], Blue,
Line[explode[bsf][#, .2] & /@ Subdivide[100]]}] // Framed


Graphics[{Thick, Line[bsf /@ Subdivide[100]], Blue,
Line[explode[bsf][#, .2] & /@ Subdivide[100]]}] // Framed


2. You can also use bsf and explode with ParametricPlot:

ParametricPlot[{bsf@t, explode[bsf][t, .2], explode[bsf][t, -.1]}, {t, 0, 1},
PlotStyle -> {Black, Blue, Green}, BaseStyle -> Thick, Axes -> False,
ImageSize -> Large]


3. Alternatively, you can use SignedRegionDistance + ContourPlot:

srd = Quiet @ SignedRegionDistance[Polygon[bsf /@ Subdivide[100]]];

ContourPlot[srd[{x, y}], {x, -3/2, 3/2}, {y, -.5, 1},
Contours -> {{.2, Blue}, {0., {Thick, Black}}},
Frame -> False, ImageSize -> Large, AspectRatio -> Automatic]


Use the options

ContourShading -> {PatternFilling["Grid", ImageScaled[1/10],
ImageScaled[{0, .35}]], None, None}


and

Epilog -> {Red, Disk[{0., .75}, .25], Black, Disk[{-.5, .8}, .1], Disk[{.5, .8}, .1]}


to get

Related Q/As:

• It is exactly what I am looking for. Could you please explain to me how you did this? Commented Aug 14, 2020 at 16:03
• @acoustics, if we have a function that describes the curve (luckily we have BSplineFunction), we can use its normalized gradient to get the directions at each point on the curve (that's the Normalize @ f'[t] piece) and move each point in that direction by the desired distance.
– kglr
Commented Aug 14, 2020 at 16:15
• I tried by extracting the surface normal vector at each point, then I tried scaling the points in that direction. But my results were wrong, the lines were intersecting. Anyways thanks. Commented Aug 14, 2020 at 16:18
• @acoustics, in general parallel curves can be self-intersecting. There is a limited range of offsets where the resulting curves do not have that property. Commented Aug 16, 2020 at 3:51