I am using Python scripting to define a mesh from a set of triangles, where the triangles are given by the XYZ coordinates of their 3 vertices. These triangles correspond to the outer contour of a roughly spherical nanoparticle (I work in atomistic modeling). When I pass the list of tirangles to a mesh object, I get some of the triangles are oriented the way I want (the normal pointing outward from the center of the nanoparticle) in gray color, and some show in black, which I understand to mean the surface is pointing inward. Intuitively, I assumed the normal is determined by the order in which the vertices are defined. So I wrote a script that calculates the cross product of (v12, v13) (where 1, 2, 3 are the vertices) and aligns the normal defined in this way with the vector pointing from the center of mass of the nanoparticle to the center of mass of the triangle in question. Indeed, I can get the triangles to be aligned or "antialigned" using this method, i.e., I can make all gray triangles black and viceversa, but I always get a random distribution of gray and black triangles, whereas I would expect all of them to be aligned or antialigned. So clearly I am missing something, but can't find on the online documentation how the order in which the triangle vertices are defined is linked to the definition of their normal.
The code I wrote is something like this:
Code: Select all
# This function changes the order in which the points are defined in the triangle to make sure
# its normal points outside of the nanoparticle. tri = [i, j, k] gives the indices of the vertices in
# a master list, and xyz gives the XYZ coordinates of these 3 vertices. Origin is the center of
# mass of the nanoparticle.
def tri_orient(tri, xyz, origin):
xyz = np.array(xyz)
origin = np.array(origin)
cm = (xyz[0] + xyz[1] + xyz[2])/3.
dir = cm - origin
v1 = xyz[1] - xyz[0]
v2 = xyz[2] - xyz[0]
if np.dot(np.cross(v1,v2), dir) >= 0:
return tri
else:
return [tri[0], tri[2], tri[1]]
# This loop goes over all triangles and orients them with the function above. tris is a list of index
# triplets and all_xyz is a numpy array that contains the XYZ coordinates of all the vertices.
triangles = []
for tri in tris:
tri = tri_orient(tri, all_xyz[tri], origin)
triangles.append(all_xyz[tri])
meshObject = Mesh.Mesh(triangles)
I must be on to something, in the sense that the order of definition of the vertices must be linked to the normal somehow (if I change the condition from >= 0 to < 0 then all the triangles change color). So my question is how I can ensure that the normal that FreeCAD sees is the same normal I *think* I'm setting up. Is this only determined by the vertices or is there another bit of missing information I need to provide to Mesh?
I'm using FreeCAD 0.18.4 on Ubuntu 20.04.