Difference between revisions of "QHull to Maya Integration-ResearchNodes"
From scripting
(Created page with "http://researchnodes.org/doku.php?id=cellularaggregation:qmel.mel // ===================================================================== // Qhull - Maya interoperabilit...") |
(No difference)
|
Latest revision as of 19:46, 24 April 2017
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);// | // | | // | | // +-------------------------------------------------------+