【问题标题】:calculate a perpendicular offset from a diagonal line计算与对角线的垂直偏移
【发布时间】:2013-06-16 05:06:28
【问题描述】:

我正在编写一个音乐显示程序,需要在两个音符之间画一个“连线”。 连线是连接两个音符的曲线 - 只是为了清楚。

我知道音符的位置并计算出曲线的起点和终点应该在哪里 - 起点 A 和终点 B

我现在需要在给定所需距离的情况下获得偏移量C,以便在二次曲线中使用。 这就是我对数学公式的知识和理解非常有限的地方。

我确实在 SO 中查看了我的答案,但提出的解决方案要么不起作用,要么我的代码太有限,无法正确编码。

谁能帮我计算一下,非数学形式

【问题讨论】:

  • 抛物线的确切高度有影响吗?
  • 您想要一条通过 A、B 连接并在 C 上具有峰值的抛物线吗? C的高度是多少?
  • @PandaBearSoup - 抛物线的高度将根据音符之间的距离而变化 - 它们不一定相邻。

标签: math geometry 2d line point


【解决方案1】:

给定线段 AB,您可以使用著名的中点公式 (A + B)/2 找到中点,例如 M。现在计算从 BA 的向量:

p =

= AB

Rotate it about the origin逆时针90°得到垂直向量

n = =

标准化:

n = / ‖n‖ 其中‖n‖ = √(n.x² + n.y²) 是欧几里得范数或长度

C = L(t) = M + t n

使用这个方程——线的参数形式——你可以沿着垂直线(在n的方向)找到任意数量的点。 t 是获得的点 CM 的距离。当t = 0时,你得到M,当t = 1时,你得到一个点,距离M沿n有1个单位,依此类推.这也适用于t 的负值,其中获得的点将位于 AB 的另一侧,即朝向音符。由于t 可以是十进制数,因此您可以通过更改其值来使用它,以从 M 获得所需点的距离和方向。

代码,既然你说你对数学术语不感兴趣;)

vec2d calculate_perp_point(vec2d A, vec2d B, float distance)
{
   vec2d M = (A + B) / 2;
   vec2d p = A - B;
   vec2d n = (-p.y, p.x);
   int norm_length = sqrt((n.x * n.x) + (n.y * n.y));
   n.x /= norm_length;
   n.y /= norm_length;
   return (M + (distance * n));
}

这只是伪代码,因为我不确定您在项目中使用的向量数学库。

上面的粗体变量是二维向量;大写字母表示点,小写字母表示没有位置的向量

【讨论】:

  • 感谢您的宝贵时间@legends2k。如果我理解正确,对您的 vec2d 对象执行的每个操作同样适用于 x 和 y 值?
  • @Simon:是的,当您看到p = B - A 时,它的真正含义是(p.x, p.y) = (B.x - A.x, B.y - A.y),而像distance * n 这样的标量和向量的运算实际上是(distance * n.x, distance * n.y)。乐于助人:)
  • @Simon:如果它对你有帮助,我不介意你接受答案:)
  • 谢谢。我在重启系统后一直在测试。
  • 还有一个问题,你能告诉我如何调整它以便为三次贝塞尔曲线设置两个控制点吗?我应该打开另一个问题吗?
【解决方案2】:

这是一个 Swift 版本:

func pointNormalToLine(startPoint: CGPoint, endPoint: CGPoint, distance: CGFloat) -> CGPoint {

    let midpoint = CGPoint(x: (startPoint.x + endPoint.x) / 2, y: (startPoint.y + endPoint.y) / 2)
    let p = CGPoint(x: startPoint.x - endPoint.x, y: startPoint.y - endPoint.y)
    var n = CGPoint(x: -p.y, y: p.x)
    let norm_length = sqrt((n.x * n.x) + (n.y * n.y))
    n.x /= norm_length
    n.y /= norm_length
    return CGPoint(x: midpoint.x + (distance * n.x), y: midpoint.y + (distance * n.y))
}

【讨论】:

    【解决方案3】:

    我接受了 legends2k 的出色回答,并在 Android 上转换为 Java。这可能会帮助某人节省一些时间。

    private PointF getPerpendicularPoint(int startX, int startY, int stopX, int stopY, float distance)
    {
        PointF M = new PointF((startX + stopX) / 2, (startY + stopY) / 2);
        PointF p = new PointF(startX - stopX, startY - stopY);
        PointF n = new PointF(-p.y, p.x);
        int norm_length = (int) Math.sqrt((n.x * n.x) + (n.y * n.y));
        n.x /= norm_length;
        n.y /= norm_length;
        return new PointF(M.x + (distance * n.x), M.y + (distance * n.y));
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-09
      • 1970-01-01
      相关资源
      最近更新 更多