How to obtain the area of a single face of a mesh?

How to obtain the area of ​​a single face of a mesh?

Hello - Ctrl-Shift select the face and DupBorder. If the face is planar, Area on that curve should report it. If not, Patch the border curve and ask for Area on the resulting surface.

-Pascal

I need in Python

Hello - here is an example that may help - you need to pass in the correct mash face index - I just used [0] here.

import rhinoscriptsyntax as rs
import Rhino

def test():
    
    id = rs.GetObject(filter = 32, preselect=True)
    if not id: return
    
    mesh = rs.coercemesh(id)
    
    mesh2 = mesh.Faces.ExtractFaces([0])
    info = Rhino.Geometry.AreaMassProperties.Compute(mesh2, True, False, False, False)
    print info.Area
    pass
test()

-Pascal

So I need to extract the face first and then request the area.
Why does a face within the mesh have no identity?

Hello - the Area finder works on a mesh, not a mesh face in a larger mesh, so by extracting that as its own mesh, you can feed it to the area finding function. Note the mesh here is in memory, for the purposes of the area query only, you will not get it in the file unless you specifically add it.

-Pascal

Hello - what version of Rhino are you running? Please run SystemInfo in Rhino and post the results.

https://developer.rhino3d.com/api/RhinoCommon/html/M_Rhino_Geometry_Collections_MeshFaceList_ExtractFaces.htm

-Pascal

Rhino 5 R14…

Hello - for V5, I guess you need to create your own mesh:

import rhinoscriptsyntax as rs
import Rhino

def test():
    
    id = rs.GetObject(filter = 32, preselect=True)
    if not id: return
    
    mesh = rs.coercemesh(id)
    face = mesh.Faces[0]

    source_verts = [face.A, face.B, face.C, face.D]
    verts = mesh.Vertices
    
    mesh2 = Rhino.Geometry.Mesh()
    for item in source_verts:
        mesh2.Vertices.Add(verts[item])
        
    mesh2.Faces.AddFace(0,1,2,3)
    mesh2.Normals.ComputeNormals()
    mesh2.Compact()
    
    info = Rhino.Geometry.AreaMassProperties.Compute(mesh2)
    print info.Area
  
test()

-Pascal

Hi Pascal,
thanks for the nice script. I am wondering if there is a trick to prevent error of multiple targets in Python?

Runtime error (ArgumentTypeException): Multiple targets could match: Compute(Surface), Compute(IEnumerable[GeometryBase]), Compute(Brep), Compute(Curve), Compute(Hatch), Compute(Mesh)

Traceback:
  line 20, in script

I understand this is due to the method has different overload version which it is not a problem in C#. While in Python, do you have any suggestion?

Best,

Xingxin

P.S. Below is the script I want to use this method to compute the Barycentric Cell of such vertex

areas = [0] * mesh.Vertices.Count
for i in range(mesh.Faces.Count):
    face = mesh.Faces.ExtractFaces([i])
    area = Rhino.Geometry.AreaMassProperties.Compute(face, True, False, False, False).Area / 3
    areas[mesh.Faces[i][0]] += area
    areas[mesh.Faces[i][1]] += area
    areas[mesh.Faces[i][2]] += area
a = areas

Hello - here is the example I keep as reference, from Dale Fugier -

import Rhino
import scriptcontext as sc
import rhinoscriptsyntax as rs

#import a couple of things from System
import System.Collections.Generic.IEnumerable as IEnumerable 
import System.Double as sd

tol = .001
targetId = rs.GetObject("Select surface or polyusurface to split", filter=8+16, preselect=True)
targetBrep = rs.coercebrep(targetId)

cuttingIds = rs.GetObjects("Select cutting surfaces or polysurfaces", filter=8+16)
cuttingBreps = [rs.coercebrep(id) for id in cuttingIds]

# When calling the splitter, you need to first tell Python what type of object you are going to 
# give it for each parameter and then provide the actual parameter values:
# In this case the method needs a list of either breps or curves and a tolerance
#the code specifies the two types ahead of time - Rhino.Geometry.Brep and a number, System.Double, here as 'sd'
# imported at the top of the script. 
splitList = targetBrep.Split.Overloads[IEnumerable[Rhino.Geometry.Brep], sd]( cuttingBreps, tol)


newIds = [ sc.doc.Objects.AddBrep(brep) for brep in splitList]

-Pascal

Doooope! Thank you so much!

In case other scripters would need it, here is the code:

import System.Boolean as bool
face = mesh.Faces.ExtractFaces([0])
info = Rhino.Geometry.AreaMassProperties.Compute.Overloads[Rhino.Geometry.Mesh, bool, bool, bool, bool](face, True, False, False, False)

If you want to compute face areas of a RhinoCommon mesh you could also implement e.g. Heron’s formula, like so:

import math

def triangleArea(ptA,ptB,ptC):
    
    """ Compute area of triangle using Heron's Formula """
    
    dA = ptB.DistanceTo(ptC)
    dB = ptA.DistanceTo(ptC)
    dC = ptA.DistanceTo(ptB)
    p = (dA+dB+dC)/2
    area = math.sqrt(p*(p-dA)*(p-dB)*(p-dC))
    
    return area

def computeMeshFaceAreas(mesh):
    
    """ Computes the face areas for a mesh using triangleArea """
    
    faceAreas = []
    vts = mesh.Vertices
    for f in mesh.Faces:
        if f.IsTriangle:
            fA = triangleArea(vts[f.A],vts[f.B],vts[f.C])
        elif f.IsQuad:
            fA1 = triangleArea(vts[f.A],vts[f.B],vts[f.C])
            fA2 = triangleArea(vts[f.A],vts[f.C],vts[f.D])
            fA = fA1 + fA2
        faceAreas.append(fA)
        
    return faceAreas
1 Like

Hi Anders,

thank you for the help! I know this formula. Similar to your code:

def triangleArea(pt_0,pt_1,pt_2):
    
    e_01 = pt_1 - pt_0
    e_12 = pt_2 - pt_1
    norm = Rhino.Geometry.Vector3f.CrossProduct(e_01, e_12)
    area = norm.Length / 2
    
    return area

I was just a bit lazy and want to use API directly haha…

Anyway, thanks for dropping the advice! Hope you have fun with your skateboard!

1 Like

Hi Pascal,

Just FYI, the ExtractedFaces() is not robust enough I supposed. Here attached is the manifold failed to extract faces.

[NOT ROBUST] Mesh.Faces.ExtractFaces().gh (173.5 KB)

Best,

Xingxin

What are you expecting it to do in your script? The method essentially pops (to use Python lingo) a sub-mesh from a mesh by a list of face indices:

210512_ExtractMeshFaces_GHPython_00.gh (171.1 KB)

If you’re looking to just delete faces you can use Mesh.Faces.DeleteFaces.

Hi Anders,

I am just playing with @pascal 's method to get a list of MeshFaces area by looping over the mesh using Mesh.Faces.ExtractFaces. And I found out that it may fail to extract…

That’s probably not a great logic: When you manipulate the input mesh at each iteration (i.e. pop a face), the indices in your for loop will eventually exceed the amount of faces in the mesh (i.e. the face count drops at each iteration):

Edit: You could use a while loop, but still it feels odd to implement ExtractFaces for this (in that it is meant to operate on a list of face indices):

Hi Anders,

thanks for the reply! Yeah, I also found out the function literally extract rather than duplicate then extract… No worries, I was just playing with these function.

Thanks for the help!

1 Like