Sign in to follow this  
P0jahn

Get a points coordinate

Recommended Posts

Look at these three pictures:

[attachment=12966:example1.png]

[attachment=12967:example2.png]

[attachment=12968:example3.png]

 

So the red object is some sort of watcher. It watches the green object. However, I do not want the coordinates of the green object, but the black circle. Is there any way to calculate this? 

 

Some more info about my game, the top left corner is point 0,0, x increases while moving to the right and y is increasing when moving down, just like any other java coordinate system. The black circle is always going to be at the edge of the map.

Share this post


Link to post
Share on other sites

So you want the direction to the green object from the red object?

 

direction = normalize(greenPos - redPos)

 

Then you can multiply the direction by the distance from the red object to the black circle. So if you wanted the black circle to appear 10 units away from the red object you would write:


blackCirclePos = direction * 10

 

 

 

Does that answer your question or have I misunderstood?

Share this post


Link to post
Share on other sites

Well, I am afraid he doesn't know the distance to the black circle a priori. The black circle is wherever the ray intersects the edge of the map.

 

Consider a structure called a "ray" that contains the position of the red dot (the ray's "origin") and the direction (as defined in Nyssa's post). You can find a point along the ray as ray.origin + t*ray.direction. I would write a function that finds the intersection of a ray with a line, and returns the value of the parameter t where the intersection happens (use the dot product for this). Then call it four times for the edges of the map and pick the lowest non-negative value of the parameter. That should give you the position of the black dot.

 

I may post some easy-to-read C++ code to solve this later.

Edited by Álvaro

Share this post


Link to post
Share on other sites
Here's some C++ code to solve the problem. I tried to not use references or static variables, to not confuse matters. But I couldn't get myself to not overload a few operators... Let me know if you have a hard time understanding what it's doing. But the function find_black_dot() is the key to it all, and it should be fairly easy to follow.
 
#include <iostream>
#include <cmath>
struct Vector {
  float x, y;
 
  Vector(float x, float y) : x(x), y(y) {
  }
};

Vector operator*(Vector v, float s) {
  return Vector(v.x*s, v.y*s);
}

float dot_product(Vector v, Vector w) {
  return v.x*w.x + v.y*w.y;
}

Vector normalize(Vector v) {
  return v * (1.0 / std::sqrt(dot_product(v, v)));
}

struct Point {
  float x, y;
 
  Point(float x, float y) : x(x), y(y) {
  }
};

std::ostream &operator<<(std::ostream &os, Point p) {
  return os << '(' << p.x << ',' << p.y << ')';
}

Vector operator-(Point p, Point q) {
  return Vector(p.x-q.x, p.y-q.y);
}

Point operator+(Point p, Vector v) {
  return Point(p.x+v.x, p.y+v.y);
}

struct Ray {
  Point origin;
  Vector direction;
 
  Ray(Point origin, Vector direction) : origin(origin), direction(direction) {
  }
};

// If dot_product(p-origin,normal)==constant, p is in the line
struct Line {
  Vector normal;
  float constant;
  
  Line(Vector normal, float constant) : normal(normal), constant(constant) {
  }
};

float find_intersection_parameter(Ray ray, Line line) {
  return (line.constant - dot_product(ray.origin-Point(0.0f,0.0f), line.normal))
    / dot_product(ray.direction, line.normal);
}

Point find_black_dot(Point red_point, Point green_point) {
  Line lines[4] = {
    Line(Vector(1.0f,0.0f), 0.0f),
    Line(Vector(1.0f,0.0f), 30.0f),
    Line(Vector(0.0f,1.0f), 0.0f),
    Line(Vector(0.0f,1.0f), 20.0f)
  };
 
  Ray ray(red_point, normalize(green_point-red_point));
  double min_non_negative_intersection_parameter = 1.0e20f;
  for (int i=0; i<4; ++i) {
    float intersection_parameter = find_intersection_parameter(ray, lines[i]);
    if (intersection_parameter >= 0.0f
        && intersection_parameter < min_non_negative_intersection_parameter)
      min_non_negative_intersection_parameter = intersection_parameter;
  }
 
  return ray.origin + ray.direction * min_non_negative_intersection_parameter;
}

int main() {
  Point red(16.5,10.5);
  Point green(11.5,15.5);
 
  std::cout << find_black_dot(red, green) << '\n';
}
Edited by Álvaro

Share this post


Link to post
Share on other sites
You don't really need the Pythagorean theorem for this, and the method I proposed is also kind of overkill.

This is much simpler code that does the same thing. I should probably posted this solution before:
#include <iostream>

struct Point {
  float x, y;

  Point(float x, float y) : x(x), y(y) {
  }
};

Point find_black_dot(Point red_point, Point green_point) {
  float vertical_intersection_time = 1.0e20f;
  if (green_point.x > red_point.x)
    vertical_intersection_time = (30.0f-red_point.x)/(green_point.x-red_point.x);
  else if (green_point.x < red_point.x)
    vertical_intersection_time = (0.0f-red_point.x)/(green_point.x-red_point.x);

  float horizontal_intersection_time = 1.0e20f;
  if (green_point.y > red_point.y)
    horizontal_intersection_time = (20.0f-red_point.y)/(green_point.y-red_point.y);
  else if (green_point.y < red_point.y)
    horizontal_intersection_time = (0.0f-red_point.y)/(green_point.y-red_point.y);

  float time = std::min(horizontal_intersection_time,vertical_intersection_time);
  return Point(red_point.x + time * (green_point.x-red_point.x), red_point.y + time * (green_point.y-red_point.y));
}

int main() {
  Point red(16.5,10.5);
  Point green(11.5,15.5);

  Point black = find_black_dot(red, green);
  std::cout << '(' << black.x << ',' << black.y << ")\n";
}

Share this post


Link to post
Share on other sites
Thanks Alvaro. May I ask what type of data the returned point actually contains? If it is the black circle as you described, how can it find it without knowing the dimension of the map?
Also, can you suggest some sort of professional name for this method? :) Edited by P0jahn

Share this post


Link to post
Share on other sites

I didn't understand what you did the second time there (I need to copy it into SciTE and look at it more closely), but this is what I came up with (just because I like messing with this kind of problem).

 

struct Vector2 {
  int x;
  int y;
};

Vector2 findTargetAlignedBoundaryIntersection(Vector2 obsever, Vector2 target) {
  Vector2 targetDelta = { //vector to the target from the obserer
    target.x - observer.x,
    target.y - observer.y
  };
  
  //position of the relevant boundaries (will also be abused as a retval later)
  //start by assuming max bounds (lower right)...
  Vector2 boundary = {
    X_MAXIMUM_BOUND,
    Y_MAXIMUM_BOUND
  };
  //and then correct by axis when wrong
  if(targetDelta.x < 0) {boundary.x = X_MINIMUM_BOUND;}
  if(targetDelta.y < 0) {boundary.y = Y_MINIMUM_BOUND;}
  
  //vector from observer to relevant map corner
  Vector2 boundaryDelta = {
    boundary.x - observer.x,
    boundary.y - observer.y
  };
  
  //find ratio of boundary vs target deltas per-axis
  //(Edit - corrected against div-by-zero)
  //(Note - behavior is undefined if observer and target are equal)
  float xRatio = std::numeric_limits<float>::max();
  if(targetDelta.x) {xRatio = (float)(boundaryDelta.x) / targetDelta.x;}
  float yRatio = std::numeric_limits<float>::max();
  if(targetDelta.y) {yRatio = (float)(boundaryDelta.y) / targetDelta.y;}
  
  if(xRatio > yRatio) { //slope collides with y bound first
    boundary.x = observer.x + (targetDelta.x * yRatio);
  }
  else { //slope collides with x bound first
    boundary.y = observer.y + (targetDelta.y * xRatio);
  }
  
  return boundary;
}

 

Edit - Ah, I see. Same solution. Cool.

 

@P0jahn - He's just using 30.0f and 20.0f as map bounds there. You'd have to fill in the actual bounds where he uses the constants.

Edited by Khatharr

Share this post


Link to post
Share on other sites

Yes, 30.0 is the width and 20.0 is the height (as in the examples in the first post). I think of the ray as being a particle starting at the red point, moving at constant velocity so that at time 1 it is at the green point. I use vertical_intersection_time and horizontal_intersection_time to see when that particle would hit the edges of the map. Whichever one happens first is where the black dot will be.

 

std::min does what you expect: Return the minimum of two values. I don't know how you say that in Java.

Share this post


Link to post
Share on other sites

Hmmmm. I did not get it to work for some reason.

Watch the result:

[attachment=12972:error.png]

 

The position is wrong as well.

 

The code:

public static Point findEdgePoint(GameObject observer, GameObject target) //TODO:
{
 float vertical_intersection_time = 1.0e20f;


 if (target.posX > observer.posX) vertical_intersection_time = (observer.stage.width-observer.posX)/(target.posX-observer.posX);
 else if (target.posX < observer.posX) vertical_intersection_time = (0.0f-observer.posX)/(target.posX-observer.posX);


 float horizontal_intersection_time = 1.0e20f;


 if (target.posY > observer.posY) horizontal_intersection_time = (observer.stage.height-observer.posY)/(target.posY-observer.posY);
 else if (target.posY < observer.posY) horizontal_intersection_time = (0.0f-observer.posY)/(target.posY-observer.posY);


 float time = Math.min(horizontal_intersection_time, vertical_intersection_time);


 return new Point((int)(observer.posY + time * (target.posY-observer.posY)), (int)(observer.posY + time * (target.posY-observer.posY)));
}

Where did it go wrong?

Share this post


Link to post
Share on other sites

Ops, my bad. Fixed it. Works perfect now, almost...

There seems to be some inconsistency  when the black circle is at the bottom. The circle is not at the bottom-most position, instead, it is about 40 pixels above it.

The problem is probably because the provided method use float as coordinates while my game only use ints as coordinates.

Is there a way around this?

Share this post


Link to post
Share on other sites
Ops, my bad. Fixed it. Works perfect now, almost...
There seems to be some inconsistency  when the black circle is at the bottom. The circle is not at the bottom-most position, instead, it is about 40 pixels above it.
The problem is probably because the provided method use float as coordinates while my game only use ints as coordinates.
Is there a way around this?

That doesn't sound like a int-vs-float problem at all. Pick a particular example where the code does the wrong thing and follow it step by step, using a debugger. You should be able to see at what point the computation departs from what you expect.

Share this post


Link to post
Share on other sites

I fixed it somehow. I think that it... Actually I have no idea how I fixed it. But the problem is solved, big thanks to all the help.

I am going to test this ingame, as see how it works. I will report back if there is anything that do not work well.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this