我有一条从点 A 到点 B 的直线;我知道这两个点的坐标 (x,y)。我还有一个以点 B 为中心、宽和高已知的矩形。
我需要找到这条直线与矩形相交的点的坐标 (x,y)。是否有一个公式可以给出这个点的坐标?
我有一条从点 A 到点 B 的直线;我知道这两个点的坐标 (x,y)。我还有一个以点 B 为中心、宽和高已知的矩形。
我需要找到这条直线与矩形相交的点的坐标 (x,y)。是否有一个公式可以给出这个点的坐标?
// Line2 - 2D line with origin (= offset from 0,0) and direction
// Rectangle2 - 2D rectangle by min and max points
// Contacts - Stores entry and exit times of a line through a convex shape
Contacts findContacts(const Line2 &line, const Rectangle2 &rect) {
Contacts contacts;
// If the line is not parallel to the Y axis, find out when it will cross
// the limits of the rectangle horizontally
if(line.Direction.X != 0.0f) {
float leftTouch = (rect.Min.X - line.Origin.X) / line.Direction.X;
float rightTouch = (rect.Max.X - line.Origin.X) / line.Direction.X;
contacts.Entry = std::fmin(leftTouch, rightTouch);
contacts.Exit = std::fmax(leftTouch, rightTouch);
} else if((line.Offset.X < rect.Min.X) || (line.Offset.X >= rect.Max.X)) {
return Contacts::None; // Rectangle missed by vertical line
}
// If the line is not parallel to the X axis, find out when it will cross
// the limits of the rectangle vertically
if(line.Direction.Y != 0.0f) {
float topTouch = (rectangle.Min.Y - line.Offset.Y) / line.Direction.Y;
float bottomTouch = (rectangle.Max.Y - line.Offset.Y) / line.Direction.Y;
// If the line is parallel to the Y axis (and it goes through
// the rectangle), only the Y axis needs to be taken into account.
if(line.Direction.X == 0.0f) {
contacts.Entry = std::fmin(topTouch, bottomTouch);
contacts.Exit = std::fmax(topTouch, bottomTouch);
} else {
float verticalEntry = std::fmin(topTouch, bottomTouch);
float verticalExit = std::fmax(topTouch, bottomTouch);
// If the line already left the rectangle on one axis before entering it
// on the other, it has missed the rectangle.
if((verticalExit < contacts.Entry) || (contacts.Exit < verticalEntry)) {
return Contacts::None;
}
// Restrict the intervals from the X axis of the rectangle to where
// the line is also within the limits of the rectangle on the Y axis
contacts.Entry = std::fmax(verticalEntry, contacts.Entry);
contacts.Exit = std::fmin(verticalExit, contacts.Exit);
}
} else if((line.Offset.Y < rect.Min.Y) || (line.Offset.Y > rect.Max.Y)) {
return Contacts::None; // Rectangle missed by horizontal line
}
return contacts;
}
end - start
。计算两个交点的坐标只需使用entryPoint = origin + direction * contacts.Entry
和exitPoint = origin + direction * contacts.Exit
即可。我不知道这是否是最好的方法,但你可以计算出线段在矩形内部的比例。你可以通过矩形的宽度和点A和B的x坐标(或高度和y坐标)之差来得到这个比例;根据宽度和高度,你可以确定哪种情况适用,而另一种情况将在矩形边缘的延伸上。当你得到这个比例后,只需取从B到A向量的该比例,就可以得到交点的坐标。
通过一些简单的数学计算,你可以比大多数答案建议的方法更轻松地解决这个问题。
策略:
在C++中,这看起来像:
struct point { double x, y; };
struct rect { point center; double xradius, yradius; }
point intersect(const point& p, const rect& r) {
// Steps 1 and 2: Transform to origin and scale by xradius and yradius.
point q{ (p.x - r.center.x) / r.xradius, (p.y - r.center.y) / r.yradius };
// Steps 3 and 4: Transform to Quadrant 1 and find scaling factor.
double f = max(abs(q.x), abs(q.y));
// Step 5: Divide by scaling factor to find intersection point on square.
point intersect{ q.x/f, q.y/f };
// Step 6: Inverse transformations from steps 1 and 2.
return {intersect.x * r.xradius + r.center.x, intersect.y * r.yradius + r.center.y};
}
point intersect(const point& p, const rect& r) {
matrix m = scale_matrix(r.xradius, r.yradius)*translate_matrix(p - r.center)
point q = m * p;
return m.inverse() * q/(max(abs(q.x), abs(q.y))
}
警告:此代码未处理p.x==r.centerx && p.y==r.centery
的情况,这将导致第5步出现除以零的错误。处理该错误条件将留给读者作为练习。 :-)