/* TOI Bookshelf Generator */ // revision 1.1 2014; TOI, T. Welman TU Delft // make sure the windows are reset at load, so the UI is always up-to-date if ( `window -exists toi_bookshelfgen_window` ) deleteUI toi_bookshelfgen_window; global proc toi_bookshelfGenerator () { if ( !`window -exists toi_bookshelfgen_window` ) { int $toi_bookgen_rs = 4; window -t "TOI Bookshelf Generator" -w 304 -h 180 -retain toi_bookshelfgen_window; columnLayout -rs $toi_bookgen_rs toi_bookgen_mainCol; checkBoxGrp -ncb 1 -v1 1 -l "Mode" -l1 "Use relative dimensions" -cc "toi_bookgenUI_changeMode(#1)" toi_bookgen_mode; text -l "" toi_bookgen_modeExplain; text -l "Height of the books"; floatSliderGrp -l "minimum" -f 1 -pre 1 -v 20 toi_bookgen_minHeight; floatSliderGrp -l "maximum" -f 1 -pre 1 -v 99 toi_bookgen_maxHeight; separator -style "none"; text -l "Width of the books"; floatSliderGrp -l "minimum" -f 1 -pre 1 -v 2 toi_bookgen_minWidth; floatSliderGrp -l "maximum" -f 1 -pre 1 -v 20 toi_bookgen_maxWidth; separator -style "none"; text -l "Depth of the books"; floatSliderGrp -l "maximum" -f 1 -pre 1 -v 25 toi_bookgen_minDepth; floatSliderGrp -l "maximum" -f 1 -pre 1 -v 80 toi_bookgen_maxDepth; separator -style "none"; text -l "Distance that books are 'pushed' inward:"; floatSliderGrp -l "minimum" -f 1 -pre 1 -v 25 toi_bookgen_minOffset; floatSliderGrp -l "maximum" -f 1 -pre 1 -v 80 toi_bookgen_maxOffset; separator -style "none"; text -l "Gaps:"; floatSliderGrp -l "minimum" -f 1 -pre 1 -v 25 toi_bookgen_minGap; floatSliderGrp -l "maximum" -f 1 -pre 1 -v 200 toi_bookgen_maxGap; floatSliderGrp -l "chance (1 in n)" -f 1 -pre 1 -v 10 -min 1 -max 1000 toi_bookgen_chanceGap; separator -style "none"; text -l "" toi_bookgen_selectExplain; checkBoxGrp -l "" -l1 "Flip direction" -ncb 1 -v1 0 toi_bookgen_flip; button -l "Generate books" -c "toi_createBooksUI()"; } toi_bookgenUI_changeMode(1); //set defaults selectPref -trackSelectionOrder 1; //make sure selection order tracking is enabled showWindow toi_bookshelfgen_window; } global proc toi_bookgenUI_changeMode ( int $mode ) { checkBoxGrp -e -v1 $mode toi_bookgen_mode; if ( $mode == 0 ) { //absolute mode text -e -l "Minimum and maximum are absolute (in scene units)" toi_bookgen_modeExplain; text -e -l "Select edges that indicate the edge of the shelf" toi_bookgen_selectExplain; floatSliderGrp -e -min 0.01 -max 100 -pre 3 -v .18 toi_bookgen_minHeight; floatSliderGrp -e -min 0.01 -max 100 -pre 3 -v .50 toi_bookgen_maxHeight; floatSliderGrp -e -min 0.01 -max 100 -pre 3 -v .01 toi_bookgen_minWidth; floatSliderGrp -e -min 0.01 -max 100 -pre 3 -v .12 toi_bookgen_maxWidth; floatSliderGrp -e -min 0.01 -max 100 -pre 3 -v .15 toi_bookgen_minDepth; floatSliderGrp -e -min 0.01 -max 100 -pre 3 -v .45 toi_bookgen_maxDepth; floatSliderGrp -e -min 0.01 -max 100 -pre 3 -v .01 toi_bookgen_minOffset; floatSliderGrp -e -min 0.01 -max 100 -pre 3 -v .05 toi_bookgen_maxOffset; floatSliderGrp -e -min 0.01 -max 200 -pre 3 -v .02 toi_bookgen_minGap; floatSliderGrp -e -min 0.01 -max 200 -pre 3 -v .60 toi_bookgen_maxGap; } else { //relative mode text -e -l "Minimum and maximum are a percentage of the vertical distance between selected edges" toi_bookgen_modeExplain; text -e -l "Select pair(s) of edges that indicate the edge of the shelf and the edge of the shelf above" toi_bookgen_selectExplain; floatSliderGrp -e -min 1 -max 100 -pre 1 -v 55 toi_bookgen_minHeight; floatSliderGrp -e -min 2 -max 100 -pre 1 -v 99 toi_bookgen_maxHeight; floatSliderGrp -e -min 0.1 -max 50 -pre 1 -v 2 toi_bookgen_minWidth; floatSliderGrp -e -min 0.2 -max 50 -pre 1 -v 20 toi_bookgen_maxWidth; floatSliderGrp -e -min 1 -max 100 -pre 1 -v 35 toi_bookgen_minDepth; floatSliderGrp -e -min 2 -max 200 -pre 1 -v 75 toi_bookgen_maxDepth; floatSliderGrp -e -min 0 -max 100 -pre 3 -v 0 toi_bookgen_minOffset; floatSliderGrp -e -min 0 -max 100 -pre 3 -v 5 toi_bookgen_maxOffset; floatSliderGrp -e -min 0 -max 500 -pre 1 -v 2 toi_bookgen_minGap; floatSliderGrp -e -min 0 -max 500 -pre 1 -v 200 toi_bookgen_maxGap; } } global proc toi_createBooksUI () { int $mode = `checkBoxGrp -q -v1 toi_bookgen_mode`; int $flip = `checkBoxGrp -q -v1 toi_bookgen_flip`; float $factor = 1; if ( $mode == 1 ) { //relative: make percentages $factor = 100; } float $minHeight = `floatSliderGrp -q -v toi_bookgen_minHeight` / $factor; float $maxHeight = `floatSliderGrp -q -v toi_bookgen_maxHeight` / $factor; float $minWidth = `floatSliderGrp -q -v toi_bookgen_minWidth` / $factor; float $maxWidth = `floatSliderGrp -q -v toi_bookgen_maxWidth` / $factor; float $minDepth = `floatSliderGrp -q -v toi_bookgen_minDepth` / $factor; float $maxDepth = `floatSliderGrp -q -v toi_bookgen_maxDepth` / $factor; float $minOffset = `floatSliderGrp -q -v toi_bookgen_minOffset` / $factor; float $maxOffset = `floatSliderGrp -q -v toi_bookgen_maxOffset` / $factor; float $minGap = `floatSliderGrp -q -v toi_bookgen_minOffset` / $factor; float $maxGap = `floatSliderGrp -q -v toi_bookgen_maxOffset` / $factor; float $gapChance = 1.0 / `floatSliderGrp -q -v toi_bookgen_chanceGap`; toi_createBooks( $mode, $flip, $minHeight, $maxHeight, $minWidth, $maxWidth, $minDepth, $maxDepth, $minOffset, $maxOffset, $gapChance, $minGap, $maxGap); } global proc toi_createBooks( int $mode, int $flip, float $minHeight, float $maxHeight, float $minWidth, float $maxWidth, float $minDepth, float $maxDepth, float $minOffset, float $maxOffset, float $gapChance, float $minGap, float $maxGap) { string $sel[] = `ls -long -orderedSelection -flatten`; string $n; string $edges[]; int $c, $b; for ( $n in $sel ) { if ( size(`match "\.e\[[0-9]+\]$" $n`) > 0 ) { //no edge $edges[$c++] = $n; } } int $increase; if ( $mode == 0 ) { //absolute mode $increase = 1; } else { //relative mode $increase = 2; //(works on pairs) } if ( size($edges) < $increase ) { error("Please select at least "+$increase+" edge(s)"); } string $edge1, $edge2, $edgeSet[]; float $height, $width, $depth, $offset; float $vertical, $edgeLen, $posOnEdge; string $books[], $booksGroup; for ( $c = 0; $c < size($edges); $c = $c + $increase ) { if ( $mode == 0 ) { //absolute mode $edge1 = $edges[$c]; } else { if ( size($edges) < $c+2 ) { break; //odd number of edges, break now } $edgeSet = toi_sortEdgesVertical ( $edges[$c], $edges[$c+1] ); $edge1 = $edgeSet[0]; //lower $edge2 = $edgeSet[1]; //upper $vertical = toi_getEdgesVerticalDistance($edge1, $edge2); } $edgeLen = toi_getEdgeLength($edge1); if ( $vertical < 0.01 || $edgeLen < 0.01 ) continue; clear($books); $booksGroup = `group -empty -name "generatedBooks"`; $b = 0; for ( $posOnEdge = 0; $posOnEdge < $edgeLen; $posOnEdge += $width ) { if ( rand( 0, 1) <= $gapChance ) { //create a gap $posOnEdge += rand( $minGap, $maxGap); } if ( $mode == 0 ) { //absolute $height = rand( $minHeight, $maxHeight ); $width = rand( $minWidth, $maxWidth ); $depth = rand( $minDepth, $maxDepth ); $offset = rand( $minOffset, $maxOffset); } else { $height = rand( ($minHeight * $vertical), ($maxHeight * $vertical) ); $width = rand( ($minWidth * $vertical), ($maxWidth * $vertical) ); $depth = rand( ($minDepth * $vertical), ($maxDepth * $vertical) ); $offset = rand( ($minOffset * $vertical), ($maxOffset * $vertical)); } if ( $width + $posOnEdge > $edgeLen ) { $width = $edgeLen - $posOnEdge; } $books[$b++] = toi_createBook( $edge1, $flip, $width, $height, $depth, $offset, $posOnEdge); } parent $books $booksGroup; } } global proc string toi_createBook( string $edge, int $flip, float $width, float $height, float $depth, float $offset, float $posOnEdge) { float $perpendic_angle = 90; float $extrude_factor = 1; if ( $flip ) { $extrude_factor = -1; $perpendic_angle *= -1; } float $vect[] = toi_getEdgeVector($edge); normalize($vect); float $normal[] = lv_floatVectorRotate($vect, {0.0,1.0,0.0}, $perpendic_angle); float $pos1[] = toi_getEdgePoint($edge, 0); float $pos[] = lv_floatVectorAdd( $pos1, lv_floatVectorMult($vect, $posOnEdge)); float $rotate = rad_to_deg(angle( <<1,0,0>>, <<$vect[0], $vect[1], $vect[2]>> )); //string $book[] = `polyCube -w $width -h $height -d $depth`; //move ($width / 2.0) ($height / -2.0) (($depth / -2.0) - $offset )($cube[0]+".rotatePivot") ($cube[0]+".scalePivot"); //makeIdentity -apply true -t 1 -r 1 -s 1 -n 0 $cube[0]; //float $rotate = rad_to_deg(angle( <<1,0,0>>, <<$vect[0], $vect[1], $vect[2]>> )); // move -rpr $pos[0] $pos[1] $pos[2] $cube[0]; //rotate -a 0 (-1* $rotate) 0 $cube[0]; float $pivot[] = $pos; $pos[0] += $normal[0] * $offset; $pos[1] += $normal[1] * $offset; $pos[2] += $normal[2] * $offset; string $book[] = `polyCreateFacet -name "bookOnShelf" -ch off -tx 1 -p $pos[0] $pos[1] $pos[2] -p ($pos[0] + $vect[0] * $width) ($pos[1] + $vect[1] * $width) ($pos[2] + $vect[2] * $width) -p (($pos[0] + $vect[0] * $width) + $normal[0] * $depth) (($pos[1] + $vect[1] * $width) + $normal[1] * $depth) (($pos[2] + $vect[2] * $width) + $normal[2] * $depth) -p ($pos[0] + $normal[0] * $depth) ($pos[1] + $normal[1] * $depth) ($pos[2] + $normal[2] * $depth)`; polyExtrudeFacet -ch off -keepFacesTogether 1 -lt 0 0 ($extrude_factor * $height) ($book[0]+".f[0]"); polyAutoProjection -ch off -rotate 0 $rotate 0 -lm 0 -pb 0 -ibd 1 -cm 0 -l 2 -sc 1 -o 1 -ps 0 -ws 0 $book[0]; move $pivot[0] $pivot[1] $pivot[2] ($book[0]+".scalePivot") ($book[0]+".rotatePivot"); return $book[0]; } global proc string[] toi_sortEdgesVertical ( string $edge1, string $edge2 ) { float $pos1[] = toi_getEdgePoint( $edge1, 0); float $pos2[] = toi_getEdgePoint( $edge2, 0); if ( $pos1[1] > $pos2[1] ) { return { $edge2, $edge1 }; } return { $edge1, $edge2 }; } global proc float toi_getEdgesVerticalDistance ( string $edge1, string $edge2 ) { float $pos1[] = toi_getEdgePoint( $edge1, 0); float $pos2[] = toi_getEdgePoint( $edge2, 0); return abs($pos2[1] - $pos1[1]); } global proc float[] toi_getEdgePoint ( string $edge, float $param ) { float $pos[], $pos1[], $pos2[], $vect[]; string $vtx[] = lv_getEdgeVertices($edge); $pos1 = `pointPosition -w $vtx[0]`; $pos2 = `pointPosition -w $vtx[1]`; $vect = lv_floatVectorSub($pos2, $pos1); $pos = { ($pos1[0] + ($param * $vect[0])), ($pos1[1] + ($param * $vect[1])), ($pos1[2] + ($param * $vect[2])) }; return $pos; } global proc float[] toi_getEdgeVector ( string $edge ) { float $pos1[], $pos2[]; string $vtx[] = lv_getEdgeVertices($edge); $pos1 = `pointPosition -w $vtx[0]`; $pos2 = `pointPosition -w $vtx[1]`; return lv_floatVectorSub($pos2, $pos1); } global proc float toi_getEdgeLength ( string $edge ) { float $vect[] = toi_getEdgeVector($edge); float $dist = mag( <<$vect[0], $vect[1], $vect[2] >> ); return $dist; } global proc string[] lv_getEdgeVertices ( string $e ) { string $objName = `substitute "\.e\[[0-9]+\]$" $e ""`; string $buffer[] = `polyInfo -edgeToVertex $e`; string $buf[] = stringToStringArray($buffer[0], " "); return {($objName+".vtx["+$buf[2]+"]"),($objName+".vtx["+$buf[3]+"]")}; } global proc float[] lv_floatVectorRotate ( float $a[], float $b[], float $angle ) { vector $v = rot( <<$a[0], $a[1], $a[2] >>, <<$b[0], $b[1], $b[2] >>, deg_to_rad($angle) ); return { ($v.x), ($v.y), ($v.z) }; } global proc float[] lv_floatVectorAdd ( float $a[], float $b[] ) { return { ($a[0] + $b[0]), ($a[1] + $b[1]), ($a[2] + $b[2]) }; } global proc float[] lv_floatVectorSub ( float $a[], float $b[] ) { return { ($a[0] - $b[0]), ($a[1] - $b[1]), ($a[2] - $b[2]) }; } global proc float[] lv_floatVectorMult ( float $a[], float $b ) { return { ($a[0] * $b), ($a[1] * $b), ($a[2] * $b) }; }