我正在寻找一种优化的基于整数的点对点算法,您可以在其中使用开始和结束坐标定义线,并根据x或y输入来查找点。
我知道如何使用dy / dx除法来做到这一点,但我正在寻找一种消除所有除法的算法。
这是我目前正在做的事情:
int mult = ((px - v0.x)<<16) / (v1.x - v0.x);
vec2 result{px, v0.y + (lerpmult*(v1.y - v0.y))>>16};
第一行的划分是我要消除的问题。
答案 0 :(得分:0)
解决此问题的一个技巧是使用scalar product确定两个向量之间的角度的余弦值:
def line_test(a, b, p):
v_ap = tuple(m - n for n, m in zip(a, p))
v_ab = tuple(m - n for n, m in zip(a, b))
scp = sum(m * n for m, n in zip(v_ap, v_ab))
return scp > 0 and scp * scp == sum(n * n for n in v_ap) * sum(n * n for n in v_ab) and all(m <= n for m, n in zip(v_ap, v_ab))
以上函数的参数是线的端点(a
和b
)和点p
(图像中的c
),我们要测试。
逐步在每一行中发生以下情况:
v_ap = tuple(m - n for n, m in zip(a, p))
a
到p
(v_ap
)的向量v_ab = tuple(m - n for n, m in zip(a, b))
a
到b
(v_ab
)的向量scp = sum(m * n for m, n in zip(v_ap, v_ab))
v_ap
和v_ab
的标量积。结果为scp = cos(v_ab, v_ap) * euclidean_length(v_ab) * euclidean_length(v_ap)
,其中向量的欧式长度定义为sqrt(sum(n * n for n in vector))
(向量的几何长度的标准定义)。return scp > 0 and scp * scp == sum(n * n for n in v_ap) * sum(n * n for n in v_ab) and all(m <= n for m, n in zip(v_ap, v_ab)
scp * scp == sum(n * n for n in v_ap) * sum(n * n for n in v_ab)
由于不允许除法,我们也不应该使用平方根,因为它的计算通常涉及除法。因此,我们不用计算平方根,而是将两个向量的欧几里德长度和标量积都取平方,从而消除了平方根计算:
scp = cos(v_ab, v_ap) * euclidean_length(v_ab) * euclidean_length(v_ap) =
= cos(v_ab, v_ap) * sqrt(sum(n ^ 2 for n in v_ab)) * sqrt(sum(n ^ 2 for n in v_ap))
scp ^ 2 = cos(v_ab, v_ap) ^ 2 * sum(n ^ 2 for n in v_ab) * sum(n ^ 2 for n in v_ap)
如果两个向量指向同一方向,则它们之间的角度的余弦值应为1。因此,如果向量共享相同方向,则标量积的平方将为
euclidean_length(v_ap) ^ 2 * euclidean_length(v_ab) ^ 2
然后将其与实际标量积scp
进行比较。
但是,这留下了一个问题:用正方形消除符号,我们将用比较scp > 0
进行单独检查。由于欧式长度始终为正,因此仅余弦的符号决定scp
的值。负值scp
表示v_ap
和v_ab
之间的夹角至少为pi / 4
,最大为pi * 3/4
。但是,scp
的符号在平方时会丢失,这意味着我们只能检查两个向量是否平行,而不能检查两个向量是否指向同一方向。通过另外检查scp > 0
可以解决此问题。
最后但并非最不重要的一点是,我们必须检查从a
到p
的距离是否比从a
到b
的距离短。这可以通过检查v_ap
的长度是否小于v_ab
来完成。由于我们已经检查了两个向量指向完全相同的方向,因此足以检查v_ap
中的所有元素是否最多与v_ab
中的相应元素一样大,这是通过完成的>
all(m <= n for m, n in zip(v_ap, v_ab))
答案 1 :(得分:0)
找到的答案如下:
可以说我们的线方程为Ax + By + C = 0
。那我们只需要
这三个系数(A
,B
和C
)。
说这条线穿过点P(P_x, P_y)
和Q(Q_x, Q_y)
。然后
计算上述三个系数很容易。
A = P_y - Q_y,
B = Q_x - P_x,
C = - A P_x - B P_y
一旦有了线方程,就可以轻松计算出x
或y
分别协调给定的y
或x
。
这是我的c++
模板:
#include <iostream>
using namespace std;
// point struct
struct pt {
int x, y;
};
// line struct
struct line {
int a, b, c;
// create line object
line() {}
line (pt p, pt q) {
a = p.y - q.y;
b = q.x - p.x;
c = - a * p.x - b * p.y;
}
// a > 0; is must be true otherwise runtime error will occure
int getX(int y) {
return (-b * y - c) / a;
}
// b > 0; is must be true otherwise runtime error will occure
int getY(int x) {
return (-a * x - c) / b;
}
};
int main() {
pt p, q;
p.x = 1, p.y = 2;
q.x = 3, q.y = 6;
line m = line(p, q);
cout << "for y = 4, x = " << m.getX(4) << endl;
cout << "for x = 2, y = " << m.getY(2) << endl;
return 0;
}
输出:
for y = 4, x = 2
for x = 2, y = 4