# Face area calculation too slow

#1

Trying to calculate surface areas with greater precision than the “meshop.getfacearea()” method. I need to calculate in double precision, so using a bit of .net to give me greater accuracy. Any thoughts on how I can speed this up without compromising accuracy? (Is really quite slow with high poly objects)

``````Pt = dotnetclass "System.Windows.Media.Media3D.point3d"
Crossproduct = (dotnetclass "System.Windows.Media.Media3D.Vector3D").Crossproduct
Fn GetFaceArea obj faces =
(
start = timeStamp()
TotalArea = 0
faces = (faces as array)
for i = 1 to faces.count do
(
V = (meshop.GetVertsUsingFace obj i)as array
if V.count == 3 do
(
Verts = (for j = 1 to 3 collect (getvert obj V[j]))
Pt1 = dotnetobject Pt (Verts[1].x) (Verts[1].y) (Verts[1].z)
Pt2 = dotnetobject Pt (Verts[2].x) (Verts[2].y) (Verts[2].z)
Pt3 = dotnetobject Pt (Verts[3].x) (Verts[3].y) (Verts[3].z)
TotalArea += ((Crossproduct (pt.subtract pt1 pt2) (pt.subtract pt1 pt3)).length)/2.0
)
)
end = timeStamp()
format "Processing took % seconds\n" ((end - start) / 1000.0)
Return (TotalArea)
)``````

#2

I didn’t check whether unwrap getArea function uses double precision to calc the area (unlikely), but it returned exactly the same result as yours and did it substantially faster. So why complicate things?

``````t1=timestamp();hf = heapfree

\$.modifiers[1].getarea #{1..\$.numfaces} &x &y &width &height &areaUVW &areaGeom

format "Time: %sec. Mem: %  Area: %\n" ((timestamp()-t1)/1000 as float) (hf-heapfree) areaGeom

-- or simply
t1=timestamp();hf = heapfree

mesh_area = meshop.getFaceArea \$ #all -- returns exactly the same result as your double precision fn

format "Time: %sec. Mem: %  Area: %\n" ((timestamp()-t1)/1000 as float) (hf-heapfree) mesh_area``````

upd
here’s the optimized version. It is still much slower compared to meshop.getFaceArea and the difference in accuracy not that big

``````
fn GetFaceArea obj faces =
(
start = timeStamp()
TotalArea = 0
sqrtd = (dotNetClass "system.math").sqrt

/*
-- #1
fn CrossProdLengthDouble a b =
(
-- 		x = (a.Y as double) * b.Z - (a.Z as double) * b.Y
-- 		y = (a.Z as double) * b.X - (a.X as double) * b.Z
-- 		z = (a.X as double) * b.Y - (a.Y as double) * b.X

sqrtd (((a.Y as double) * b.Z - (a.Z as double) * b.Y)^2 + ((a.Z as double) * b.X - (a.X as double) * b.Z)^2 + ((a.X as double) * b.Y - (a.Y as double) * b.X)^2)
)

for f in faces do
(
V  = getFace obj f
v1 = getvert obj V[1]
TotalArea += CrossProdLengthDouble (v1 - (getvert obj V[2])) (v1 - (getvert obj V[3]))
)
*/

-- #2 more optimized
tri = snapshotAsMesh obj
for f in faces do
(
V = getFace tri f
v1 = getvert tri V[1]
a  = v1 - getvert tri V[2]
b  = v1 - getvert tri V[3]

TotalArea += sqrtd (((a.Y as double) * b.Z - (a.Z as double) * b.Y)^2 + ((a.Z as double) * b.X - (a.X as double) * b.Z)^2 + ((a.X as double) * b.Y - (a.Y as double) * b.X)^2)
)
free tri
end = timeStamp()
format "Processing took % seconds.  Area: %\n" ((end - start) / 1000.0) (TotalArea / 2.0)
TotalArea / 2.0
)

GetFaceArea \$ #{1..\$.numfaces}``````

#3

Floating point precision is usually sufficient for any calculation in 3DS MAX. But you should use the work unit scale appropriate for your task. That for some reason, some projects are the last to care …