需要一个函数来限制一条线(以其坐标表示)的长度

时间:2009-05-19 23:06:03

标签: java math graphics image-processing drawing

我需要一个占据一条线的函数(以其坐标表示) 并返回一行相同角度,但限制为一定长度

当线路转为'右'时,我的代码会提供正确的值
(经验证明,对不起)。

我错过了什么吗?

public static double getAngleOfLine(int x1, int y1, int x2, int y2) {
  double opposite = y2 - y1;
  double adjacent = x2 - x1;

  if (adjacent == Double.NaN) {
    return 0;
  }

  return Math.atan(opposite / adjacent);
}

// returns newly calculated destX and destY values as int array
public static int[] getLengthLimitedLine(int startX, int startY,
    int destX, int destY, int lengthLimit) {

  double angle = getAngleOfLine(startX, startY, destX, destY);

  return new int[]{
        (int) (Math.cos(angle) * lengthLimit) + startX,
        (int) (Math.sin(angle) * lengthLimit) + startY
      };
}
BTW:我知道在Java中返回数组是愚蠢的, 但这仅仅是为了这个例子。

6 个答案:

答案 0 :(得分:3)

将它视为矢量会更容易。通过将其大小除以然后乘以所需长度的因子来归一化它。

但是,在您的示例中,请尝试Math.atan2。

答案 1 :(得分:2)

在Python中,因为我没有方便的Java编译器:

import math

def getLengthLimitedLine(x1, y1, x2, y2, lengthLimit):
    length = math.sqrt((x2-x1)**2 + (y2-y1)**2)
    if length > lengthLimit:
       shrink_factor = lengthLimit / length
       x2 = x1 + (x2-x1) * shrink_factor
       y2 = y1 + (y2-y1) * shrink_factor
    return x2, y2

print getLengthLimitedLine(10, 20, 25, -5, 12)
# Prints (16.17, 9.71) which looks right to me 8-)

答案 2 :(得分:1)

不需要使用trig,它可能有一些令人讨厌的边缘情况。只需使用类似的三角形:

public static int[] getLengthLimitedLine(int startX, int startY,
    int destX, int destY, int lengthLimit)
{
    int deltaX = destX - startX;
    int deltaY = destY - startY;
    int lengthSquared = deltaX * deltaX + deltaY * deltaY;
    // already short enough
    if(lengthSquared <= lengthLimit * lengthLimit)
        return new int[]{destX, destY};

    double length = Math.sqrt(lengthSquared);
    double newDeltaX = deltaX * lengthLimit / length;
    double newDeltaY = deltaY * lengthLimit / length;

    return new int[]{(int)(startX + newDeltaX), (int)(startY + newDeltaY)};
}

答案 3 :(得分:1)

如果您了解有关矢量的内容,这是一个简单的问题。

给定两个点(x1,y1)和(x2,y2),可以计算从第1点到第2点的向量:

v12 =(x2-x1)i +(y2-y2)j

其中i和j是x和y方向的单位向量。

您可以通过获取组件的平方和的平方根来计算v的大小:

v = sqrt((x2-x2)^ 2 +(y2-y1)^ 2)

从点1到点2的单位矢量等于v12除以其幅度。

鉴于此,你可以通过将单位向量乘以长度并将其加到第1点来计算单位向量上所需距离的点。

答案 4 :(得分:1)

在一个类中封装Line,添加一个单位方法和一个缩放方法。

public class Line {
private float x;
private float y;

public Line(float x1, float x2, float y1, float y2) {
    this(x2 - x1, y2 - y1);
}

public Line(float x, float y) {
    this.x = x;
    this.y = y;
}

public float getLength() {
    return (float) Math.sqrt((x * x) + (y * y));
}

public Line unit() {
    return scale(1 / getLength());
}

public Line scale(float scale) {
    return new Line(x * scale, y * scale);

}
}

现在你可以通过调用

获得任意长度为l的行
Line result = new Line(x1, x2, y1, y2).unit().scale(l);

答案 5 :(得分:0)

只需使用Pythagorean theorem,就像这样:

public static int[] getLengthLimitedLine(int start[], int dest[], int lengthLimit) {
    int xlen = dest[0] - start[0]
    int ylen = dest[1] - start[1]
    double length = Math.sqrt(xlen * xlen + ylen * ylen)

    if (length > lengthLimit) {
        return new int[] {start[0], start[1],
                start[0] + xlen / lengthLimit,
                start[1] + ylen / lengthLimit}
    } else {
        return new int[] {start[0], start[1], dest[0], dest[1];}
    }
}