【问题标题】:Need a function to limit a line (known by its coordinates) in its length需要一个函数来限制一条线(通过它的坐标知道)的长度
【发布时间】:2010-10-27 11:51:30
【问题描述】:

我需要一个函数,它需要一条线(通过它的坐标知道) 并返回一条具有相同角度但限制在一定长度内的线。

我的代码仅在行转'右'时给出正确的值
(仅凭经验证明,抱歉)。

我错过了什么吗?

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 中返回数组很愚蠢, 但这只是示例。

【问题讨论】:

  • 您对 NaN 的检查将始终返回 false,因为没有任何东西等于 NaN。错误返回 0 也是不好的,因为 0 是一个有效的角度。
  • 哦,你是对的!它来自一些旧代码。

标签: java math graphics image-processing drawing


【解决方案1】:

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

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

【讨论】:

  • 没错,atan2就是这里要用的方法。它有更多信息可以使用,因为它将 x 和 y 作为单独的参数,并且可以正确地返回从 -π 到 +π 的角度。 atan 只有足够的信息来覆盖 -π/2 到 π/2 的范围。
【解决方案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-)

【讨论】:

  • +1 - 我开始非常欣赏 Python 的简洁和优雅。好的。不需要对长度进行“if”检查 - 它适用于除长度 == 0 以外的所有情况。这就是您需要进行的检查。也不需要 abs(),因为正方形总是正数。
  • @duffymo:关于 abs() 的好点 - 我已经删除了它。但我认为'if'是必要的,否则当它比限制短时它会增长
  • 会的,但这不一定是错误的结果。它只是无法满足海报提出的狭隘要求。在另一个用例中扩展这条线同样有效。
【解决方案3】:

如果您对向量有所了解,这将是一个简单的问题。

给定两个点 (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】:

    将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】:

      无需使用 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】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-01-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多