3d 中圆上的最近点。缺少什么?

发布于 2024-11-18 03:45:12 字数 1507 浏览 7 评论 0原文

我希望我能够清楚地解释这一点。我正在尝试计算 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

I hope I manage to explain this clearly. I am trying to calculate the closest point on a circle in 3D. I found the following solution:
http://www.geometrictools.com/Documentation/DistancePoint3Circle3.pdf

My code is below (written in Lua). The main problem is that the projection Q seems to be incorrect, or I don't understand how to calculate it correctly. As you can read in the paper Q should be the projection of the point on the plane of the circle.

For example the normal of the circle is {0,1,0} and its center is located at {3, 3, 3}. My point (p) for which I'm trying to calculate the closest distance to the circle is located at {6, 3, 2}. Then, in my calculation, the projection Q onto the plane of the circle is {6, 0, 2}.

In order to make the algorithm work I seem to have to offset Q with the position of the plane eg the circle center component in the direction of its normal. In this case the y direction so value 3.

I can hack this for normal {0,1,0} because its easy, but once the circle will face any arbitrary position I don't know how to calculate this.

What am I missing and where am I going wrong?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

深海夜未眠 2024-11-25 03:45:12

我认为,你链接到的那篇论文对这次行动起到了一定的推动作用。

您的问题是 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 类会更方便,也许是这个,这样你就可以写 P - C 而不是挑剔的vec3.sub(P, C) 等等。

That paper you linked to makes a bit of a meal of this operation, I think.

Your problem is that projectVectorOntoPlane does not actually project the vector onto the plane you want. It projects the vector onto another plane that's parallel to the plane you want, but which passes through the origin. (You're then trying to fix this problem with your Q[2] = C[2], but this just makes things worse.)

A plane can be defined by a normal vector together with some point on the plane, so you could write the projectVectorOntoPlane function like this:

-- 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

However, for this problem it's simplest to work all the way through in a coordinate system based on the centre of the circle, so I suggest something like this:

-- 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

Oh, and you might find it more convenient to use a nicer vec3 class, perhaps this one, so that you can write P - C instead of the fussy vec3.sub(P, C) and so on.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文