9
$\begingroup$

For example, this is a 2D MeshRegion with one (or more) holes in it:

mr = DiscretizeRegion@RegionDifference[
   Rectangle[{-1, -1}, {1, 1}],
   Disk[{0, 0}, 0.5]
]

I would like to identify outer boundary (MeshCells) and inner boundary of a hole. I can get indices of all boundary MeshCells, but cannot distinguish between them. How can I do that?

HighlightMesh[mr, MeshCellIndex[mr, {1, "Boundary"}]] 

mesh

Ultimately I will convert this MeshRegion to ElementMesh and assign different integer markers to LineElements on the boundary.

$\endgroup$
2
  • $\begingroup$ What is the reason you start with a MeshRegion in the first place? $\endgroup$
    – user21
    Jan 9, 2019 at 8:01
  • $\begingroup$ @user21 There is no particular reason, I just couldn't think of a better solution. Actually the input and output for this procedure will always be ElementMesh. $\endgroup$
    – Pinti
    Jan 9, 2019 at 8:04

2 Answers 2

8
$\begingroup$

You can use ConnectedMeshComponents as follows:

cmc = ConnectedMeshComponents[DiscretizeGraphics[MeshPrimitives[mr, {1, "Boundary"}]]]; 

Show[mr,  Epilog -> Thread[{Thickness[.01], {Red, Blue},  MeshPrimitives[#, 1] & /@ cmc}]]

enter image description here

$\endgroup$
5
$\begingroup$

You can convert your MeshRegion to a boundary element mesh with auto generated markers by:

Needs["NDSolve`FEM`"]
bmesh = ToBoundaryMesh[RegionBoundary[mr]];
bmesh["Wireframe"["MeshElementStyle" -> "BoundaryGrouping"]]

enter image description here

The fact that the rectangle has also been split is desirable for FEM. You can look at the markers generated.

bmesh["BoundaryElementMarkerUnion"]
{1, 2, 3, 4, 5}

Here is a mesh that has an outer boundary, an inner boundary and a material boundary:

Needs["NDSolve`FEM`"]
\[CapitalOmega] = 
  ImplicitRegion[(x - 1/2)^2 + (y - 1/2)^2 >= (1/
        2)^2 && (x + 1/2)^2 + (y + 1/2)^2 >= (1/2)^2, {{x, -2, 
     2}, {y, -2, 2}}];
(mesh = ToElementMesh[\[CapitalOmega], 
    "RegionHoles" -> {{-1/2, -1/2}}, 
    "RegionMarker" -> {{{1/2, 1/2}, 2}, {{1/2, -1/2}, 1}}, 
    "MaxBoundaryCellMeasure" -> 0.125])["Wireframe"]

enter image description here

You can then extract the boundary element marker union; these markers are auto generated.

groups = mesh["BoundaryElementMarkerUnion"]
{1, 2, 3, 4, 5, 6}

Some colors for the markers:

temp = Most[Range[0, 1, 1/(Length[groups])]];
colors = ColorData["BrightBands"][#] & /@ temp

enter image description here

mesh["Wireframe"["MeshElement" -> "BoundaryElements", 
  "MeshElementStyle" -> (Directive[#] & /@ colors)]]

enter image description here

To further work with this you could use MeshElementSplitByMarker:

mesbm = Flatten[
   MeshElementSplitByMarker[
    MeshOrderAlteration[mesh, 1]["BoundaryElements"]]];

and extract one of the components:

Graphics[GraphicsComplex[mesh["Coordinates"], 
  Line[ElementIncidents[mesbm[[6]]]]]]

enter image description here

This selection works by looking at normals and grouping them with some threshold. There are a few examples in the ElementMesh ref page in the Scope section under "BoundaryNormals".

Another approach is to use the "VertexBoundaryConnectivity" in conjunction with StronglyConnectedComponents.

bmesh = ToBoundaryMesh[mesh];
belems = bmesh["BoundaryElements"];

bincidents = Join @@ ElementIncidents[belems];
S = bmesh["VertexBoundaryConnectivity"];
S = Transpose[S].S;
components = SparseArray`StronglyConnectedComponents[S];
pls = Map[Line[Developer`ToPackedArray /@ (Part[bincidents, #])] &, 
  components]
Graphics[GraphicsComplex[bmesh["Coordinates"], pls]]

enter image description here

$\endgroup$
4
  • $\begingroup$ Thanks. I think that StronglyConnectedComponents method is suitable for me, since my ElementMesh objects may come without distinct markers of "BoundaryElements", because they could be imported from elsewhere. $\endgroup$
    – Pinti
    Jan 9, 2019 at 9:57
  • 1
    $\begingroup$ @Pinti, I think they should have boundary markers even if they are imported. If not, could you please send me such an example to look at it? Thanks. $\endgroup$
    – user21
    Jan 9, 2019 at 11:48
  • $\begingroup$ Very useful! Which version did you use? In MMA 11.0 on Windows, the third line of your reply (bmesh["Wireframe"["MeshElementStyle" -> "BoundaryGrouping"]]) throws an error: BoundaryGrouping is not a Graphics primitive or directive. $\endgroup$ Jul 2, 2019 at 12:05
  • $\begingroup$ Reproduced on another 11.0 Windows machine. Works fine in 11.3. $\endgroup$ Jul 2, 2019 at 12:13

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.