从数学上讲,这个问题只是坐标的变化。更困难的部分是为所涉及的数量找到一个好的符号。
您有两个坐标系统:(x,y) 是您的显示器的笛卡尔坐标,(v,w) 是相对于向量 (c-a),(b-a) 的重心坐标,它们确定另一个(非正交) 系统。
你只需要在 (x,y) 系统中找到两条线的方程,然后将点 p 投影到这些线上就很容易了。
要实现这一点,您可以明确地找到从 (x,y) 坐标传递到 (v,w) 坐标并返回的矩阵。您正在使用的函数toBaryCoords 进行此计算以从 (x,y) 中找到坐标 (v,w),我们可以重用该函数。
我们想要找到从 世界 坐标 (x,y) 到 重心 坐标 (v,w) 的变换系数。格式必须是
v = O_v + x_v * x + y_v * y
w = O_w + x_w * x + y_w * y
即
(v,w) = (O_v,O_w) + (x_v,y_y) * (x,y)
你可以通过计算toBaryCoord(0,0)来确定(O_v,O_w),然后通过计算(1,0)的坐标找到(x_v,x_w),找到(y_v,y_w)=toBaryCoord(1, 0) - (O_v,O_w) 然后通过计算 (y_v,y_w) = toBaryCoord(0,1)-(O_v,O_w) 找到 (y_v,y_w)。
此计算需要调用 toBaryCoord 三次,但实际上每次都在该例程中计算系数,因此您可以修改它以一次计算所有六个值。
你的函数 vp 的值可以计算如下。我将使用 f 而不是 v 因为我们使用 v 作为重心坐标。因此,以下我的意思是 f(x,y) = vp, fa = va, fb = vb, fc = vc。
你有:
f(v,w) = fa + (fb-fa)*v + (fc-fa)*w
即
f(x,y) = fa + (fb-fa) (O_v + x_v * x + y_v * y) + (fc-fa) (O_w + x_w * x + y_w * y)
其中 (x,y) 是您的点 p 的坐标。您可以通过插入三个顶点 a、b、c 的坐标来检查该等式的有效性,并验证您是否获得了三个值 fa、fb 和 fc。请记住,a 的重心坐标是 (0,0),因此 O_v + x_v * a_x + y_v * a_y = 0 等等...(a_x 和 a_y 是点 a 的 x,y 坐标)。
如果你让
q = fa + (fb_fa)*O_v + (fc-fa)*O_w
fx = (fb-fa)*x_v + (fc-fa) * x_w
fy = (fb-fa)*y_v + (fc-fa) * y_w
你得到
f(x,y) = q + fx*x + fy * y
请注意,q、fx 和 fy 可以从 a,b,c,fa,fb,fc 计算一次,如果您只更改点 p 的坐标 (x,y),则可以重复使用它们。
现在如果 f(x,y)>max,您可以轻松地将 (x,y) 投影到达到 max 的那条线上。投影坐标为:
(x',y') = (x,y) - [(x,y) * (fx,fy) - max + q]/[(fx,fy) * (fx,fy)] (fx ,fy)
现在。您想拥有代码。那么这里有一些伪-代码:
toBarycoord(Vector2(0,0),a,b,c,O);
toBarycoord(Vector2(1,0),a,b,c,X);
toBarycoord(Vector2(0,1),a,b,c,Y);
X.sub(O); // X = X - O
Y.sub(O); // Y = Y - O
V = Vector2(fb-fa,fc-fa);
q = fa + V.dot(O); // q = fa + V*O
N = Vector2(V.dot(X),V.dot(Y)); // N = (V*X,V*Y)
// p is the point to be considered
f = q + N.dot(p); // f = q + N*p
if (f > max) {
Vector2 tmp;
tmp.set(N);
tmp.multiply((N.dot(p) - max + q)/(N.dot(N))); // scalar multiplication
p.sub(tmp);
}
if (f < min) {
Vector2 tmp;
tmp.set(N);
tmp.multiply((N.dot(p) - min + q)/(N.dot(N))); // scalar multiplication
p.sum(tmp);
}