Anim8or Community

Please login or register.

Login with username, password and session length
Advanced search  

News:

An update to Anim8or, v1.00b, is available with a few bug fixes. Get your copy HERE. See the "ReadMe" file for details.

Author Topic: Find Distance Between Two Points Script  (Read 9959 times)

CobraSpectre

  • Newbie
  • *
  • Posts: 39
    • View Profile
Find Distance Between Two Points Script
« on: February 14, 2008, 11:56:28 pm »

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.

Code: [Select]
#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
« Last Edit: February 15, 2008, 12:05:44 am by CobraSpectre »
Logged

vobla

  • Jr. Member
  • **
  • Posts: 68
    • View Profile
Re: Find Distance Between Two Points Script
« Reply #1 on: February 15, 2008, 01:56:27 am »

Hm.. a propper output (like msgBox) would be fabulous.. It might come with ASL update. If it's still not planed, Steve, please consider that ;)
Logged

Kubajzz

  • Flying Platypus
  • Global Moderator
  • Sr. Member
  • *****
  • Posts: 548
  • Little doggie ate my avatar...
    • View Profile
Re: Find Distance Between Two Points Script
« Reply #2 on: August 12, 2008, 11:00:36 am »

I apologize for reviving this very old topic... But there is a good reason :)

The original script by CobraSpectre finds the distance between two points and then new material is created - it's name contains the distance (there was no output support when CobraSpectre wrote that script...)

Anim8or version 0.97b supports output to console so I reworked the script - it now prints the output to console.

The script file is attached.
Logged

Tanzim

  • Guest
Re: Find Distance Between Two Points Script
« Reply #3 on: August 13, 2008, 10:52:18 am »

Nice one!
Logged

Steve

  • Administrator
  • Hero Member
  • *****
  • Posts: 1532
    • View Profile
Re: Find Distance Between Two Points Script
« Reply #4 on: August 16, 2008, 09:24:27 pm »

I don't think you need to do all that just to format numbers.  You can print the output with different floating point precision.  Here's an example:

/* console.txt */

file $console;

$console.open("$console", "w");

$console.print("The square root of 2 is %12.8f\n", sqrt(2.0));

...

The square root of 2 is   1.41421354

.....

You can also print directly to a string with PrintToString:

$str = PrintToString("this is a string %12.8f", sqrt(3.0));

and the value of $str will have:

"this is a string   1.73205078"

Logged

Kubajzz

  • Flying Platypus
  • Global Moderator
  • Sr. Member
  • *****
  • Posts: 548
  • Little doggie ate my avatar...
    • View Profile
Re: Find Distance Between Two Points Script
« Reply #5 on: August 16, 2008, 10:43:32 pm »

Yes, you are right... I was too lazy to read the whole code when I was editing this script so I only edited the last 15 rows or so... Instead of creating new material, console is opened, that's all I did...

I also didn't feel like doing some huge edits because I was editing the script without CobraSpectre's knowledge ::)

But the new ASL features are great! Console output makes debugging so easy... Thanks for that!
Logged

Steve

  • Administrator
  • Hero Member
  • *****
  • Posts: 1532
    • View Profile
Re: Find Distance Between Two Points Script
« Reply #6 on: August 19, 2008, 06:14:53 am »

Sorry if it seemed like I was critizing your changes.  I just thought it was a good place to point out the new functions :)
Logged