At Rahul's suggestion I looked into the "smallest circle problem", which covers the circumcircle. And for the incircle I needed to read about the "largest empty circle".
I wrote some code that will find the necessary circles for version 9, which doesn't have the nifty built-in functions that I use above. I borrowed a function from cormullion here, and adapted some code from DrBob here which uses an algorithm from here.
The circumcircle is found via a recursive algorithm that looks at each point and decides whether it is inside the circle so far, if not then it will be part of the boundary points.
For the incircle, it is trickier. I use the fact that for a convex polygon, the center of the incircle will be on one of the vertices of the Voronoi diagram of the polygon vertices (this may not be generally true, I'm awful at proofs, but it seems to work here). Generating these vertices takes a long time using the ComputationalGeometry
package, but it is doable.
Needs["ComputationalGeometry`"];
outCircle[Polygon[a_]] := outCircle[Flatten[a, Depth[a] - 3]];
outCircle[points_List] :=
outCircle[points] =
Module[{calcDisk, moveToFront, circleThrough3Points},
circleThrough3Points[{p1_, p2_, p3_}] :=
Module[{ax, ay, bx, by, cx, cy, a, b, c, d, e, f, g, centerx,
centery, r}, {ax, ay} = p1;
{bx, by} = p2;
{cx, cy} = p3;
a = bx - ax;
b = by - ay;
c = cx - ax;
d = cy - ay;
e = a (ax + bx) + b (ay + by);
f = c (ax + cx) + d (ay + cy);
g = 2 (a (cy - by) - b (cx - bx));
If[g == 0,
False, {centerx = (d e - b f)/g, centery = (a f - c e)/g,
r = Sqrt[(ax - centerx)^2 + (ay - centery)^2]}];
{{centerx, centery}, r}];
calcDisk[{}] := {0, 0};
calcDisk[{{x_, y_}}] := {0, 0};
calcDisk[{{x_, y_}, {x2_, y2_}}] := {Mean[{{x, y}, {x2, y2}}],
Norm[{x, y} - {x2, y2}]/2};
calcDisk[{{x_, y_}, {x2_, y2_}, {x3_, y3_}}] :=
circleThrough3Points[{{x, y}, {x2, y2}, {x3, y3}}];
moveToFront[pts_, b_] := Module[{copy = pts, c, rs},
{c, rs} = calcDisk[b];
If[Length@b != 3,
Do[If[Norm[copy[[n]] - c] > rs, {c, rs} =
moveToFront[copy[[;; n - 1]], Union[b, copy[[{n}]]]];
copy = Prepend[Delete[copy, n], copy[[n]]]], {n,
Length@pts}]];
{c, rs}];
moveToFront[points, {}]];
inCircle[Polygon[a_ /; Depth[a] == 4]] :=
Last@SortBy[inCircle /@ a, Last];
inCircle[Polygon[a_ /; Depth[a] == 3]] := inCircle[a];
inCircle[p_List] := inCircle[p] = Quiet@Module[{vdpoints, dist},
vdpoints =
p // VoronoiDiagram // First // Cases[#, _List] & //
Select[#, (Graphics`Mesh`InPolygonQ[p, #] &)] &;
dist[pt_] :=
Min[EuclideanDistance[pt, #] & /@ p];
{#, dist@#} &@Last[SortBy[vdpoints, dist]]
]
Here it is applied to a couple of examples (be patient, it takes a while). You can see the results match up reasonably well with those above.
pol = CountryData["Japan", {"Polygon", "Mercator"}];
Graphics[{Blue,
Disk @@ outCircle[#], Black, #,
Red, Disk @@ inCircle[#]}] &@pol
Last[inCircle[pol]]^2/Last[outCircle[pol]]^2
pol = CountryData["SierraLeone", {"Polygon", "Mercator"}];
Graphics[{Blue,
Disk @@ outCircle[#], Black, #,
Red, Disk @@ inCircle[#]}] &@pol
Last[inCircle[pol]]^2/Last[outCircle[pol]]^2
DistanceTransform
, but that only works for rasterized regions. $\endgroup$