我有两个点a和b,以及一个0,0,w,h的边界框。两个点都在边界框内。如何扩展a和b创建的线段以找到线与框相交的点c和d?
*c-------------*
| \ |
| \ |
| a |
| \ |
| \ |
| b |
| \ |
*--------d-----*
答案 0 :(得分:1)
获取equation for the line
对于每个(垂直)侧取X并求解Y - 检查Y是否在顶部和底部之间
如果不是,则使用水平边的Y值并求解'X'
答案 1 :(得分:0)
好的,如果你弄错了,让我们看一个例子:假设w = 6,h = 5,并假设线段在(3,4)和(2,1)之间。
y
^
|
6
5------------
4 x |
3 |
2 |
1 x |
0 1 2 3 4 5 6 -->x
让我们找到斜率,
m = (y2-y1)/(x2-x1) = (4-1)/(3-2) = 3
现在拦截c在哪里,y = mx + c
。使用第一个点(2,1),
1 = 3*2 + c => c = -5.
因此,该行的等式为y = 3x -5
或3x - y - 5 = 0
。
现在,使用边界条件y>=0 AND y<=5
和x>=0 AND x<=6
x = 0 => 3*0 - y - 5 = 0 => y = -5 --> Out of boundary
y = 0 => 3*x - 0 - 5 = 0 => x = 5/3 --> Within boundary (Intersects bottom line)
x = 6 => 3*6 - y - 5 = 0 => y = 13 --> Out of boundary
y = 5 => 3*x - 5 - 5 = 0 => x = 10/3 --> Within boundary (Intersects top line)
答案 2 :(得分:0)
由于直线是直的,我们知道渐变是:
gradient = (ax - bx) / (ay - by)
事实上,对于X,Y点上的任何一点:
gradient = (X - bx) / (Y - by)
重新排列我们得到以下表达式,允许我们在给定X给出Y或Y的情况下找到X:
X = (gradient * (Y - by)) + bx
Y = ((X - bx) / gradient) + by
我们也有框的边界,称之为 leftX , rightx , topy 和 bottomy 。
我们可以通过使用上述方程计算出线与每个边界相交的点,例如。
Y = ((leftx - bx) / gradient) + by
当X = leftx 时,为Y赋予一些值。
真正的问题是这个线点是否在框内。在您的示例中,我们将得到大于 topy 的Y值,因此我们可以得出结论,该行与该框的左侧边缘不相交。
计算所有四个交叉点,你会发现它们中只有两个在框的范围内。这是你需要的两个。当然,在特殊情况下,您的C和D点实际上是方框的角落,您的 leftx 解决方案将与您的 topy 解决方案相同(在你的例子:如果这条线倾斜了另一条路,可能是 leftx 和 bottomy 。
答案 3 :(得分:0)
对我而言,回答的最佳方式是尝试这个主题,因为它让我感兴趣。
我使用Processing作为视觉部分(及其PVector,但在此处使用它是微不足道的)。基本上,它是Java代码。我使用了Wikipedia's Line-line intersection文章的公式。
int MARGIN = 10;
int POINT_SIZE = 7;
// Definition of the bouding box
float xMin, xMax;
float yMin, yMax;
// The two points inside the bounding box
// A PVector is just a pair of x and y coordinates
PVector pointA = new PVector();
PVector pointB = new PVector();
// The intersection points
PVector[] pointsI = new PVector[2];
void setup()
{
size(800, 800);
MakeBB();
SetPoints();
FindIntersections();
}
void draw()
{
background(#DDFFFF);
stroke(#FFFF00);
fill(#8000FF);
rect(xMin, yMin, xMax - xMin, yMax - yMin);
noStroke();
fill(#FF8000);
ellipse(pointA.x, pointA.y, POINT_SIZE, POINT_SIZE);
fill(#FF8000);
ellipse(pointB.x, pointB.y, POINT_SIZE, POINT_SIZE);
stroke(#FFFF00);
strokeWeight(5);
line(pointA.x, pointA.y, pointB.x, pointB.y);
noStroke();
fill(#FF0000);
ellipse(pointsI[0].x, pointsI[0].y, POINT_SIZE * 2, POINT_SIZE * 2);
fill(#FF0000);
ellipse(pointsI[1].x, pointsI[1].y, POINT_SIZE * 2, POINT_SIZE * 2);
stroke(#FF8000);
strokeWeight(1);
line(pointsI[0].x, pointsI[0].y, pointsI[1].x, pointsI[1].y);
}
void keyPressed()
{
MakeBB();
SetPoints();
FindIntersections();
}
// Make bounding box
void MakeBB()
{
xMin = (int) random(MARGIN, width/2);
xMax = (int) random(width/2, width - MARGIN);
yMin = (int) random(MARGIN, height/2);
yMax = (int) random(height/2, height - MARGIN);
}
void SetPoints()
{
pointA.x = (int) random(xMin, xMax);
pointA.y = (int) random(yMin, yMax);
pointB.x = (int) random(xMin, xMax);
pointB.y = (int) random(yMin, yMax);
}
void FindIntersections()
{
// The corners of the BB
PVector pTL = new PVector(xMin, yMin);
PVector pBL = new PVector(xMin, yMax);
PVector pTR = new PVector(xMax, yMin);
PVector pBR = new PVector(xMax, yMax);
// The sides of the BB
PVector pT = IntersectLines(pTL, pTR);
PVector pB = IntersectLines(pBL, pBR);
PVector pL = IntersectLines(pTL, pBL);
PVector pR = IntersectLines(pTR, pBR);
int i = 0;
// Eliminates the intersection points out of the segments
if (pT != null && pT.x >= xMin && pT.x <= xMax) pointsI[i++] = pT;
if (pB != null && pB.x >= xMin && pB.x <= xMax) pointsI[i++] = pB;
if (pL != null && pL.y >= yMin && pL.y <= yMax) pointsI[i++] = pL;
if (pR != null && pR.y >= yMin && pR.y <= yMax) pointsI[i++] = pR;
}
// Compute intersection of the line made of pointA and pointB
// with the given line defined by two points
PVector IntersectLines(PVector p1, PVector p2)
{
PVector pRes = new PVector();
float v1 = pointA.x * pointB.y - pointA.y * pointB.x;
float v2 = p1.x * p2.y - p1.y * p2.x;
float d = (pointA.x - pointB.x) * (p1.y - p2.y) -
(pointA.y - pointB.y) * (p1.x - p2.x);
if (d == 0)
{
println("Ouch!");
return null;
}
pRes.x = (v1 * (p1.x - p2.x) - (pointA.x - pointB.x) * v2) / d;
pRes.y = (v1 * (p1.y - p2.y) - (pointA.y - pointB.y) * v2) / d;
return pRes;
}
这是一个快速的黑客,没有优化和所有。但它有效......: - )
答案 4 :(得分:0)
有趣,昨晚,我意识到我的解决方案对于给定的问题有点过于通用......有一个通用的解决方案很好,但是仅针对垂直和水平线进行测试,公式可以简单得多
所以我写了一个简化版本并来到这里展示它......看到第一个答案,接受了答案,刚刚说明了!我忽略了这个提示,跳过更通用的解决方案......
无论如何,因为这可能是其他访问者感兴趣的,这里是替代版本:
void FindIntersections()
{
// Test against the sides of the BB
PVector pT = IntersectHorizontalSegment(yMin, xMin, xMax);
PVector pB = IntersectHorizontalSegment(yMax, xMin, xMax);
PVector pL = IntersectVecticalSegment(xMin, yMin, yMax);
PVector pR = IntersectVecticalSegment(xMax, yMin, yMax);
int i = 0;
// Eliminates the non-intersecting solutions
if (pT != null) pointsI[i++] = pT;
if (pB != null) pointsI[i++] = pB;
if (pL != null) pointsI[i++] = pL;
if (pR != null) pointsI[i++] = pR;
}
PVector IntersectHorizontalSegment(float y, float xMin, float xMax)
{
float d = pointA.y - pointB.y;
if (d == 0)
return null; // Horizontal line doesn't intersect horizontal segment (unless they have same y)
float x = -(pointA.x * pointB.y - pointA.y * pointB.x - y * (pointA.x - pointB.x)) / d;
println("X: " + x);
if (x < xMin || x > xMax)
return null; // Not in segement
return new PVector(x, y);
}
PVector IntersectVecticalSegment(float x, float yMin, float yMax)
{
float d = pointA.x - pointB.x;
if (d == 0)
return null; // Vertical line doesn't intersect vertical segment (unless they have same x)
float y = (pointA.x * pointB.y - pointA.y * pointB.x - x * (pointA.y - pointB.y)) / d;
println("Y: " + y);
if (y < yMin || y > yMax)
return null; // Not in segement
return new PVector(x, y);
}
它减少了对象创建,这是一件好事。在一个强烈调用这些例程的程序中,我甚至会完全避免创建对象(传递一个对象以获得结果),因为垃圾收集会减慢很多帧速率很重要的应用程序(具有可见的发生率)。