[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.
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