将线段扩展到边界框

时间:2009-10-05 15:35:18

标签: algorithm geometry

我有两个点a和b,以及一个0,0,w,h的边界框。两个点都在边界框内。如何扩展a和b创建的线段以找到线与框相交的点c和d?

*c-------------*
| \            |
|  \           |
|   a          |
|    \         |
|     \        |
|      b       |
|       \      |
*--------d-----*

5 个答案:

答案 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 -53x - y - 5 = 0

现在,使用边界条件y>=0 AND y<=5x>=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);
}

它减少了对象创建,这是一件好事。在一个强烈调用这些例程的程序中,我甚至会完全避免创建对象(传递一个对象以获得结果),因为垃圾收集会减慢很多帧速率很重要的应用程序(具有可见的发生率)。