7
$\begingroup$

I have a multiply connection two-dimensional region such as the following:

br = BoundaryDiscretizeGraphics@Graphics[Disk[#, 8/9] & /@ CirclePoints[9]]

Mathematica graphics

I am looking for a way to discard all inner "holes", i.e. get this:

enter image description here

In order to get this I was hoping to be able to separate the two boundaries of the region, then manually pick the outer one. What is a simple way to do this?

$\endgroup$

2 Answers 2

7
$\begingroup$

Here's an attempt to automate the selection of the outer boundaries with some undocumented properties. Here's a BoundaryMeshRegion with multiple holes and multiple outer boundaries:

g1 = Graphics[Table[Annulus[{x, 0}, {0.5 + x/20, 1}], {x, 0, 9, 3}]];
g2 = Graphics[Rectangle[{1.5, -0.3}, {7.5, 0.3}]];
br = RegionUnion[BoundaryDiscretizeGraphics /@ {g1, g2}]

enter image description here

The "BoundaryGroups" property groups the boundaries of connected regions, and it appears that the first element of each group is the outer boundary. (Pure conjecture of course, but that was the case for the limited number of tests I did).

bgps = br["BoundaryGroups"]
(* {{6, 2, 3, 4, 5}, {8, 7}, {1, 9}} *)

outer = bgps[[All, 1]]
(* {6, 8, 1} *)

I use another undocumented property, "IndexedBoundaryPolygons" to extract the polygons with those indices and construct a new region:

polys = br["IndexedBoundaryPolygons"][[outer]];

MeshRegion[MeshCoordinates[br], polys]

enter image description here

$\endgroup$
5
$\begingroup$

One possible solution is to take the boundary, then find the connected components:

ConnectedMeshComponents@RegionBoundary[br]

Mathematica graphics

Key functions: ConnectedMeshComponents, RegionBoundary.

We can then manually pick the boundary we want:

outer = First[%];

And convert it back to a polygon (a 2D region rather than a boundary):

BoundaryDiscretizeRegion@Polygon@MeshCoordinates[outer]

Mathematica graphics

In more complicated examples order of the points returned by MeshCoordinates may not follow the boundary in a continuous manner. In this case we can reorder them before converting them to a polygon:

pts = Part[
   MeshCoordinates[outer],
   DeleteDuplicates@Level[MeshCells[outer, 1], {-1}]
 ];
$\endgroup$
5
  • $\begingroup$ I arrived to this solution after I have written up the question. Given that it took me some time to figure this out, I though posting the solution would be more valuable than deleting the question. $\endgroup$
    – Szabolcs
    Commented Dec 21, 2015 at 9:25
  • $\begingroup$ I was just about to post just another way of selecting the relevant mesh coordinates by selecting outside a disk...this is helpful and I am voting for it:) $\endgroup$
    – ubpdqn
    Commented Dec 21, 2015 at 9:43
  • $\begingroup$ @ubpdqn If you have another solution, I would like to see it! $\endgroup$
    – Szabolcs
    Commented Dec 21, 2015 at 9:49
  • $\begingroup$ @ubpdqn That would have worked too. I disk would not work for my real example, but I could have drawn an outline manually to separate the outer boundary from the inner ones, then test whether the points are within this outline. $\endgroup$
    – Szabolcs
    Commented Dec 21, 2015 at 9:50
  • $\begingroup$ it probably just worked for this case where the internal boundary is conveniently separable by a disk and the outer coordinates conveniently ordered... $\endgroup$
    – ubpdqn
    Commented Dec 21, 2015 at 9:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.