(MEL) unable to group uvs based on Area(Size)

polycounter lvl 10
Offline / Send Message
onionhead_o polycounter lvl 10
trying to write a procedure thats groups the uvs shells into 3 seperate categories (Small, Medium, Large). but running into an issue where small uv shells doesnt get cast to the correct array $uvShellSmlList. Im been spending the whole day looking and testing to see why its doing that.

Note this code only works on maya 2017.4 +  since texGetShell is a new procedure after uvToolkit was added.

global proc float[] getUVShellArea(){
global string $shellList[];
$shellList =`texGetShells`;
float $shellArea[];
//print $shellList;
//print (size($shellList));
for ($i = 0; $i < `size($shellList)`; $i++)
{

string $tempList[] = stringToStringArray($shellList[$i], " ");

// Calculate shell UV area
string $faceList[] = `polyListComponentConversion -fromUV -toFace $tempList`;
$faceAreas = `polyEvaluate -uvFaceArea $faceList`; // polyEvaluate returns a float[]
float $totalArea;
for ($faceArea in $faceAreas)
$totalArea += $faceArea;
$shellArea[$i] = $totalArea;
}
//print $shellArea;
return $shellArea;
}

// sum of total Area of all shells then divided by TotalShells to get Average area. function to group shells according the area. Split into 3 categories (Small,Mid,Large)
global proc string[] uvShellCompare(){
global string $shellList[];
float $shellArea[] = `getUVShellArea`;
float $sortedShellAreaList[] = `sort $shellArea`;
float $shellAreaMin = $sortedShellAreaList[0]; //gets the smallest shell
float $shellAreaMax = $sortedShellAreaList[size($shellArea)]; //gets the largest shell
float $shellAreaAvg;
float $shellAreaTotalSum;
string $uvShellSmlList[];
string $uvShellMidList[];
string $uvShellLarList[];
string $combShellList[];
for ($tmpshellAreas in $shellArea)
$shellAreaTotalSum += $tmpshellAreas;

print $shellAreaTotalSum;

//$shellAreaAvg = $shellAreaTotalSum / (size($shellArea)); // may not use this method in cases where theres a large disparity between shell sizes
//(len - 1) / 2 and len / 2 even/odd
if ((size ($sortedShellAreaList)) % 2 == 0){
//even
$shellAreaAvg = $sortedShellAreaList[((size ($sortedShellAreaList)) - 1)/ 2];
}
//odd
if ((size ($sortedShellAreaList)) % 2 != 0){
$shellAreaAvg = $sortedShellAreaList[(size ($sortedShellAreaList))/ 2];
}

print ("\n" + $shellAreaAvg);

for ($i = 0; $i <= `size($shellArea)`; $i++)
{
if ($shellArea[$i] < $shellAreaAvg && (equivalentTol($shellArea[$i],$shellAreaAvg,0.03) == 0))
{
$uvShellSmlList[size($uvShellSmlList)] = $shellList[$i];
}

if ($shellArea[$i] == $shellAreaAvg || (equivalentTol($shellArea[$i],$shellAreaAvg,0.03) == 1))
{
$uvShellMidList[size($uvShellMidList)] = $shellList[$i];
}

if ($shellArea[$i] > $shellAreaAvg && (equivalentTol($shellArea[$i],$shellAreaAvg,0.01) == 0))
{
$uvShellLarList[size($uvShellLarList)] = $shellList[$i];
}
}
$combShellList[0] = stringArrayToString($uvShellSmlList, " ");
$combShellList[1] = stringArrayToString($uvShellMidList, " ");
$combShellList[2] = stringArrayToString($uvShellLarList, " ");
return $combShellList;

}

{
string $testList[] = `uvShellCompare`;
print "\n";
print "Small ";
print $testList[0];
print "\n";
print "Medium ";
print $testList[1];
print "\n";
print "Large ";
print $testList[2];
}



Replies

  • ProperSquid
    Offline / Send Message
    ProperSquid polycounter lvl 8
    Just throwing a random guess out there, but my guess is when you sort shellArea, you are losing the indexes of the mesh, and that's why it isn't working as expected. If I were to do this in Python, I'd instead do something like this:

    # Assuming that getUVShellArea is a Python function.
    shellArea = getUVShellArea()

    # Enumerate will return a tuple of the index and the value in the shellArea
    # list. For example, if we have a list of two items, it'd look something like
    # this:
    # [(0, 5.0), (1, 4.3)]
    sortedShellAreaList = list(enumerate(shellArea))
    # Sort the list by the second item in the tuple.
    # Now the list will look something like this:
    # [(1, 4.3), (0, 5.0)]
    sortedShellAreaList.sort(key=lambda x: x[1])

    # Continue on from there

  • onionhead_o
    Offline / Send Message
    onionhead_o polycounter lvl 10
    thanks for the tip. I will double check on the sorted list part.

    Yeh i wish mel has tuples. not sure why they dont have it. So from what I understand is you put both the shells and the area together into the tuple and sorted it?

    If you dont mind i have another question. How do you separate numbers and group them. for example   rawNumbers = (0.2, 0.3 , 0.12, 2 ,3 ,7 ,10)  >>>>>>>> SmlNum = (0.12, 0.2, 0.3) MidNum = (2,3) LarNum(7,10). in my code im trying to use equivalentTol, which in my case is suppose to compare the numbers with a tolerance. I find it hard to troubleshoot.


  • ProperSquid
    Offline / Send Message
    ProperSquid polycounter lvl 8
    You're right about the first bit. Also, here's a way you can do the second part:

    mid = 0.0
    low = 0.0
    areas = set()

    # Get all of the areas, and make sure they're unique.
    for _, area in sortedShellArea:
        areas.add(area)

    # Convert the areas into a sorted list.
    areas = sorted(areas)
    # Pick an area that is in about the 2/3rds index position in the list, or
    # roughly mid.
    mid = max(mid, areas[int(len(areas) * 2.0 / 3.0]))
    # Pick an area that is in about the 1/3rds index position in the list, or
    # roughly low.
    low = max(low, areas[int(len(areas) * 1.0 / 3.0]))

    highAreas = []
    midAreas = []
    lowAreas = []

    # Go through the sorted shell list. If the area is less than or equal to low,
    # then it is low. If it is less than or equal to mid, then it is mid, otherwise
    # it is high.
    for index, area in sortedShellArea:
         if area <= low:
            lowAreas.append((index, area))
         elif area <= mid:
            midAreas.append((index, area))
         else:
            highAreas.append((index, area))

  • onionhead_o
    Offline / Send Message
    onionhead_o polycounter lvl 10
    ahh I see im gona try translating this in mel. I know i know python is better. but i dont have time to recode everything. This is part of a large procedure which has 800+ lines. Thanks for your help. I will post the solution up once i have something working.
  • onionhead_o
    Offline / Send Message
    onionhead_o polycounter lvl 10
    i tried to get as far as i can. but stuck on some syntax.
    //derived from texSortShellsByBounds, uses same idea of combining the shellarea into the shelllist

    global proc string[] sortShellsByUVArea(string $shellList[]){
        global string $shellArea[];
        string $prefixList[];

        for ($i = 0; $i < `size($shellList)`; $i++)
        {
            string $temp[] = stringToStringArray($shellList[$i], " ");

            string $faceList[] = `polyListComponentConversion -fromUV -toFace $temp`;
            $faceAreas = `polyEvaluate -uvFaceArea $faceList`; // polyEvaluate returns a float[]
            float $area;
            for ($faceArea in $faceAreas)
                $area += $faceArea;
                $shellArea[$i] = $area;
            $prefixList[$i] = ($shellArea[$i] + "%" + $shellList[$i]);
         }

    string $sortedShellList[];

    $sortedShellList = `sort($prefixList)`;

        return $sortedShellList;
    }

    global proc string[] uvShellCompare(){

        float $lowNum;
        float $midNum;
        string $rawShellList[] = `texGetShells` ;
        string $shellSmlList[];
        string $shellMidList[];
        string $shellLarList[];
        //float $highNum; no need anymore
        float $finalShellArea[];
        string $finalShellList[];
        string $combShellList[];
        string $sortedShellList[] = sortShellsByUVArea($rawShellList); //call procedure
       
        for ($i = 0; $i < size($sortedShellList); $i++)
            {
            string $regex = "[^ ]+ *";
            string $buffer[];
             $finalShellList[$i] = `substitute $regex $sortedShellList[$i] ""`;
             tokenize($sortedShellList[$i], "%", $buffer);
             $finalShellArea[$i] =  `float($buffer[0])`;
            }
           
        $lowNum = $finalShellArea[(int(size($finalShellArea)* 1.0 / 3.0)];
           $midNum = $finalShellArea[(int(size($finalShellArea)* 2.0 / 3.0)];
          
           for ($i = 0; $i < size($finalShellArea); $i++)
               {
               if ($finalShellArea <= lowNum){
                   $shellSmlList[size($shellSmlList)] = $finalShellList[$i];
                   }
               if ($finalShellArea <= midNum){
                   $shellMidList[size($shellMidList)] = $finalShellList[$i];
                   }
               else{
                   $shellLarList[size($shellLarList)] = $finalShellList[$i];
                   }
               }
              
           $combShellList[0] = stringArrayToString($shellSmlList, " ");
        $combShellList[1] = stringArrayToString($shellMidList, " ");
        $combShellList[2] = stringArrayToString($shellLarList, " ");
       return $combShellList;
    }

    uvShellCompare;


    having syntax error on this line
     $finalShellArea[$i] =  `float($buffer[0])`;
    Then of course the rest below fails.
  • onionhead_o
    Offline / Send Message
    onionhead_o polycounter lvl 10
    ok so after some more troubleshooting, i was able to solve the syntax errors. But getting incorrect results. where both Small shells and Medium shells identical.

    mesh to test

    new code
    //derived from texSortShellsByBounds, uses same idea of combining the shellarea into the shelllist

    global proc string[] sortShellsByUVArea(string $shellList[]){
        global string $shellArea[];
        string $prefixList[];

        for ($i = 0; $i < `size($shellList)`; $i++)
        {
            string $temp[] = stringToStringArray($shellList[$i], " ");

            string $faceList[] = `polyListComponentConversion -fromUV -toFace $temp`;
            $faceAreas = `polyEvaluate -uvFaceArea $faceList`; // polyEvaluate returns a float[]
            float $area;
            for ($faceArea in $faceAreas)
                $area += $faceArea;
                $shellArea[$i] = $area;
            $prefixList[$i] = ($shellArea[$i] + "%" + $shellList[$i]);
         }

    string $sortedShellList[];

    $sortedShellList = `sort($prefixList)`;

        return $sortedShellList;
    }

    global proc string[] uvShellCompare(){

        float $lowNum;
        float $midNum;
        string $rawShellList[] = `texGetShells` ;
        string $shellSmlList[];
        string $shellMidList[];
        string $shellLarList[];
        //float $highNum; no need anymore
        float $finalShellArea[];
        string $finalShellList[];
        string $combShellList[];
        string $sortedShellList[] = sortShellsByUVArea($rawShellList); //call procedure
       
        for ($i = 0; $i < size($sortedShellList); $i++)
            {
            string $regex = "[^ ]+ *";
            string $buffer[];
             $finalShellList[$i] = `substitute $regex $sortedShellList[$i] ""`;//removes the area prefix, leaves just the shell list
             tokenize($sortedShellList[$i], "%", $buffer);// gets the area before the %
             $finalShellArea[$i] =  (float($buffer[0]));
            }
           
        int $ArrayTokenLow = (ceil((size($finalShellArea))* (1/3)));
        int $ArrayTokenMid = (ceil((size($finalShellArea))* (2/3)));
       
        $lowNum = $finalShellArea[$ArrayTokenLow];
           $midNum = $finalShellArea[$ArrayTokenMid];
          
           for ($i = 0; $i < size($finalShellArea); $i++)
               {
               if ($finalShellArea[$i] <= $lowNum){
                   $shellSmlList[size($shellSmlList)] = $finalShellList[$i];
                   }
               if ($finalShellArea[$i] <= $midNum){
                   $shellMidList[size($shellMidList)] = $finalShellList[$i];
                   }
               else{
                   $shellLarList[size($shellLarList)] = $finalShellList[$i];
                   }
               }
              
           $combShellList[0] = stringArrayToString($shellSmlList, " ");
        $combShellList[1] = stringArrayToString($shellMidList, " ");
        $combShellList[2] = stringArrayToString($shellLarList, " ");
       return $combShellList;
    }

    {
        string $testList[] = `uvShellCompare`;
        print "\n";
        print "Small ";
        print $testList[0];
        print "\n";
        print "Medium ";
        print $testList[1];
        print "\n";
        print "Large ";
        print $testList[2];
        }

    last bit is used to print the list

    EDIT: added some more comments
  • ProperSquid
    Offline / Send Message
    ProperSquid polycounter lvl 8
    Yeah, I think I've reached the end of my usefulness here. I tend to avoid MEL like the plague, and I don't have a copy of Maya at home, so I wouldn't be able to tinker with this. The only thing that I can offer is you should be using something like an else if or elif (not sure what the syntax is in MEL) to make sure that the mid list does not contain the low list. Otherwise the two if statements are treated as independent, when they are dependent.
  • onionhead_o
    Offline / Send Message
    onionhead_o polycounter lvl 10
    np you help me out alot already. really appreciate it. I will eventually make my way to python haha.
Sign In or Register to comment.