I'd like to generate triangular meshes or a cylinder and sphere primitives as part of a lattice meshing program I am writing to experiment with Mathematica. Consider the following snippet:

{p1, p2, r} = {{-1, 0, 0}, {1, 2, 1}, 0.5};
BoundaryDiscretizeGraphics[Cylinder[{p1, p2}, r]]
BoundaryDiscretizeGraphics[Sphere[p1, r], MaxCellMeasure -> 0.01]

I have 2 questions

  1. For the sphere: How can I extract the coordinates and connectivities I can see in the output of the second FullForm call into separate list of vertices and connectivities. I guess I need to do some magic to extract correct parts of the expression.

  2. For the cylinder: How can I convert the polygons defining the caps and the quadrilaterals around the body into triangles and then extract the triangles into vertices and connectivity lists as for the cylinder

enter image description here enter image description here

  • 2
    $\begingroup$ How odd. It seems that even with a ridiculously small setting of MaxCellMeasure, the cylinder remains untriangulated... $\endgroup$ – J. M.'s ennui Nov 9 '15 at 23:09
  • 2
    $\begingroup$ @J.M. BoundaryDiscretizeGraphics doesn't triangulate flat surfaces (in contrast to DiscretizeGraphics). It is simply unnecessary for boundary approximation. $\endgroup$ – ybeltukov Nov 9 '15 at 23:28
  • 2
    $\begingroup$ Anyway: look up MeshCoordinates[] and MeshCells[]. $\endgroup$ – J. M.'s ennui Nov 10 '15 at 1:55
  • $\begingroup$ @J.M. Amazing, that's exactly what I want :) I knew it had to be something easy, but I didn't find those so I was thinking I would need some combination of Position[...,Heads->True] and Part[...], this is much easier though, thanks! $\endgroup$ – mkm Nov 10 '15 at 7:32

Perhaps something like this:

bmesh = ToBoundaryMesh[Cylinder[{p1, p2}, r], 
  RegionBounds[Cylinder[{p1, p2}, r]]]

enter image description here

More information can be found on the ref page of ToBoundaryMesh.

  • $\begingroup$ Nice, thanks for contributing, your solution is very concise! I slightly prefer my own though since for my lattice application I wanted to generate lots of bars each with a small number of elements. I should have mentioned that in the question. $\endgroup$ – mkm Nov 12 '15 at 7:47
  • 1
    $\begingroup$ @mkm, no worries if you want a more complicated solution I can come with one - not a very typical request though ;-) $\endgroup$ – user21 Nov 12 '15 at 7:55
  • $\begingroup$ haha, sure. The solution can have more elements, but the cylinder needs less, man! :) $\endgroup$ – mkm Nov 12 '15 at 8:08

For the first half of Question 2, use BoundaryDiscretizeRegion. For some reason it's important to avoid machine-precision Real numbers. Instead of 0.5, use arbitrary-precision Rational 1/2.

{p1, p2, r} = {{-1, 0, 0}, {1, 2, 1}, 1/2};
reg = BoundaryDiscretizeRegion[Cylinder[{p1, p2}, r]]

triangulated cylindrical surface

And yeah, as pointed out by J. M.♦ in the comment, MeshCoordinates and MeshCells are for the rest of your questions.

Array[Graphics3D[GraphicsComplex[MeshCoordinates[reg], MeshCells[reg, #]]] &, 3, 0]

extracting mesh elements

  • $\begingroup$ This is cool, and simpler than my suggestion, can you make the mesh coarser? $\endgroup$ – mkm Nov 12 '15 at 7:50
  • $\begingroup$ MaxCellMeasure still doesn't work well, so basically no. $\endgroup$ – Taiki Nov 12 '15 at 8:06

Using the tip from the comments I figured out the following solution

bdg = BoundaryDiscretizeGraphics[Cylinder[{p1, p2}, r]];

(* Triangulate boundary quads and cap polygons *)
cylinderPolyAll = Map[(#[[-1]]) &, MeshCells[bdg, 2], 1];
cylinderQuad = Select[cylinderPolyAll, (Length[#] == 4) &];
cylinderQuadE = 
  Flatten[Map[({#[[{1, 2, 3}]], #[[{3, 4, 1}]]}) &, cylinderQuad], 
cylinderCaps = Select[cylinderPolyAll, (Length[#] != 4) &];
cylinderCapsE = 
  Flatten[Map[(Table[{#[[1]], #[[i + 1]], #[[i + 2]]}, {i, 1, 
        Length[#] - 2}]) &, cylinderCaps], 1];

(* Vertices and connectivity of triangulated cylinder *)
cylinderE = Join[cylinderQuadE, cylinderCapsE];
cylinderV = MeshCoordinates[bdg];

(* Visualise triangulated cylinder *)
cylinderVE = With[{v = cylinderV, e = cylinderE}, Table[
    {v[[e[[i, 1]]]], v[[e[[i, 2]]]], v[[e[[i, 3]]]]},
    {i, 1, Length[cylinderE]}]];
Graphics3D[Map[Polygon[#] &, cylinderVE]];

enter image description here

The sphere case is easier


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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