代码之家  ›  专栏  ›  技术社区  ›  ivan_ivanovich_ivanoff

需要一个函数来限制一条直线(由其坐标所知)的长度

  •  0
  • ivan_ivanovich_ivanoff  · 技术社区  · 15 年前

    我需要一个函数,它取一条直线(由它的坐标知道) 并返回一行 相同的 角度,但 限于一定长度 .

    我的代码给出了正确的值 只有 当线路转弯时 “对”
    (仅凭经验证明,对不起)。

    我错过什么了吗?

    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
          };
    }
    

    顺便说一句,我知道在Java中返回数组是愚蠢的, 但只是举个例子。

    6 回复  |  直到 15 年前
        1
  •  2
  •   RichieHindle    15 年前

    在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
  •  3
  •   ghempton    15 年前

    仅仅把它当作一个向量就容易了。通过除以它的大小,然后乘以所需长度的一个因子,将其归一化。

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

        3
  •  1
  •   duffymo    15 年前

    如果你了解向量的一些知识,这是一个简单的问题。

    给定两点(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
  •   Jherico    15 年前

    将行封装到类中,添加Unit方法和Scale方法。

    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);
    
    }
    }
    

    现在您可以通过调用

    Line result = new Line(x1, x2, y1, y2).unit().scale(l);
    
        5
  •  1
  •   Adam Rosenfield    15 年前

    不需要使用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)};
    }
    
        6
  •  0
  •   phihag    15 年前

    只使用 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];}
        }
    }