One feature that I have wanted in Anim8or was the ability to measure the distance between points. I thought it would be easy, it was, getting that number out to the user isn't.
For starters, there isn't a debug number out. So while coding this I was creating parametric spheres to figure out what was going on with my code. The easy way to get a float out would be to use an export script or create a parametric object. I considered an export, except that it would be in the export menu and you have to find the file. I really didn't want a parametric object because it messes with your object and the undo.
I figured a material would be a good option. In the material toolbar, you can keep it there until you want to get rid of it. Compare several measures if necessary. Except you can only name a material with a string, not a float. Also there is no inbuilt function to convert from float to string.
I end up coding my own my own converter. It may not use the best method, but it works. However, it does have some problems with accuracy. Some numbers will evaluate out with trailing 0s or 9s and then pseudorandom 'noise' numbers. Others are just fine. During testing I found that in general only the first eight digits would be accurate, after that the float has noise. Also really big numbers tend to have problems.
Anim8or might be blame. For example, you can't input a floating point number that would have a problem into a location or length without it being rounded to five digit places or switching to Xe+Y format. I don't want to just say the problem is Anim8or, because I really can't tell what's going on.
The part which finds the selected points is based on the OBJ export script example by Steve. I could not figure out how to use shapes from just the ASL spec. I learned you can crash Anim8or during a compile test with a type mismatch in GetPointSelected.
The script works using a selection of two points. You can use points on the same mesh or different meshes. It works with meshes in groups. Subdivision and path points cannot be used. If more or less than 2 points are selected, it will result in an error output.
Try it out, give some feedback on usage. Tell me what you think of the script code.
#command("object");
/* Two_Point_Distance.a8s
* Version 1.0
* Released: 14-Feb-08
*/
/* This script finds the distance between two selected points.
* A new material is created to display the distance.
*
* To use, select two points of any mesh or meshes
* and run this script. The distance is output as
* the name of an object material. Distance is
* in Anim8or units.
*
* Points can be of the same mesh, unjoined meshes, or groups.
* Paths and subdivision objects cannot be used.
*
* Very large numbers may not evaluated properly,
* materials created that start with "ERR:" may not be accurate.
*
* If more or less than two points are selected, a material
* will be created with the name "Select 2 points".
*
* Portion of code based on export_obj_plugin.a8s,
* Copyright 2006 R. Steven Glanville.
*/
/* Declare working variables for output needed in distance */
float $numOut;
int $UserErrFlag;
/* Start - Find distance between two selected points */
shape $shape, $shapes[1], $childShapes[1];
meshdata $mdata;
int $numPoints;
int $k;
point3 $point;
float4x4 $transformMatrix;
point3 $p[0];
project.curObject.GetShapes($childShapes);
$shapes.size = 0;
while ($childShapes.size > 0)
$shapes.push($childShapes.pop());
while ($shapes.size > 0 && $p.size <= 2) {
$shape = $shapes.pop();
if ($shape.GetKind() == SHAPE_KIND_GROUP) {
$shape.GetShapes($childShapes);
while ($childShapes.size > 0) {
$shapes.push($childShapes.pop());
}
}
else if ($shape.GetKind() == SHAPE_KIND_SPHERE ||
$shape.GetKind() == SHAPE_KIND_RECT_SOLID ||
$shape.GetKind() == SHAPE_KIND_CYLINDER ||
$shape.GetKind() == SHAPE_KIND_PARAM_PLUGIN ||
$shape.GetKind() == SHAPE_KIND_PATH ||
$shape.GetKind() == SHAPE_KIND_SUBDIVISION ||
$shape.GetKind() == SHAPE_KIND_MODIFIER ||
$shape.GetKind() == SHAPE_KIND_TEXT)
{
/* Point data cannot be processed, must be excluded */
}
else {
$mdata = $shape.GetMeshData();
$transformMatrix = $shape.GetGlobalTransform();
$numPoints = $mdata.GetNumPoints();
for $k = 0 to $numPoints - 1 do {
$point = $mdata.GetPoint($k);
if ($shape.GetPointSelected($k) == true) {
$point = $transformMatrix.Project($point); /* Find global location */
$p.push($point);
}
}
}
}
if ($p.size == 2) {
/* Euclidean distance */
$numOut = sqrt(pow($p[0].x - $p[1].x, 2) + pow($p[0].y - $p[1].y, 2) + pow($p[0].z - $p[1].z, 2));
}
else
$UserErrFlag = true;
/* End - Find distance between two selected points */
/* Start - Float to material name */
float $numEval;
int $digitArray[0];
int $DotLoc; /* number of places to left of decimal */
string $textout;
string $message;
int $i;
int $j;
int $totalnum;
int $NegFlag;
int $ErrFlag;
string $ErrorText;
string $UserErrorText;
$textout = "";
$message = "Dist: "; /* output string leader */
/* Set $numOut here to force its value. Use to test float to string conversion. */
/* $numOut = 5; */
/* $UserErrFlag = false */
/* Handle negative numbers */
if ($numOut < 0) {
$NegFlag = true;
$numOut = abs($numOut);
}
/* Error setup */
$ErrorText = "ERR: ";
$UserErrorText = "Select 2 points";
if ($numOut > 10000000) /* very large numbers do not convert to string properly */
$ErrFlag = true;
if ($UserErrFlag == true)
$numOut = 0;
/* determine $DotLoc */
$numEval = $numOut;
while($numEval >= 1 && $numOut >= 1){
$numEval = $numEval / 10;
$DotLoc = $DotLoc + 1;
}
$totalnum = $DotLoc;
/* Handle 0 case */
if ($numOut == 0) {
$digitArray.push(0);
$totalnum = 1;
}
/* Add numbers to left of decimal to array */
$numEval = $numOut;
if ($DotLoc >= 1) {
$numEval = $numEval / pow(10, $DotLoc-1);
for $i = 0 to ($DotLoc-1) do {
$j = $numEval;
$digitArray.push($j);
$numEval = $numEval - $j;
$numEval = $numEval * 10;
}
}
/* Add numbers to right of decimal to array */
if ($numOut < 1)
$numEval = $numEval * 10;
while ($numEval != 0 && $totalnum <= 23) { /* prevent endless loop */
$j = $numEval;
$digitArray.push($j);
$numEval = $numEval - $j;
$numEval = $numEval * 10;
$totalnum = $totalnum + 1;
}
/* Create strings for building number output */
string $str0; $str0 = "0";
string $str1; $str1 = "1";
string $str2; $str2 = "2";
string $str3; $str3 = "3";
string $str4; $str4 = "4";
string $str5; $str5 = "5";
string $str6; $str6 = "6";
string $str7; $str7 = "7";
string $str8; $str8 = "8";
string $str9; $str9 = "9";
string $strDot; $strDot = ".";
string $strNeg; $strNeg = "-";
if ($NegFlag == true)
$textout = $textout + $strNeg;
/* Prevent excessive float output */
/* limit output to 8 digits or $DotLoc, whichever is greater */
if ($DotLoc > 8) /* eight appears to be max float accuracy */
$i = $DotLoc;
else
$i = 8; /* eight appears to be max float accuracy */
$totalnum = clamp($totalnum, 0, $i);
/* Truncate zeros */
if ($totalnum != $DotLoc && $digitArray[0] != 0) {
$i = $totalnum - 1;
$j = $digitArray[$i];
while ($j == 0 && $i >= $DotLoc) {
$i = $i - 1;
$j = $digitArray[$i];
}
$totalnum = $i + 1;
}
/* Build output */
for $i = 0 to $totalnum-1 do {
if ($i == $DotLoc && $numOut != 0)
$textout = $textout + $strDot;
$j = $digitArray[$i];
if ($j == 0)
$textout = $textout + $str0;
if ($j == 1)
$textout = $textout + $str1;
if ($j == 2)
$textout = $textout + $str2;
if ($j == 3)
$textout = $textout + $str3;
if ($j == 4)
$textout = $textout + $str4;
if ($j == 5)
$textout = $textout + $str5;
if ($j == 6)
$textout = $textout + $str6;
if ($j == 7)
$textout = $textout + $str7;
if ($j == 8)
$textout = $textout + $str8;
if ($j == 9)
$textout = $textout + $str9;
}
/* Create material */
material $material;
$material = project.curObject.NewMaterial("must be unused"); /* Seriously... */
$material.SetDiffuseColor((0, 1, 0)); /* Set normal color */
if ($ErrFlag == true) {
$textout = $ErrorText + $textout;
$material.SetDiffuseColor((1, 1, 0)); /* Set error output color */
}
else
$textout = $message + $textout;
if ($UserErrFlag == true) {
$textout = $UserErrorText;
$material.SetDiffuseColor((1, 0, 0)); /* Set user error output color */
}
$material.name = $textout;
/* End - Float to material name */
Crosspost to Anim8or.org