how to get area of one componennt polygon face


#1

how to get area of one componennt polygon face

hi,super guy,I got a problem,when I want to get area of one componennt polygon face,
maya mel command “polyEvaluate -area” always return whole polygon object area,as follow:

//create a polyCube
polyCube -n pCube1;
//select one of componennt faces
select -r pCube1.f[1] ;
//get faces area
polyEvaluate -area;
// Result: 6 //
polyEvaluate -area pCube1.f[1];
// Result: 6 //

any one know why? have any solution for that? thanks!


#2

its because the command is made that way :confused:

see: polyEvaluate

I mean… thats pretty clear…
You could “Compute the area of a triangle” ;] but of non-trianulated face?.. dunno now.


#3

you could make a temp copy of the surface, delete that one face, and then compare the result of -area maybe? that should be relatively quick if your polygon is not extremely complex-


#4

what greatPumpkin said should be a good solution.
Here’s a small script which does what he said :

//select the obj you want
 
 $theFaceIndex = 3; // set the index of the face you want to calculate
 $theDup = `duplicate -rr`;
 select -r ($theDup[0] + ".f[" + $theFaceIndex +"]");
 invertSelection;
 doDelete;
 select -r $theDup;
 $res = `polyEvaluate -worldArea`;
 delete $theDup;

#5

That looks good- only thing i would recommend changing as a matter of good practice is to not invert selection and delete. There are very few commands in mel that require you to actual select anything, so it’s a good habit to avoid them if you can-

Deleting a single face and running polyEvaluate twice will prolly be more efficient- select and delete commands or anything that will require the display to update will generally really bog maya down (although in this case i suppose it’s irrelevant given it looks like you’re only doing one face/object at a time unless your object is very complex-)

The code below can be done with selected object or selected faces as well if you need help with that give a yell-


  $targObject = [name of target object]
  $preRes = `polyEvaluate =worldArea $targObject`;
  $theFaceIndex = 3; // set the index of the face you want to calculate
  $theDup = `duplicate -rr $targObject`;
  delete ($theDup[0] + ".f[" + $theFaceIndex +"]");  
  $res = `polyEvaluate -worldArea $theDup`;
  delete $theDup;
  float $postRes = ($preRes - $res);


#6

or you need not make a duplicate object

global proc float sbGetPolyFaceArea(string $face)
{
	//get the name of the object
	string $object = `match "[^.]+" $face`;
	//get the area
	float $before[] = `polyEvaluate -area $object`;
	//delete the face
	delete $face;
	//get the new area
	float $after[] = `polyEvaluate -area $object`;
	//undo the delete
	undo;
	return ($before[0] - $after[0]);
}

i dont think this will work if the poly has only one face though


#7

If you know the face number, get the bounding edges and work out the area yourself?

This way you don’t rely on any duplicating of any thing which will slow maya down and in some cases depending on the complexity of the mesh or the uv /colorset or animation setup on the model crash maya… or corrupt the mesh. Comes from experience.

Besides this way you can build a building block process that may come in for more complex work at a later date.


#8

Here are two mel commands to calculate the area of a face in world space:

global proc float areaOfTriangle( string $mesh, string $vertIndices[] ) {
 	vector $verts[3];
 	
 	// get the transform node for the mesh
 	string $transform[] = `listRelatives -p $mesh`;
 
 	// query the matrix transform
 	float $transformMatrix[] = `xform -q -ws -m $transform[0]`;
 	
 	int $i;
 	for ($i=0; $i<3; $i++) {
 		// vert pos with tweaks
 		vector $vert = `getAttr ($mesh+".vt["+ $vertIndices[$i] +"]")`;
 		vector $offset = `getAttr ($mesh+".pt["+ $vertIndices[$i] +"]")`;
 		$vert = $vert + $offset;
 		
 		// apply the transform matrix to the point
 		float $v[] = pointMatrixMult($vert, $transformMatrix);
 		$verts[$i] = <<$v[0], $v[1], $v[2]>>;
 	}
 	
 	// calculate the area using the cross product of vectors
 	vector $v1 = $verts[1] - $verts[0];
 	vector $v2 = $verts[2] - $verts[0];
 	return abs(cross($v1, $v2)) / 2;
 }
 
 
 global proc float areaOfPolygon( string $mesh, int $face ) {
 	float $area = 0;
 	
 	// get the vertex indices
 	select -r ($mesh+".f["+$face+"]");
 	string $vertIndicesStr[] = `polyInfo -fv`;
 	
 	// place the indices into an array
 	string $vertIndices[];
 	tokenize $vertIndicesStr[0] $vertIndices;
 	
 	// note the vert count for the polygon
 	int $vertCount = `size($vertIndices)` - 2;
 	
 	// calculate the area based on polygon type
 	
 	// triangle
 	if ($vertCount == 3) {
 		string $triangle[3] = {$vertIndices[2], $vertIndices[3], $vertIndices[4]};
 		
 		$area = areaOfTriangle($mesh, $triangle);
 	} 
 	// quad (decompose into two triangles)
 	else if ($vertCount == 4) {
 		// 
 		string $triangle1[3] = {$vertIndices[2], $vertIndices[3], $vertIndices[4]};
 		string $triangle2[3] = {$vertIndices[2], $vertIndices[4], $vertIndices[5]};
 		
 		$area = areaOfTriangle($mesh, $triangle1) + areaOfTriangle($mesh, $triangle2);
 	} 
 	// n-gon (decompose into n - 2 triangles where n = # of verts)
 	else {
 		int $i;
 		for ($i=0; $i < $vertCount-2; $i++) { 
 			string $triangle[3] = {$vertIndices[2], $vertIndices[$i+3], $vertIndices[$i+4]};
 			
 			$area += areaOfTriangle($mesh, $triangle);
 		}
 	}
 	
 	return $area;
 }

You call the main function like this with the mesh shape and the face number you want the area for:

$area = areaOfPolygon("pSphereShape1", 25);
 print ($area + "
");

You could get the total area of a selected mesh like this (works up to a couple thousand faces, then it is prohibitively slow):


 float $area = 0;
 
 // get selection
 string $sel[] = `ls -sl`;
 if (size($sel) == 0)
 	error "No objects were selected.
";
 
 
 string $s[] = `listRelatives -s $sel[0]`;
 int $f[] = `polyEvaluate -f $s[0]`;
 
 string $mesh = $s[0];
 int $faceCount = $f[0];
 
 int $i;
 for ($i=0; $i<$faceCount; $i++)
 	$area += areaOfPolygon($mesh, $i);
 
 print("Total area: " + $area + "
");

There may be a much faster way to do this in mel. The slowdown is maybe polyInfo- it has to run on a selected face. On a couple thousand polygons, that’s a lot of selections! Yet, for testing a couple faces, the command is instantaneous.
-shawn


#9

there is already a mel script calculating area
polyfacearea.mel

how about calculating volume of a polygon ?
anything about this ?

I need a good mathematic forum site or a C++ library that we can port to mel ?


#10

I wish I had known that claudiod! On the other hand, that script uses polyTriangulate (creating a new node in the network each time!) followed by an undo (that’s a lot of undo’s) to return the face to its original untessellated state and remove the node. It uses four square roots per triangle to calculate the area. I thought my version slow, but this must run like molasses :slight_smile:

Do you mean the volume of a polygon mesh? (…though some individual polygons are not planar and you could calculate the volume they occupy) There is in maya a mel script or command that calculates the volume of an entire poly mesh. I think it’s listed in the Polygon section of the mel command documentation. You could also fill a mesh with nParticles now that they have that command and it would give you an approximation.

Edit: The volume script is called computePolysetVolume. Select a poly object and run it.

-shawn


#11

and here is my version…select obj faces and run pkFaceArea(0,0);

   
proc float pkVertexVectorArea(string $obj, int $v0, int $v1, int $v2, int $local){
 float $a[], $b[], $c[];
 //get vertex world positions
 if($local){
  $a = `pointPosition -local ($obj + ".vtx[" + $v0 + "]")`;
  $b = `pointPosition -local ($obj + ".vtx[" + $v1 + "]")`;
  $c = `pointPosition -local ($obj + ".vtx[" + $v2 + "]")`;
 }else{ 
  $a = `pointPosition -world ($obj + ".vtx[" + $v0 + "]")`;
  $b = `pointPosition -world ($obj + ".vtx[" + $v1 + "]")`;
  $c = `pointPosition -world ($obj + ".vtx[" + $v2 + "]")`;
 }
 //compute components of cross product
 float $vx = ($b[1]-$a[1])*($c[2] - $a[2]) - ($b[2]-$a[2])*($c[1] - $a[1]);
 float $vy = ($b[2]-$a[2])*($c[0] - $a[0]) - ($b[0]-$a[0])*($c[2] - $a[2]);
 float $vz = ($b[0]-$a[0])*($c[1] - $a[1]) - ($b[1]-$a[1])*($c[0] - $a[0]);
 vector $v = <<$vx,$vy,$vz>>;
 //get magnitude of cross product vector
 float $mag = `mag $v`;
 float $area = 0.5 * $mag;
 return $area;
}
global proc float pkFaceArea(int $local, int $verbosity){
string $sel[] =`ls -sl -fl`;
if(!`size $sel`)error "Must select some poly faces";
float $result = 0.0;
float $a[], $b[], $c[];
for($i=0;$i<`size $sel`;++$i){
 //print $sel[$i];
 string $polyData[] =`polyInfo -faceToVertex $sel[$i]`;
 //print $polyData;
 string $verts[];
 tokenize $polyData[0] $verts;
 //print $verts;
 string $name[];
 tokenize $sel[$i] "." $name;
 //print $name;
 float $area;
 for($j=3;$j<(`size $verts`- 1);++$j){
  $area = pkVertexVectorArea($name[0],$verts[2],$verts[$j],$verts[$j+1],$local);
  //print ("Area is: " + $area + "
");
  $result += $area;
 }
 if($verbosity){
  print ("Summed Face Area is: " + $result + "
");
  float $t[] = `polyEvaluate -area $name[0]`;
  print ("by polyEvaluate:	 " + $t[0] +"
");
 }
}
return $result;
}


#12

This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.