Ближайшая точка на круге в 3d. Чего не хватает? - PullRequest
1 голос
/ 04 июля 2011

Надеюсь, мне удастся объяснить это ясно.Я пытаюсь вычислить ближайшую точку на окружности в 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 с положением плоскостинапример, компонент центра круга в направлении его нормали.В этом случае у направление так значение 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

1 Ответ

2 голосов
/ 04 июля 2011

Мне кажется, что эта бумага, на которую вы ссылались, немного напоминает эту операцию.

Ваша проблема в том, что 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) и т. д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...