ENIGMA Forums

Contributing to ENIGMA => Function Peer Review => Topic started by: RetroX on December 20, 2010, 09:02:53 pm

Title: distance_to_object
Post by: RetroX on December 20, 2010, 09:02:53 pm
Code: [Select]
#include <limits>
double distance_to_object_point(int object)
{
  enigma::object_collisions* const inst1 = ((enigma::object_collisions*)enigma::instance_event_iterator->inst);
  double distance = std::numeric_limits<double>::infinity();
  double tempdist;
  for (enigma::inst_iter *it = enigma::fetch_inst_iter_by_int(object); it != NULL; it = it->next)
  {
    const enigma::object_collisions* inst2 = (enigma::object_collisions*)it->inst;
    if (inst1 == inst2) continue;
    tempdist = point_distance(inst1->x, inst1->y, inst2->x, inst2->y);
    if (tempdist < distance)
    {
      distance = tempdist;
    }
  }
  return (distance == std::numeric_limits<double>::infinity() ? 0 : distance);
}

inline double dist_ranges(double left1, double right1, double left2, double right2)
{
double right = min(right1, right2), left = max(left1, left2);
return (left > right ? left - right : 0);
}

double distance_to_object_bbox(int object)
{
  enigma::object_collisions* const inst1 = ((enigma::object_collisions*)enigma::instance_event_iterator->inst);
  const double left1  = inst1->x + inst1->bbox_left,  top1    = inst1->y + inst1->bbox_top,
               right1 = inst1->x + inst1->bbox_right, bottom1 = inst1->y + inst1->bbox_bottom;
  double distance = std::numeric_limits<double>::infinity();
  double tempdist;
  for (enigma::inst_iter *it = enigma::fetch_inst_iter_by_int(object); it != NULL; it = it->next)
  {
    const enigma::object_collisions* inst2 = (enigma::object_collisions*)it->inst;
    if (inst1 == inst2) continue;
const double left2  = inst2->x + inst1->bbox_left,  top2    = inst2->y + inst1->bbox_top,
right2 = inst2->x + inst1->bbox_right, bottom2 = inst2->y + inst1->bbox_bottom;
    tempdist = hypot(dist_ranges(left1, right1, left2, right2),
                     dist_ranges(top1, bottom1, top2, bottom2));
    if (tempdist < distance)
    {
      distance = tempdist;
    }
  }
  return (distance == std::numeric_limits<double>::infinity() ? 0 : distance);
}

Tested and both work.  I don't know which method that GM uses, but here's two different algorithms.
Title: Re: distance_to_object
Post by: Fede-lasse on December 22, 2010, 06:33:33 am
I also did distance_to_object_bbox and Josh didn't seem to notice.
Title: Re: distance_to_object
Post by: RetroX on December 23, 2010, 02:41:32 pm
Was it in C++ or GML?
Title: Re: distance_to_object
Post by: Josh @ Dreamland on December 23, 2010, 09:51:47 pm
Issue is, I don't know what GM does either. It does compensate for something like a bbox, but I'm not sure if it calculates the distance between the closest two points in the entirety of either mask, or if it calculates the distance between those along a straight line, or if it just defaults to bbox (which would be the only reasonable method), and if in that case it uses a rotated bbox or just a standard one... I'm in the dark on it. But I might accept Retro's bottom function. Provided, of course, that dist_ranges be made inline or into a macro.
Title: Re: distance_to_object
Post by: Fede-lasse on December 24, 2010, 01:41:27 pm
@retro: It was in GML, although I used int and other premature optimizations where I could like in e.g. C#. I guess you could say I did it in EDL. :P
Title: Re: distance_to_object
Post by: RetroX on December 25, 2010, 10:54:22 am
But I might accept Retro's bottom function. Provided, of course, that dist_ranges be made inline or into a macro.
I honestly don't know why I didn't make it inline.  I was probably rushing.  If you're going to use the bottom method, I'd still keep both labeled.
Code: [Select]
#define distance_to_object(x) distance_to_object_point(x)or
Code: [Select]
inline double distance_to_object(int object) { return distance_to_object_point(object); }
Title: Re: distance_to_object
Post by: IsmAvatar on December 26, 2010, 01:43:56 pm
I'm pretty sure with() just gets converted into the iterator, so there's no speed benefit one way or the other.
Title: Re: distance_to_object
Post by: polygone on December 26, 2010, 01:46:45 pm
Thought that was probably the case, was just wondering why Retro looped through instead of using the with statement. So thought it might be due to speed.
Title: Re: distance_to_object
Post by: Fede-lasse on December 26, 2010, 01:51:05 pm
sigh
Title: Re: distance_to_object
Post by: IsmAvatar on December 26, 2010, 01:56:36 pm
For low-level functions that intend to go into the back-end, it's not uncommon for people to use straight C++ rather than EDL.
Title: Re: distance_to_object
Post by: polygone on December 26, 2010, 02:00:05 pm
OK I'll keep that in mind.
Title: Re: distance_to_object
Post by: Josh @ Dreamland on December 26, 2010, 06:16:01 pm
Not to mention, enigma::fetch_inst_iter_by_int(object) is literally as efficient as can be. It is, in fact, the function that composes with(). It is set up such that there is no way to make it any faster; the iterator it returns accounts for all aspects of instance iteration, including ID, object index with heredity, and keywords such as all, other, or noone.
Title: Re: distance_to_object
Post by: RetroX on December 27, 2010, 06:06:53 pm
Updated code:

Code: [Select]
/* ********************* */
// Place this in some math header or something.
inline double range_difference(double left1, double right1, double left2, double right2)
{
double right = min(right1, right2), left = max(left1, left2);
return (left > right ? left - right : 0);
}
/* ********************* */


#include <limits>

double distance_to_object_point(int object)
{
  enigma::object_collisions* const inst1 = ((enigma::object_collisions*)enigma::instance_event_iterator->inst);
  double distance = std::numeric_limits<double>::infinity();
  double tempdist;
  for (enigma::inst_iter *it = enigma::fetch_inst_iter_by_int(object); it != NULL; it = it->next)
  {
    const enigma::object_collisions* inst2 = (enigma::object_collisions*)it->inst;
    if (inst1 == inst2) continue;
    tempdist = point_distance(inst1->x, inst1->y, inst2->x, inst2->y);
    if (tempdist < distance)
    {
      distance = tempdist;
    }
  }
  return (distance == std::numeric_limits<double>::infinity() ? 0 : distance);
}

double distance_to_object_bbox(int object)
{
  enigma::object_collisions* const inst1 = ((enigma::object_collisions*)enigma::instance_event_iterator->inst);
  const double left1  = inst1->x + inst1->bbox_left,  top1    = inst1->y + inst1->bbox_top,
               right1 = inst1->x + inst1->bbox_right, bottom1 = inst1->y + inst1->bbox_bottom;
  double distance = std::numeric_limits<double>::infinity();
  double tempdist;
  for (enigma::inst_iter *it = enigma::fetch_inst_iter_by_int(object); it != NULL; it = it->next)
  {
    const enigma::object_collisions* inst2 = (enigma::object_collisions*)it->inst;
    if (inst1 == inst2) continue;
const double left2  = inst2->x + inst1->bbox_left,  top2    = inst2->y + inst1->bbox_top,
right2 = inst2->x + inst1->bbox_right, bottom2 = inst2->y + inst1->bbox_bottom;
    tempdist = hypot(range_difference(left1, right1, left2, right2),
                     range_difference(top1, bottom1, top2, bottom2));
    if (tempdist < distance)
    {
      distance = tempdist;
    }
  }
  return (distance == std::numeric_limits<double>::infinity() ? 0 : distance);
}


inline double distance_to_point_point(double x, double y)
{
  enigma::object_collisions* const inst1 = ((enigma::object_collisions*)enigma::instance_event_iterator->inst);
  return point_distance(inst1->x, inst1->y, x, y);
}

inline double distance_to_point_bbox(double x, double y)
{
  enigma::object_collisions* const inst1 = ((enigma::object_collisions*)enigma::instance_event_iterator->inst);
  const double left1  = inst1->x + inst1->bbox_left,  top1    = inst1->y + inst1->bbox_top,
               right1 = inst1->x + inst1->bbox_right, bottom1 = inst1->y + inst1->bbox_bottom;
  return hypot(abs(min(left1 - x, right1 -x),
               min(top1 - x, bottom1 -x)));
}


// Possible option in configuration to choose which method is used?
inline double distance_to_object(int object) { return distance_to_object_bbox(object); }
inline double distance_to_point(double x, double y) { return distance_to_point_bbox(x, y); }

I'm almost certain that someone will modify this before it's put into ENIGMA, but this is what I have.
Title: Re: distance_to_object
Post by: IsmAvatar on December 27, 2010, 06:18:57 pm
If you make it complex enough and it works, nobody will bother touching it.
Title: Re: distance_to_object
Post by: polygone on December 27, 2010, 06:46:35 pm
I still prefer this:

Code: (EDL) [Select]
return (distance == std::numeric_limits<double>::infinity() ? -1 : distance);
Title: Re: distance_to_object
Post by: RetroX on December 27, 2010, 10:48:17 pm
But of course.