Notifications
Clear all

[Closed] Get UV face's area

So I an edit poly mesh. I select a face is there a way to get the area of that face in a given map channel i.e. its UVs. Preferably without having to add a Unwrap modifier. I can get the vert’s channel position via GetMapVertex, and could calculate if everything is a triangulated. But if more than three verts I feel like things could get twisty.

4 Replies
    fn AreaOfUVPolyFace pobj  mapc face =
    (
    	mverts = polyop.getmapface pobj mapc face; 
    	uvs = for v in mverts collect  polyop.getmapvert pobj mapc v;
    		
    	a = 0.0;
    	for v = 1 to uvs.count do
    	(
    		nv = v + 1;
    		if v == uvs.count then nv = 1;
    			
    		a = a + uvs[v].x * uvs[nv].y;
    		a = a - uvs[v].y * uvs[nv].x;
    	)
    	a * 0.5;
    )	

    AreaOfUVPolyFace $ 1 ((polyop.getFaceSelection $) as array)[1]

you can loose the * 0.5 if you want as there are no actual units and everything is relative.

Looks like unwrap fails to calculate correct areas for concave polygons.

(	
	
	fn AreaOfUVPolyFace pobj  mapc face =
	(
		mverts = polyop.getmapface pobj mapc face; 
		uvs = for v in mverts collect  polyop.getmapvert pobj mapc v;
			
		a = 0.0;
		for v = 1 to uvs.count do
		(
			nv = v + 1;
			if v == uvs.count then nv = 1;
				
			a = a + uvs[v].x * uvs[nv].y;
			a = a - uvs[v].y * uvs[nv].x;
		)
		a * 0.5;
	)	

	delete objects
	objs = #(
		channel channel_width:100 channel_length:100 channel_thickness:40 wirecolor:red,
		Ngon radius:45 cornerRadius:0 nsides:6 circular:off scribe:1 wirecolor:green
	)
	
	objs[3] = copy objs[2] wirecolor:yellow
	convertToPoly objs[3]	
	polyop.setVert objs[3] 5 [20,0,0]
	update objs[3]

	for obj in objs do
	(
		
		convertToPoly obj
		addModifier obj (Unwrap_UVW())
		select obj
		max modify mode
			
		uvarea  = 0
		geoarea = 0
		obj.modifiers[1].getAreaByNode #{1} &uvarea &geoarea obj
			
		format "%\n" obj
		format "unwrap uvarea   : %\n" uvarea
		format "AreaOfUVPolyFace: %\n\n" (AreaOfUVPolyFace obj 1 1)
		
	)
)

Klvnk I tried your method and seemed like it was getting the bounds rather than the face area like Serejah stated. I ended up making a copy of the mesh and putting the uvs in world space, and then measuring faces area via polyop.getFaceArea then handing the data I needed back the original mesh. Not super fast or elegant but worked for what I was doing.

			-- Put the UVs into world space, and reset exform.
		channelInfo.CopyChannel faceToCheck 3 spnChan.value 
		channelInfo.PasteChannel faceToCheck 1 0
		channelInfo.NameChannel faceToCheck 1 0 "-none-"
		resetxform faceToCheck
		collapsestack faceToCheck

looks pretty solid to me

fn AreaOfUVPolyFace pobj  mapc face =
(
	mverts = polyop.getmapface pobj mapc face; 
	uvs = for v in mverts collect  polyop.getmapvert pobj mapc v;
		
	a = 0.0;
	for v = 1 to uvs.count do
	(
		nv = v + 1;
		if v == uvs.count then nv = 1;
			
		a = a + uvs[v].x * uvs[nv].y;
		a = a - uvs[v].y * uvs[nv].x;
	)
	a * 0.5;
)	

fn buildpoly =
(
	verts = #([0.25,0.0,0],[0.75,0.0,0],[0.5,0.5,0],[0.75,1.0,0],[0.25,1.0,0],[0.0,0.5,0]);
	faces = #([1,2,3],[1,3,6],[3,4,5],[3,5,6]);
	edges = #(#(true,true,false),#(false,false,true),#(true,true,false),#(false,true,false));

	msh = trimesh();
	msh.numverts = verts.count;
	msh.numfaces = faces.count;
		
	for v = 1 to verts.count do setvert	msh v verts[v];
	for f = 1 to faces.count do 
	(
		setface msh f faces[f];
		setedgevis msh f 1 edges[f][1];
		setedgevis msh f 2 edges[f][2];
		setedgevis msh f 3 edges[f][3];
	)	

	mobj = mesh mesh:msh;
	meshop.makeMapPlanar mobj 1;
	converttopoly mobj;
)


pobj = buildpoly();
result = (AreaOfUVPolyFace pobj  1 1) - polyop.getFaceArea pobj 1;

or

pstar = converttopoly (Star radius1:0.5 radius2:0.25 numPoints:24 pos:[0.5,0.5,0]);
polyop.setmapsupport pstar 1 true;

AreaOfUVPolyFace pstar  1 1;
polyop.getFaceArea pstar 1;

though if you have polys with “internal” verts may throw up unusual results

also checked it against this…

def_struct_primitive(polyop_getUVFaceArea, polyop, "getUVFaceArea");

Value* polyop_getUVFaceArea_cf(Value** arg_list, int count)
{
	enum args { kpoly, kmapchannel, kface, knum_of_args };

	check_arg_count(getUVFaceArea, knum_of_args, count);
	MNMesh* pmesh = get_polyForValue(arg_list[kpoly], MESH_READ_ACCESS, NULL, getUVFaceArea);

	int mapchannel = arg_list[kmapchannel]->to_int();
	checkMapChannel(pmesh, mapchannel);

	int face = arg_list[kface]->to_int() - 1; 
	range_check(face,0,(pmesh->numf - 1), GetString(IDS_FACE_INDEX_OUT_OF_RANGE));

	MNFace& mnface = pmesh->f[face];

	Tab<int> triangles;
	mnface.GetTriangles(triangles);  // get the tri (as indices of the face vert array)

	MNMapFace* mapface = pmesh->MF(mapchannel, face);
	Point3* mapverts  = pmesh->M(mapchannel)->v;

	float area = 0.0f;
	int numtriangles = mnface.deg - 2;
	for(int t = 0; t < numtriangles; ++t)
	{
		int i = t * 3;
		area += AreaOfTriangle(mapverts[mapface->tv[triangles[i]]],mapverts[mapface->tv[triangles[i+1]]],
			mapverts[mapface->tv[triangles[i+2]]]);
	}
	return Float::intern(area);
}

and all seems fine