我希望我能清楚地解释清楚。我正在尝试计算3D中圆圈上的最近点。我找到了以下解决方案: http://www.geometrictools.com/Documentation/DistancePoint3Circle3.pdf
我的代码如下(用Lua编写)。主要问题是投影Q似乎不正确,或者我不明白如何正确计算它。正如您在纸张中可以看到的,Q应该是圆的平面上的点的投影。
例如,圆的法线为{0,1,0},其中心位于{3,3,3}。我想要计算距离圆的最近距离的点(p)位于{6,3,2}。然后,在我的计算中,投影Q在圆平面上是{6,0,2}。
为了使算法工作,我似乎必须将Q与平面的位置偏移,例如在其法线方向上的圆心分量。在这种情况下,y方向值为3。
我可以将其破解为普通{0,1,0},因为它很容易,但是一旦圆圈将面临任意位置,我不知道如何计算它。
我错过了什么,我哪里出错?
function calculatePointCircleDistance(p, circleCenter, circleNormal, circleRadius)
local C = circleCenter
local R = circleRadius
local Q = projectVectorOntoPlane(p, circleNormal)
-- I need to do a fix like this in order to get the calculations right
-- This for example only works with circleNormal {0,1,0}
-- Adding the y component of the circle position to the projection Q
Q[2] = C[2]
if vec3.equal(Q, C) == 1 then
print("point exacly aligned with center circle")
return vec3.mag(vec3.sub(C, p)), C
end
-- the following is calculating X=C+R (Q−C / |Q−C|)
local QminC = vec3.sub(Q, C)
local tmp = vec3.scale(vec3.div(QminC, vec3.mag(QminC)), R)
local X = vec3.add(C, tmp)
-- return distance as |X-p| as well as point X
return vec3.mag(vec3.sub(X, p)), X
end
function projectVectorOntoPlane(v, normal)
-- U = V - (V dot N)N
local vProjected = vec3.sub(v, vec3.scale(normal, vec3.dot(v, normal)))
return vProjected
end
答案 0 :(得分:2)
我认为你所关联的那篇文章对这项操作有点用处。
您的问题是projectVectorOntoPlane
实际上并没有将矢量投影到您想要的平面上。它将矢量投影到另一个平面上,该平面与您想要的平面平行,但是它通过原点。 (然后您尝试使用Q[2] = C[2]
修复此问题,但这只会让事情变得更糟。)
平面可以由法线向量和平面上的某个点定义,因此您可以像这样编写projectVectorOntoPlane
函数:
-- Project P onto the plane with normal n containing the point O.
function projectVectorOntoPlane(P, n, O)
return vec3.sub(P, vec3.scale(n, vec3.dot(vec3.sub(P, O), n)))
end
然而,对于这个问题,最简单的方法是在基于圆心的坐标系中一直工作,所以我建议像这样:
-- Return a point on the circle with center C, unit normal n and radius r
-- that's closest to the point P. (If all points are closest, return any.)
function pointCircleClosest(P, C, n, r)
-- Translate problem to C-centred coordinates.
local P = vec3.sub(P, C)
-- Project P onto the plane containing the circle.
local Q = vec3.sub(P, vec3.scale(n, vec3.dot(n, P)))
-- If Q is at the centre, all points on the circle are equally close.
if vec3.equal(Q, {0,0,0}) then
Q = perpendicular(n)
end
-- Now the nearest point lies on the line through the origin and Q.
local R = vec3.sub(P, vec3.scale(Q, r / vec3.mag(Q)))
-- Return to original coordinate system.
return vec3.add(R, C)
end
-- Return an arbitrary vector that's perpendicular to n.
function perpendicular(n)
if math.abs(n[1]) < math.abs(n[2]) then
return vec3.cross(n, {1,0,0})
else
return vec3.cross(n, {0,1,0})
end
end
哦,您可能会发现使用更好的vec3
类perhaps this one会更方便,这样您就可以编写P - C
而不是挑剔的vec3.sub(P, C)
等等上。