QHull to Maya Integration-ResearchNodes

From scripting
Revision as of 19:46, 24 April 2017 by Nickpisca (talk | contribs) (Created page with "http://researchnodes.org/doku.php?id=cellularaggregation:qmel.mel // ===================================================================== // Qhull - Maya interoperabilit...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

http://researchnodes.org/doku.php?id=cellularaggregation:qmel.mel


// =====================================================================
// Qhull - Maya interoperability
//
// Written by : Scott Maggart
// Date : Nov 24, 2006, Dec 10, 2006
// Program : Point Cloud Convex Envelope
// Dependancies : Qhull (www.qhull.org)
// 
/* 
OK.  So the problem remains getting an ORDERED list of 
point indexes for voronoi vertices.  I can easily get the
points, and I can get a big list of indices, but I cannot 
yet find the way to get a list of polygon vertices.  I will
send an email to the Qhull guys and see if I can get an answer.
This is still producing some really interesting result even
when just using Delaunay.  Try building a somewhat regular
form with points and use the demo where you can select the
points.  The voronoi WILL work the same once we get this
issue resolved. 
*/

proc vector[] genPoints(int $quant, float $min, float $max)
{   
    // This generates 3D vectors in random space and returns as a list
    vector $points[];
    vector $P;
    for ($i=0; $i<$quant; $i++)
    {
        $P = <<(rand($min, $max)),(rand($min, $max)),(rand($min, $max))>>;
        $points[size($points)] = $P;
        spaceLocator -p ($P.x) ($P.y) ($P.z); // make a locator to see points
    }
    return $points;
}

proc vector[] genPointsFromSurf(int $quant)
{   

    string $obj[] = `ls -sl -tr`;
    print $obj; 
    vector $points[];
    vector $P;
    for ($i=0; $i<$quant; $i++)
    {
        int $sel = rand (size($obj)-1);
        string $O = $obj[$sel];

        float $u = `getAttr ($O+".spansU")`+`getAttr ($O+".degreeU")`;
        float $v = `getAttr ($O+".spansV")`+`getAttr ($O+".degreeV")`;
        float $U = `rand $u`;
        float $V = `rand $v`;
        
        $P = `pointPosition ($O+".uv["+$U+"]["+$V+"]")`;
        $points[size($points)] = $P;
        spaceLocator -p ($P.x) ($P.y) ($P.z); // make a locator to see points
    }
    return $points;
}


proc string PointsToFileForQhull(vector $Points[], int $show)
{
    // Run through a list of vectors and write a file readable for Qhull
    //string $dir = "/Users/scottmaggart/Desktop/"; //enter the path to the work folder
    $dir = `internalVar -utd`;
    $FileName = ( $dir + "QtempIn" ); // Make a temp output file
    $fileId=`fopen $FileName "w"`; // open for writing
    string $output = "3\n"+size($Points)+"\n"; // First line (Qhull format)
    for ($p in $Points)
    {
        string $currLine = ($p.x + " " + $p.y + " " + $p.z+"\n"); // Points format
        $output = $output+$currLine; // This compound the entire string to one big string.
                                     // The \n above causes the next line instead of <Enter>
    }
    fwrite $fileId $output; // write the file
    fclose $fileId; // close the file... MUST DO THIS ALWAYS
    return $FileName; // so we can pass the exact location to the read-in proc
}

proc string[] runQhull(string $FileNameIN, string $Type, int $show)
{   
    // Send commands to Qhull through the system command prompt
    string $dir = `internalVar -utd`; 
    string $FileNameIndexes = ( $dir + $Type + "Indexes" );
    string $FileNamePoints = ( $dir + $Type + "Points" );

    if ($Type == "delaunay")
        {
        // For Delaunay, we only want an index list of how to assemble
        // $Points into facets
        //
        system("qhull i < "+$FileNameIN+" > "+$FileNameIndexes);                                 
        }
    
    if ($Type == "voronoi")
        {
        // Voronoi requires a list of points and the indexing of those
        // points.  $Points will no longer be used
        //
        system("qvoronoi p < "+$FileNameIN+" > "+$FileNamePoints);                                  
        system("qvoronoi Fvoronoi <  "+$FileNameIN+" > "+$FileNameIndexes); 
        }
    if ($show == 1)
    {
        system("open "+ $FileNamePoints); 
        system("open "+ $FileNameIndexes); 
    }
    string $files[]={$FileNamePoints,$FileNameIndexes};
    return $files;
}

proc vector[]  processQPointFile(string $FileName)
{
    // This procedure will process points froma Qhull file
    // This is intended for the Qvoronoi setting
    // 
    vector $point;
    vector $points[];
    $fileId = `fopen $FileName "r"`;
    string $nextLine = `fgetline $fileId`;
    while ( size( $nextLine ) > 0 ) {
        if ( `size(strip($nextLine))` > 5 ){
            $point = `strip($nextLine)`; // Separate the digits into a list
            //$point = stringToStringArray(`strip($nextLine)`, " ");
            $points[size($points)] = $point;
            } // end if
        $nextLine = `fgetline $fileId`;
        } // end while
    fclose $fileId; 
return $points;    
}

proc string[]  processQIndexFile(string $FileName)
{
    // This procedure will process points froma Qhull file
    // This is intended for the Qvoronoi setting
    // 
    string $ind;
    string $index[];
    $fileId = `fopen $FileName "r"`;
    string $nextLine = `fgetline $fileId`;
    while ( size( $nextLine ) > 0 ) 
        {
        if ( `size(strip($nextLine))` > 5 )
            {
            $ind = `strip($nextLine)`; // Separate the digits into a list
            $index[size($index)] = $ind;
            } // end if
        $nextLine = `fgetline $fileId`;
        } // end while
    fclose $fileId;    
return $index;    
}


proc string[] makeFacets(string $Index[], string $Type, string $ResultType)/*, vector $points[]) // $Points are global*/
{   
    global vector $Points[];
    vector $tmpPoints1[] = $Points;
    vector $tmpPoints2[];
    string $index[];
    string $faces[];
    int $start=0;
    // Indexing is different for Delaunay and Voronoi
    if ($Type == "voronoi"){$start = 2;}// The first 2 numbers are not indices in voronoi output, so skip them
    
    vector $p;
    vector $prevPoint;
    int $ci;
    string $ps;
    
    string $collectCurves[];
    for ($ind in $Index)
    {
        $index = stringToStringArray($ind, " "); 
        
        
        //==========================================================================
        if ($ResultType == "nurbs")
        {
            $ci = abs(  (int)$index[$start]  );
            $prevPoint = $Points[$ci];
            for ($i=$start; $i<size($index);$i++) 
            {   
                $p = $prevPoint;
                $ps = "curve -d 1 -p (" +$p.x+ ") ("+$p.y+") ("+$p.z+")"; // init with first pnt
                $ci = abs(  (int)$index[$i]  );
                $p = $Points[$ci];
                $ps = $ps +"-p (" +$p.x+ ") ("+$p.y+") ("+$p.z+");"; 
                $tmpPoints1[$ci]=<<0,0,0>>;
                $prevPoint = $p;
                $collectCurves[size($collectCurves)] = eval ($ps); // make Curve
            }
            // Make closing curve
            $p = $prevPoint;
            $ps = "curve -d 1 -p (" +$p.x+ ") ("+$p.y+") ("+$p.z+")"; // init with first pnt
            $ci = abs(  (int)$index[$start]  );
            $prevPoint = $Points[$ci];
            $ps = $ps +"-p (" +$p.x+ ") ("+$p.y+") ("+$p.z+");"; 
    
            $collectCurves[size($collectCurves)] = eval ($ps); // make Curve
            $name = `boundary -ch 1 -or 0 -ep 0 -rn 0 -po 0 -ept 0.01 $collectCurves`;
            $faces[size($faces)]=$name[0];
        //==========================================================================
        }else if ($ResultType == "polygons"){
            string $ps = "polyCreateFacet ";
            for ($i=$start; $i<size($index);$i++) 
            {   
                int $ci = abs(  (int)$index[$i]  );
                vector $p = $Points[$ci];
                $ps = $ps +"-p (" +$p.x+ ") ("+$p.y+") ("+$p.z+")"; 
                $tmpPoints1[$ci]=<<0,0,0>>;
            }
            $ps = $ps+";"; // never forget your semicolon or there is HELL to pay!
            $name = eval ($ps); // this is how we launch the command            
            $faces[size($faces)] = $name[0];
            clear($index); // clear the list or it will build it ontop of the old data
        } else {
            catch (print ("must provide \"nurbs\" or \"polygons\" as the output type")) ;       
        }
        
        
        
    
        
        //refresh; // Uncomment this for cinematics ;-)
        clear($collectCurves);
        clear($index); // clear the list or it will build it ontop of the old data
    // break;
    } // end for
    
    for ($point in $tmpPoints1)
        {
            if ($point != <<0,0,0>>)
                $tmpPoints2[size($tmpPoints2)]=$point;
        }
    $Points = $tmpPoints2; // replace the global $Points with this set
return $faces;    
} // end proc

proc makeQPointsToLocators()
{
    global vector $Points[];
    for ($p in $Points)
    {
        $Vl = `spaceLocator -p ($p.x) ($p.y) ($p.z)`;
        setAttr ($Vl[0]+".overrideEnabled") 1;
        setAttr ($Vl[0]+".overrideColor") 7;
    }
}






//=======================================================
//=======================================================
//=======================================================
//           ____   ______          ___    __
//           |   \  |      |\  /|  /   \  /  \
//           |    | |__    | \/ | |     | \__
//           |    | |      |    | |     |    \
//           |___/  |_____ |    |  \___/  \__/  
//=======================================================
//=======================================================
//=======================================================

proc demoVoronoi(int $psmooth)
{
    // Here is the long anticipated Voronoi algo!  It's still a bit tricky
    // but it works to some degree.  The problem is to get an ordered list
    // return from Qhull in which to build the surfaces.  Once this has been
    // resolved, it will be as good as Rhino.
    //
    select -all; delete;
    global vector $Points[];
    string $Indexes[];
    string $Type = "delaunay"; // or "voronoi" 
    string $ResultType = "nurbs"; // or "polygons"  
    string $faces[];string $fileto; string $filefrom[];
    
    $Points = genPoints(10,-20,20); // num points, spatial range
    $fileto = PointsToFileForQhull($Points,0);
    $filefrom = runQhull($fileto, $Type,0);
    $Points = processQPointFile($filefrom[0]);
    $Indexes = processQIndexFile($filefrom[1]); 
    makeQPointsToLocators();   
    $faces = makeFacets($Indexes, $Type, $ResultType);//, $Points);
    print ("Faces created -> " + (size($faces))+"\n");
    print ("Num Unused Points -> " + (size($Points))+"\n\n");


    if ($psmooth == 1)
    {
        //pause -sec 30;
        print "Performing a polySmooth operation";
        undoInfo -st off;
        select -r $faces; 
        polySmooth  -mth 0 -dv 3 -c 1 -kb 0 -ksb 1 -khe 0 -kt 1 -kmb 2 -suv 1 -sl 1 -dpe 1 -ps 0.1 -ro 1 -ch 1;
        undoInfo -st on;
    }
    //system("rm "+$fileto+" "+$filefrom[0]+" "+$filefrom[1]); // Removes the temp files
}



proc makePntLocators(vector $Points[])
{
    for ($p in $Points)
    {
        spaceLocator -p ($p.x) ($p.y) ($p.z);
    }
}



//=======================================================
proc demoDelaunay1(int $psmooth)
{
    // This is the basic delaunay example.  It generates random points
    // and creates geometry from them.  The smooth is decorative.
    //
    select -all; delete;
    
    global vector $Points[];
    string $Indexes[];
    string $faces[];string $fileto; string $filefrom[];
    
    string $Type = "delaunay"; // or "voronoi" 
    string $ResultType = "nurbs"; // or "polygons"  
    $Points = genPoints(500,-100,100); // num points, spatial range
    print (`size($Points)`+" random points generated.\n");
    refresh();

    // WARNING: this while loop produces the 'Onion' effect.  It can take a really long
    // time if you have a large set of points.  You can aither use a large stopping point,
    // remove the loop, or use it.  Either way, it's up to you.    
    while (size($Points)>10)
    {
        print "Sending points to Qhull..\n";
        $fileto = PointsToFileForQhull($Points,0);
        print "Reading geometry instructions from Qhull..\n";
        $filefrom = runQhull($fileto, $Type,0);
        print "Assembling Qhull stuff into facets..\n";
        $Indexes = processQIndexFile($filefrom[1]);
        $faces = makeFacets($Indexes, $Type,$ResultType);//, $Points);
        refresh();
        print ("Faces created -> " + (size($faces))+"\n");
        print ("Num Unused Points -> " + (size($Points))+"\n\n");
    }
    if (($psmooth == 1)&&($ResultType == "polygons"))
        {
            undoInfo -st off;
            select -r $faces; polyUnite;
            polySmooth  -mth 0 -dv 3 -c 1 -kb 0 -ksb 1 -khe 0 -kt 1 -kmb 2 -suv 1 -sl 1 -dpe 1 -ps 0.1 -ro 1 -ch 1;
            undoInfo -st on;
        }
}

//=======================================================
proc demoDelaunay2(int $psmooth)
{
    // This example picks random locations on a set of nurbs surfaces
    // and then triangulates.
    //
    select -all; delete;
    
    $s1 = `sphere`; scale 5 5 5;
    $s2=`sphere`; scale 15 5 15;
    $s3=`sphere`; scale 5 15 5;
    $s4=`sphere`; 
    
    setAttr ($s1[0]+".overrideEnabled") 1;
    setAttr ($s1[0]+".overrideShading") 0;
    setAttr ($s1[0]+".primaryVisibility") 0;
    
    setAttr ($s2[0]+".overrideEnabled") 1;
    setAttr ($s2[0]+".overrideShading") 0;
    setAttr ($s2[0]+".primaryVisibility") 0;

    setAttr ($s3[0]+".overrideEnabled") 1;
    setAttr ($s3[0]+".overrideShading") 0;
    setAttr ($s3[0]+".primaryVisibility") 0;

    setAttr ($s4[0]+".overrideEnabled") 1;
    setAttr ($s4[0]+".overrideShading") 0;   
    setAttr ($s4[0]+".primaryVisibility") 0;
    
    select $s1;
    select -tgl $s2;
    select -tgl $s3;
    select -tgl $s4;
    
    global vector $Points[];
    string $Indexes[];
    string $faces[];string $fileto; string $filefrom[];
    
    string $Type = "delaunay"; // or "voronoi"    
    string $ResultType = "nurbs"; // or "polygons"  

    $Points = genPointsFromSurf(1000); // num points, spatial range

    print (`size($Points)`+" random points generated.\n");
    refresh(); 
 
     // WARNING: this while loop produces the 'Onion' effect.  It can take a really long
     // time if you have a large set of points.  You can aither use a large stopping point,
    // remove the loop, or use it.  Either way, it's up to you.
    while (size($Points)>10)
    {
        print "Sending points to Qhull..\n";
        $fileto = PointsToFileForQhull($Points,0);
        print "Reading geometry instructions from Qhull..\n";
        $filefrom = runQhull($fileto, $Type,0);
        print "Assembling Qhull stuff into facets..\n";
        $Indexes = processQIndexFile($filefrom[1]);
        $faces = makeFacets($Indexes, $Type,$ResultType);//, $Points);
        refresh();
        print ("Faces created -> " + (size($faces))+"\n");
        print ("Num Unused Points -> " + (size($Points))+"\n\n");

        if (($psmooth == 1)&&($ResultType == "polygons"))
        {
            undoInfo -st off;
            select -r $faces; polyUnite;
            polySmooth  -mth 0 -dv 3 -c 1 -kb 0 -ksb 1 -khe 0 -kt 1 -kmb 2 -suv 1 -sl 1 -dpe 1 -ps 0.1 -ro 1 -ch 1;
            undoInfo -st on;
        }
    }
}

//=======================================================
proc demoDelaunay3(int $psmooth)
{

    // This reads in a point cloud from a whitespace separated file and sends it
    // to the delaunay Qhull algorithm.  It is expected that your file is already 
    // in the Qhull input format.  Try making a sample file from Excel and then
    // place the system path in the $fileto string.  
    //
    // the Qhull format is:
    //
    // 3 (how many dimension is your vector... 2, 3, 4... typically 3)
    // 5 (how many points are you providing)
    // 1.3 2.3 5.5 (the first point.  space separated)
    // 4.3 2.4 9.0 (second point)
    // 3.0 6.0 5.5 (...)
    // 1.3 2.8 5.7
    // 2.3 3.4 2.9
    //
    select -all; delete;
    
    global vector $Points[];
    string $Indexes[];
    string $faces[];string $fileto; string $filefrom[];
    string $Type = "delaunay"; // or "voronoi" 
    string $ResultType = "nurbs"; // or "polygons"  
   
    $fileto = " <Enter the path to your input file> ";
    $Points = processQPointFile($fileto);
    vector $tmp[];
    for ($p in $Points)
    {
        $tmp[size($tmp)] = <<($p.x * 100),($p.y*100),($p.z*100)>>;
    }
    $Points = $tmp;
    makePntLocators($Points);
    refresh();
    
    // WARNING: this while loop produces the 'Onion' effect.  It can take a really long
    // time if you have a large set of points.  You can aither use a large stopping point,
    // remove the loop, or use it.  Either way, it's up to you.
    while (size($Points)>100)
    {
        print "Sending points to Qhull..\n";
        $fileto = PointsToFileForQhull($Points,0);
        print "Reading geometry instructions from Qhull..\n";
        $filefrom = runQhull($fileto, $Type, 0);
        print "Assembling Qhull stuff into facets..\n";
        $Indexes = processQIndexFile($filefrom[1]);
        $faces = makeFacets($Indexes, $Type,$ResultType);//, $Points);
        refresh();
        print ("Faces created -> " + (size($faces))+"\n");
        print ("Num Unused Points -> " + (size($Points))+"\n\n");
    }
    if (($psmooth == 1)&&($ResultType == "polygons"))
        {
            undoInfo -st off;
            select -r $faces; polyUnite;
            polySmooth  -mth 0 -dv 3 -c 1 -kb 0 -ksb 1 -khe 0 -kt 1 -kmb 2 -suv 1 -sl 1 -dpe 1 -ps 0.1 -ro 1 -ch 1;
            undoInfo -st on;
        }
}

//=======================================================
proc demoDelaunay4(int $psmooth)
{
    global vector $Points[];
    string $Indexes[];
    string $faces[];string $fileto; string $filefrom[];
    string $Type = "voronoi"; // or "delaunay"
    string $ResultType = "nurbs"; // or "polygons"  

    $items = `ls -sl`;
    for ($item in $items)
    {
        $Points[size($Points)]=`pointPosition $item`;
    }

    print "Sending points to Qhull..\n";
    $fileto = PointsToFileForQhull($Points,0);
    print "Reading geometry instructions from Qhull..\n";
    $filefrom = runQhull($fileto, $Type, 0);
    print "Assembling Qhull stuff into facets..\n";
    $Indexes = processQIndexFile($filefrom[1]);
    $faces = makeFacets($Indexes, $Type, $ResultType);
    refresh();
    print ("Faces created -> " + (size($faces))+"\n");
    print ("Num Unused Points -> " + (size($Points))+"\n\n");
    clear($Points);
    if (($psmooth == 1)&&($ResultType == "polygons"))
        {
            undoInfo -st off;
            select -r $faces; polyUnite;
            polySmooth  -mth 0 -dv 3 -c 1 -kb 0 -ksb 1 -khe 0 -kt 1 -kmb 2 -suv 1 -sl 1 -dpe 1 -ps 0.1 -ro 1 -ch 1;
            undoInfo -st on;
        }
}

//=======================================================
proc demoVoronoi2(int $psmooth)
{
    global vector $Points[];
    string $Indexes[];
    string $faces[];string $fileto; string $filefrom[];
    string $Type = "voronoi"; // or "delaunay"     
    string $ResultType = "nurbs"; // or "polygons"  

    $items = `ls -sl`;
    for ($item in $items)
    {
        $Points[size($Points)]=`pointPosition $item`;
    }
    $fileto = PointsToFileForQhull($Points,0);
    clear($Points);
    $filefrom = runQhull($fileto, $Type,0);
    $Points = processQPointFile($filefrom[0]);
    $Indexes = processQIndexFile($filefrom[1]); 
    makeQPointsToLocators();   
    $faces = makeFacets($Indexes, $Type, $ResultType);
    print ("Faces created -> " + (size($faces))+"\n");
    print ("Num Unused Points -> " + (size($Points))+"\n\n");
    clear($Points);
}


 
 
//  +-----------------Run Delaunay Demo---------------------+
//  |                                                       |
//  |                                                       |
/*  |            */demoDelaunay1(0);//  basic                |
/*  |            /demoDelaunay2(0);//  using surfaces       |
/*  |            /demoDelaunay3(0);//  for text files       |
/*  |            /demoDelaunay4(0);//  from selected points |
//  |                                                       |
//  +------------------Run Voronoi Demo---------------------+
//  |                                                       |
//  |                                                       |
/*  |                 /demoVoronoi(0);//                    |
/*  |                 /demoVoronoi2(0);//                    |
//  |                                                       |
//  |                                                       |
//  +-------------------------------------------------------+