## Sloppy pyramid worm

February 7th, 2009

A growing pyramid worm, with faces and corners aligned, mostly. It doesn’t line up exactly, and I’m not sure if that’s because of the shape of the pyramid or my dodgy code.

It’s easy to find out how far away something is, but how do you tell left from right? Things I thought I knew, until I tried to explain them. I may have to resort to particle physics.

MEL code follows…

```//---start---

//find the center of a face
proc vector centerOfFace(string \$face) {
// get locations of all vertices in an array
float \$pos[] = `xform -q -ws -t (\$face)`;

//get length of the array: # vertices * 3
int \$posSize = size(\$pos);

//put the average of all vectors into 1st vector
for (\$i = 0; \$i < 3; \$i++){
for (\$j = \$i + 3; \$j < \$posSize; \$j += 3){
\$pos[\$i] += \$pos[\$j];
}
\$pos[\$i] /= (\$posSize / 3);
}
vector \$averagePos = <<\$pos, \$pos, \$pos>>;
return \$averagePos;
}

//given three distances, get angle - law of cosines
proc float getAngle(float \$distance) {
//cos angle c = a^2+b^2-c^2/2ab
\$cSquared = `pow \$distance 2`;
//a and b in this case are both 1
\$cosAngleC = (2-\$cSquared)/2;
//fix more sloppiness
if (\$cosAngleC < -1) {\$cosAngleC = -1;}
//solve for angle with arccosine, in degrees
\$degrees = `acosd \$cosAngleC`;
//get angle to closest corner
\$deg2 = \$degrees % 120;
return \$deg2;
}

//get distance between two vertices
proc float getDistance(string \$vertA, string \$vertB) {
//get location of both vertices
\$aLoc = `xform -q -ws -t \$vertA`;
\$bLoc = `xform -q -ws -t \$vertB`;

//get distance with a temporary distanceDimension
\$distObj = `distanceDimension -sp \$aLoc \$aLoc \$aLoc
-ep \$bLoc \$bLoc \$bLoc`;
float \$dist = `getAttr \$distObj.distance`;
//cleanup
\$distObj = firstParentOf(\$distObj);
delete \$distObj;
delete "*cator*";
return \$dist;
}

proc doit() {

//make a 3-sided cone and select it
select `polyCone -r 1 -h 1.414214 -sx 3 -n "pCone1"`;
//move its pivot point to the bottom face
xform -rp 0 -0.707107 0;
//move to origin and freeze xforms
xform -t 0 0.707107 0;
makeIdentity -apply true -t 1;

//turn off constraint warnings
cycleCheck -e off;

for (\$i=0; \$i<500; ++\$i) {
//select cone
\$old = `ls -sl`;

//select a random face that isn't the base
int \$r = rand(3)+1;
\$selectedFace = ( \$old + ".f[" + \$r + "]" );
select \$selectedFace;

//instance cone and move to face
select `instance \$old`;
\$new = `ls -sl`;
vector \$fc = centerOfFace(\$selectedFace);
xform -a -t (\$fc.x) (\$fc.y) (\$fc.z) \$new;

//align instance to face with a temporary normal constraint
string \$tmpConst[] = `normalConstraint -aim 0 1 0 \$selectedFace \$new`;
delete \$tmpConst;

//pick a vertex on each cone
\$newVertex = \$new+".vtx"; // 0 is on the base
\$oldVertex = \$old+".vtx"; // 3 is the tip

//until i can tell left from right, repeat until it works
float \$angle = 60; // start with a non-zero number
while (\$angle > 1) {
// 1) get distance between two vertices
float \$dist = getDistance(\$newVertex, \$oldVertex);
// 2) get angle between two vertices
\$angle = getAngle(\$dist);
// 3) rotate the instance to align the corners
xform -r -os -ro 0 \$angle 0 \$new;
}

//animate visibility
setKeyframe -attribute "visibility" -v 0 -t 0 \$new;
setKeyframe -attribute "visibility" -v 1 -t (\$i+1) \$new;

select \$new;
}
cycleCheck -e on;
}
doit();

//---end---
```
« previously: Aligned faces pyramid worm | Home | next: Something I Learned Today »