1

これを明確に説明できることを願っています。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} です。

アルゴリズムを機能させるには、平面の位置、たとえば円の中心成分をその法線の方向にオフセットする必要があるようです。この場合、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
4

1 に答える 1

3

あなたがリンクしたその論文は、この操作のちょっとした食事になると思います。

あなたの問題は、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)

于 2011-07-04T15:17:51.447 に答える