/* TOI Snap Tools */ // revision 1.0 2008; 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_snapTools_window` ) { deleteUI toi_snapTools_window; } global proc toi_snapTools ( ) { if ( !`window -exists toi_snapTools_window` ) { window -t "Snap Tools" -w 300 -h 400 -retain toi_snapTools_window; columnLayout; frameLayout -w 280 -l "Edge snap" -borderStyle "etchedOut" -visible 1 -collapsable 0 -mw 2 -mh 2; columnLayout -rs 2 toi_snapTools_MainCol; text -l "You need to use Curve snap for edge snapping"; checkBoxGrp -cw2 60 20 -l "enable" -onc "intSliderGrp -e -enable 1 toi_snapToolsNumMagnets; floatSliderGrp -e -enable 1 toi_snapToolsSensitivity; toi_updateEdgeSnap()" -ofc "intSliderGrp -e -enable 0 toi_snapToolsNumMagnets; floatSliderGrp -e -enable 0 toi_snapToolsSensitivity; toi_updateEdgeSnap()" toi_snapToolsEnabled; intSliderGrp -enable 0 -cw3 60 40 80 -v 1 -l "divisions" -field true -min 1 -max 10 -fmn 1 -fmx 100 -cc "toi_updateEdgeSnap()" toi_snapToolsNumMagnets; floatSliderGrp -enable 0 -cw3 60 40 80 -v 2 -l "sensitivity" -field true -min 1 -max 20 -fmn 0.1 -fmx 1000 -cc "toi_updateEdgeSnap()" toi_snapToolsSensitivity; setParent ..; setParent ..; frameLayout -w 280 -l "Vertex To Face" -borderStyle "etchedOut" -visible 1 -collapsable 0 -mw 2 -mh 2; columnLayout -rs 2 toi_vtfMainCol; textFieldGrp -l "face:" -enable 0 -text "" -cw2 60 100 toi_vtf_Face; rowLayout -nc 2 -cw2 60 200; text -l ""; button -label "Use selected face to snap to" -command "toi_vtf_setFace()"; setParent ..; text -label "Select axis or direction to constrain move:"; rowLayout -nc 3 -cw3 60 124 20; text -l ""; radioButtonGrp -label "" -numberOfRadioButtons 3 -l1 "X" -l2 "Y" -l3 "Z" -cw4 1 40 40 40 -changeCommand "toi_vtf_setVectorPreset" toi_vtf_VectorPreset; text -l "or"; setParent ..; rowLayout -nc 2 -cw2 60 180; text -l ""; button -label "Use selected edge" -command "toi_vtf_setEdge"; setParent ..; floatFieldGrp -nf 3 -label "X Y Z" -precision 8 -cw4 60 60 60 60 toi_vtf_constrainVector; button -c "toi_vtf_snapUI" -l "Snap selected vertices to face"; text -l "You can also select the vertices, edge and face together"; button -c "toi_vtf_snap_smart" -l "Smart Snap using active list"; } showWindow toi_snapTools_window; } global proc toi_updateEdgeSnap () { if ( `checkBoxGrp -q -v1 toi_snapToolsEnabled` ) { int $num = `intSliderGrp -q -v toi_snapToolsNumMagnets`; if ( $num > 0 ) { float $sens = `floatSliderGrp -q -v toi_snapToolsSensitivity`; snapMode -edgeMagnet $num -edgeMagnetTolerance $sens; } } else { snapMode -edgeMagnet 0; } } //snapMode -edgeMagnet 2; /* Sets the X Y Z for the selected vector oreset */ global proc toi_vtf_setVectorPreset() { int $sel = `radioButtonGrp -q -select toi_vtf_VectorPreset`; vector $v = <<0,0,0>>; switch ( $sel ) { case 1: $v = <<1,0,0>>; break; case 2: $v = <<0,1,0>>; break; case 3: $v = <<0,0,1>>; break; } floatFieldGrp -e -v1 ($v.x) -v2 ($v.y) -v3 ($v.z) toi_vtf_constrainVector; } /* Stores the selected face in the interface */ global proc toi_vtf_setFace() { string $sl[] = `ls -sl -flatten`; string $face = $sl[0]; if ( ! size(`match "\.f\[[0-9]+\]$" $face`) > 0) { error("No face selected"); } textFieldGrp -e -text $face toi_vtf_Face; } /* stores X Y Z for the selected edge to use as constraint vector*/ global proc toi_vtf_setEdge () { string $sl[] = `ls -sl -flatten`; string $e = $sl[0]; if ( size(`match "\.e\[[0-9]+\]$" $e`) > 0) { vector $v = toi_vtf_getEdgeVector($e); floatFieldGrp -e -v1 ($v.x) -v2 ($v.y) -v3 ($v.z) toi_vtf_constrainVector; } } global proc vector toi_vtf_getEdgeVector ( string $e ) { string $vertices[] = lv_getEdgeVertices($e); float $vtx1[] = `pointPosition -w $vertices[0]`; float $vtx2[] = `pointPosition -w $vertices[1]`; vector $v = <<$vtx2[0],$vtx2[1],$vtx2[2]>> - <<$vtx1[0],$vtx1[1],$vtx1[2]>>; normalize($v); return $v; } global proc toi_vtf_snap_smart () { string $face; vector $v; string $vertices[] = toi_vtf_getSelectedVertices ( ); if ( size($vertices) == 0 ) { error("No vertices selected"); } string $edges[] = toi_vtf_getSelectedEdges ( ); if ( size($edges) == 0 ) { // no faces selected - try to use the Fields float $ux = `floatFieldGrp -q -v1 toi_vtf_constrainVector`; float $uy = `floatFieldGrp -q -v2 toi_vtf_constrainVector`; float $uz = `floatFieldGrp -q -v3 toi_vtf_constrainVector`; $v = <<$ux,$uy,$uz>>; } else { $v = toi_vtf_getEdgeVector ( $edges[0] ); } string $faces[] = toi_vtf_getSelectedFaces ( ); if ( size($faces) == 0 ) { // no faces selected - try to use the textField $face = `textFieldGrp -q -text toi_vtf_Face`; } else { $face = $faces[0]; } for ( $vtx in $vertices ) { toi_vtf_snapVtx($vtx,$v,$face); } } global proc toi_vtf_snapUI () { string $face = `textFieldGrp -q -text toi_vtf_Face`; float $ux = `floatFieldGrp -q -v1 toi_vtf_constrainVector`; float $uy = `floatFieldGrp -q -v2 toi_vtf_constrainVector`; float $uz = `floatFieldGrp -q -v3 toi_vtf_constrainVector`; vector $u = <<$ux,$uy,$uz>>; //vector of the direction to constrain move to string $vertices[] = toi_vtf_getSelectedVertices ( ); if ( size($vertices) == 0 ) { error("No vertices selected"); } for ( $vtx in $vertices ) { toi_vtf_snapVtx($vtx,$u,$face); } } global proc string[] toi_vtf_getSelectedVertices ( ) { string $sl[] = `ls -sl -flatten`; string $vertices[]; for ( $vtx in $sl ) { if ( size(`match "\.vtx\[[0-9]+\]$" $vtx`) > 0) { $vertices = stringArrayCatenate($vertices,{$vtx}); } } return $vertices; } global proc string[] toi_vtf_getSelectedEdges ( ) { string $sl[] = `ls -sl -flatten`; string $edges[],$edge; for ( $edge in $sl ) { if ( size(`match "\.e\[[0-9]+\]$" $edge`) > 0) { $edges = stringArrayCatenate($edges,{$edge}); } } return $edges; } global proc string[] toi_vtf_getSelectedFaces ( ) { string $sl[] = `ls -sl -flatten`; string $faces[],$face; for ( $face in $sl ) { if ( size(`match "\.f\[[0-9]+\]$" $face`) > 0) { $faces = stringArrayCatenate($faces,{$face}); } } return $faces; } /* Helper function to move a single vertex to the intersectionpoint with a face */ global proc toi_vtf_snapVtx ( string $vtx, vector $u, string $face ) { float $vtxpos[] = `pointPosition -w $vtx`; // world position of selected vertex if ( size($face) == 0 ) { error("No face set to snap to"); } string $face_vertices[] = lv_getFaceVertices($face); float $fv1[] = `pointPosition -w $face_vertices[0]`; float $fv2[] = `pointPosition -w $face_vertices[1]`; float $fv3[] = `pointPosition -w $face_vertices[2]`; vector $n = lv_getNormal($fv1,$fv2,$fv3); // calulate the face normal, using three vertices of that face // the vectors vector $w = <<$fv1[0],$fv1[1],$fv1[2]>> - <<$vtxpos[0],$vtxpos[1],$vtxpos[2]>>; // vector of the selected vertex to a point on the face. if ( mag($u) < 0.000001 ) { error("No (valid) direction set to constrain movement to"); } float $len = dot($n,$w) / dot($n,$u); // calculate the length of the vector with direction $u between the vertex and the intersection with the surface vector $is = <<$vtxpos[0],$vtxpos[1],$vtxpos[2]>> + $len * $u; move -a ($is.x) ($is.y) ($is.z) $vtx; } /* calculate the normal of a face, given three points on that face */ global proc vector lv_getNormal ( float $p1[], float $p2[], float $p3[] ) { return cross( (<<$p2[0],$p2[1],$p2[2]>>-<<$p1[0],$p1[1],$p1[2]>>) , (<<$p3[0],$p3[1],$p3[2]>>-<<$p1[0],$p1[1],$p1[2]>>) ); } /* get vertices of a face */ global proc string[] lv_getFaceVertices ( string $f ) { string $objName = `substitute "\.f\[[0-9]+\]$" $f ""`; string $verts[]; string $buffer[] = `polyInfo -faceToVertex $f`; string $buf[] = stringToStringArray($buffer[0], " "); for ( $i=2; $i < size($buf)-1; $i++ ) { $verts = stringArrayCatenate( $verts, {($objName+".vtx["+$buf[$i]+"]")} ); // add to result array } return $verts; } /* get vertices of an edge */ 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]+"]")}; }