# 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.