6
$\begingroup$

I need to find a normal pointing outside for every face / cell of a closed Mesh Region.

How can I do this?

Here's what I have now - mesh + mesh cells centers and I'm stuck and puzzled. There's VertexNormals, but there's no "CellNormals" or whatever else.

(* import OBJ *)
input = Import["torus.obj"];

(* Faces & Points *)
coords = MeshCoordinates[input]; (* вершины *)
cells = MeshCells[input, 2]; (* грани *)

(* Boundary Mesh Region *)
torus = BoundaryMeshRegion[coords, cells, 
   MeshCellStyle -> Opacity[0.3]];


(* Cell Centers *)
meshprimitives = MeshPrimitives[torus, 2];
cellcenters = 
  Table[RegionCentroid[meshprimitives[[i]]], {i, 
    meshprimitives // Length}];
ссPoints = ListPointPlot3D[cellcenters, PlotStyle -> Red];

(* Graph *)
Show[torus, ссPoints]

Here's what I need:

enter image description here

NB! The normals need to be pointed outside.

Please help!

$\endgroup$
7
  • $\begingroup$ Please povide a minimal working example, this will increase your chance to get helpful answers! $\endgroup$ Commented Jun 24, 2022 at 13:38
  • $\begingroup$ @UlrichNeumann I would, if I could ) $\endgroup$
    – Anton
    Commented Jun 24, 2022 at 13:41
  • $\begingroup$ Starting examplary with a Sphere[] ??? $\endgroup$ Commented Jun 24, 2022 at 13:49
  • $\begingroup$ @UlrichNeumann I could draw a vector ))) $\endgroup$
    – Anton
    Commented Jun 24, 2022 at 13:51
  • 1
    $\begingroup$ There's Region`Mesh`MeshCellNormals. See mathematica.stackexchange.com/questions/130226/… etc. from searching the site for MeshCellNormals. $\endgroup$
    – Michael E2
    Commented Jun 24, 2022 at 14:41

2 Answers 2

8
$\begingroup$

Here is an approach using the undocumented Region`Mesh`MeshCellNormals function mentioned previously in this answer, from which the vector plotting code I show below is also inspired.

First let's get a coarsely-discretized torus:

input = 
 DiscretizeRegion[
   ParametricRegion[
     {Cos[t] (3 + Cos[u]), Sin[t] (3 + Cos[u]), Sin[u]}, 
     {{t, 0, 2 Pi}, {u, 0, 2 Pi}}
   ],
 MaxCellMeasure -> 1000
]

3D torus, meshed

Then let's use the undocumented fucntion to calculate the direction of the normals to each face:

normals = Region`Mesh`MeshCellNormals[input, 2]

(* Out: 
{{0.999555, 0.00942983, 0.0282893}, {-0.652107, 0.577115, -0.491625}, ... , 
 {-0.847775, 0.493059, -0.195371}, {0.846814, -0.513404, 0.139001}}
*)

... and plot them on the surface, as arrows:

Show[
 input,
 Graphics3D[{
   Thickness[0.002], Arrowheads[Medium],
   {Darker[rc = RandomColor[]], FaceForm[rc], #} & /@
    MapThread[
     {#1, Arrow[{Mean@#1[[1]], Mean@#1[[1]] + Normalize@#2}]} &,
     {MeshPrimitives[input, 2], normals}
     ]
   }]
 ]

3D torus with cell normals plotted as arrows

$\endgroup$
2
  • $\begingroup$ Ah, I forgot that one. Very nice. $\endgroup$ Commented Jun 24, 2022 at 14:27
  • $\begingroup$ Excellent, thank you! $\endgroup$
    – Anton
    Commented Jun 24, 2022 at 14:31
8
$\begingroup$

The conventional way to get face normals is to use Newell's method (which I have also used in previous answers):

newellNormals[pts_?MatrixQ] := Module[{tp = Transpose[pts]}, Normalize[MapThread[Dot,
              {RotateLeft[ListConvolve[{{-1, 1}}, tp, {-1, -1}]], 
               RotateRight[ListConvolve[{{1, 1}}, tp, {-1, -1}]]}]]]

This assumes that all the polygons in your mesh are consistently oriented: if a polygon in your mesh is oriented anticlockwise from where it is being viewed, then the resulting normal will point in that direction. (Both FindMeshDefects[] and to a lesser extent FaceForm[] are useful for diagnostics like this.)

Since the OP does not give a usable example, I'll use one of the built-in meshes:

herbie = ExampleData[{"Geometry3D", "UtahVWBug"}, "MeshRegion"];
polys = MeshPrimitives[herbie, 2];
nrms = newellNormals @@@ polys;
Graphics3D[{{Arrowheads[Tiny], GrayLevel[0.25], 
             MapThread[With[{c = Mean @@ #1},
                            Arrow[Tube[{c, c + 5 #2}]]] &,
                       {polys, nrms}]},
            {Directive[Hue[0.6, 0.3, 0.85], EdgeForm[], 
                       FaceForm[Specularity[0.2, 30]]], polys}}, 
           Lighting -> {{"Ambient", GrayLevel[0.45]},
                        {"Directional", GrayLevel[0.3], ImageScaled[{2, 0, 2}]},
                        {"Directional", GrayLevel[0.33], ImageScaled[{2, 2, 2}]},
                        {"Directional", GrayLevel[0.3], ImageScaled[{0, 2, 2}]}}]

A Bug's Normals

$\endgroup$
1
  • $\begingroup$ Wow thank you this looks like what I was looking for !! $\endgroup$
    – Anton
    Commented Jun 24, 2022 at 14:15

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.