Home > other >  Finding a point on the right side of a line at a given distance
Finding a point on the right side of a line at a given distance

Time:12-02

I want to find the point at distance d on the right side of a line defined by P1(x1,y1) and P2(x2,y2) (the distance is calculated from the middle of the line). I came up with the following code, which works well, but I think I have made unnecessary calculations, and it can be done faster.

#define PI 3.141592653589793238462643383279502884197169399375105820974944592308

double x2, x1, y1, y2, px, py, p1x, p1y, p2x, p2y, d, ax, ay, b, dx, dy;

d = 2.0; // given distance
ax = (x1   x2) / 2; // middle point
ay = (y1   y2) / 2; // middle point
b = tan(atan2(y2 - y1, x2 - x1)   PI / 2); // slope of the perpendicular line
dx = (d / sqrt(1   (b * b)));
dy = b * dx;
p1x = ax   dx;
p1y = ay   dy;
p2x = ax - dx;
p2y = ay - dy;

// cross product
if (((x2 - x1) * (p1y - y1) - (y2 - y1) * (p1x - x1)) > 0)
{
    px = p1x;
    py = p1y;
}
else
{
    px = p2x;
    py = p2y;
}

CodePudding user response:

You don't need atan, b value, cross product to check orientation (moreover, b might be zero and cause division error).

Instead calculate normalized (unit length) direction vector and get right normal to it:

d = 2.0; // given distance
ax = (x1   x2) / 2; // middle point
ay = (y1   y2) / 2; // middle point
dx = x2 - x1;
dy = y2 - y1;
scale = d / sqrt(dx*dx   dy*dy);   //distance/vector length
px = ax   dy * scale;  // add normal vector to the right side of p1-p2 direction
py = ay - dx * scale;   //note minus sign

CodePudding user response:

For generating a 2D vector perpendicular to another, one result that falls out from a special case of the dot product is that you can swap the two components of the vector and negate one of them.

For example, let's say you have the vector d which points from p1 to p2:

dx = p2x - p1x;
dy = p2y - p1y;

And now you want to generate right which is perpendicular, it is simply:

rightx = dy;
righty = -dx;

Now, let's do a quick visual check for our definition of "on the right", in case we actually want to negate those two values...

  o p2 = [2, 3]
 /
o p1 = [0, 0]

Above, d is simple: [2, 3]. Intuitively, we would think of (as viewed from above) walking from p1 to p2 and looking to the right, which would mean a vector in the positive X direction and the negative Y direction. So yes, that looks fine.

Note: If your co-ordinate system is screen-based (i.e. positive Y direction is down), then the inverse is true (and you would negate both the terms in the calculation of the right vector). This is due to the handedness of the co-ordinate system being left instead of right.

Now, you can calculate the midpoint mid as either (p1 p2) / 2 or p1 d / 2.

midx = (p1x   p2x) / 2;
midy = (p1y   p2y) / 2;

And finally to generate p3 you start from mid and extend down the vector right by an amount height, you need to normalize that vector by dividing by its length and scale by height. Formally, the final point will be mid right * height / length(right).

This is the only particularly expensive part of the calculation, because it needs a square root.

rdist = height / sqrt(rightx * rightx   righty * righty);
p3x = midx   rightx * rdist;
p3y = midy   righty * rdist;

Congratulations! You now have an isosceles triangle!

  • Related