Render.ru

Нужна помошь знатоков по векторным операциям

Andots

Знаток
Рейтинг
66
#1
Доброго дня. Нужна подсказка, если конечно знает кто.

есть 3 точки с известными координатами.

нужно математически найти на виртуальной прямой между точками p1 и p2 ближайшую точку от p3
vec.jpg
Интерполяцию (int) между p1 и p2 я сделал и могу получить координаты всех точек в зависимости от дистанции (trans) на этой прямой.
p1 = (x,y,z)
p2 = (x,y,z)
p3 = (x,y,z)
trans = any

v1, v2 = om.MVector(p1), om.MVector(p2)

ds = v2 - v1
dist = om.MVector(v2-v1).length()
int = v1+(trans/dist*ds)

честно говоря векторную алгебру уже не помню и поиск по гуглу мало что дал. Но мало ли, мож кто из APIшников сюда заглядывает и подскажет что.

PS. Глупости вроде "Есть же констрейн closestpoint" не предлагать. Нужен математический способ.
 
Последнее редактирование:

Andots

Знаток
Рейтинг
66
#3
А через высоту треугольника нельзя найти?
Да фиг его знает, в двухмерном пространстве на листке бумаги я бы нашел.. Но 3х мерное немного мозги закручивает, никак не могу сообразить. Как это все векторами выразить, что то крутиться в голове но не могу зацепиться. Не надо мне было с девками в ботаническом саду бухать когда нам в универе векторную алгебру преподавали. Эхх ))))

Вообще наверно кое что можно сделать.. Получить длины всех ребер треугольныка. 1 угол я знаю он 90 град т.е квадрат гипотенузы равен сумме квадратов катетов.. гипотенузу тоже знаю... Блин, а вот катеты не знаю)) хотя знаю 2 гипотенузы и 1 катет общий..Достаточно найти длину любого катета и через интерполяцию получу коорд точки. Мда общий катет это высота треугольника. Жесть, здравствуй школа.
 
Последнее редактирование:

Lemieux

Знаток
Рейтинг
58
#4
Вообще наверно кое что можно сделать.. Получить длины всех ребер треугольныка. 1 угол я знаю он 90 град т.е квадрат гипотенузы равен сумме квадратов катетов.. гипотенузу тоже знаю... Блин, а вот катеты не знаю)) хотя знаю 2 гипотенузы и 1 катет общий..Достаточно найти длину любого катета и через интерполяцию получу коорд точки. Мда общий катет это высота треугольника. Жесть, здравствуй школа.
Углы тут нужны только для частных случаев. А так, у тебя же известны координаты точек, можно посчитать для сторон треугольника, дальше высоту, а потом и вычислить точку.
 

Andots

Знаток
Рейтинг
66
#5
Углы тут нужны только для частных случаев. А так, у тебя же известны координаты точек, можно посчитать для сторон треугольника, дальше высоту, а потом и вычислить точку.
Так и делаю. Формулу то прописал вот впихиваю ее в ноду на питонской API .. Тот еще кровопийца, то одно not defined то другое ему не нравиться. ((( Мозги уже кипеть начинают
 

Dark™

Модератор форума
Команда форума
Рейтинг
431
#6
Вектор к ближайшей точке будет равен P1 + (P3-P1)*(P2-P1)/|(P2-P1)|^2*(P2-P1). Думаю, дальше сами разберетесь.
 
Последнее редактирование:

4i4ikov

Знаток
Рейтинг
37
#8
есть 3 точки с известными координатами.

нужно математически найти на виртуальной прямой между точками p1 и p2 ближайшую точку от p3
Без векторов решил, не выкидывать же теперь))

Есть треугольник со сторонами a,b,c
c - расстояние между P1 и P2, на "с" лежит искомая точка
(a,b,c находятся стандартно по формуле расстояния между точками в трехм. прос-ве)

Находим отрезки x и у, которые делят "с" на две части:
Решаем систему уравнений
x+y = c
a*a-x*x=b*b-y*y

Так как вольфрам альфа сейчас у меня в дауне, решаю на sympy:
from sympy import *
x,y = symbols('x,y')
a,b,c = symbols('a,b,c')
print solve([a*a-x*x-b*b+y*y, x+y-c],[x, y])

sympy говорит:
x = (a**2 - b**2 + c**2)/(2*c)
y = (-a**2 + b**2 + c**2)/(2*c)

коэффициент интерполяции между P1 и P2:
k = x/c
(у не нужен)

получаем точку:
X = (x2*k+x1*(1-k))
Y = (y2*k+y1*(1-k))
Z = (z2*k+z1*(1-k))
 
Последнее редактирование:

Andots

Знаток
Рейтинг
66
#10
Спасибо вам всем огромное за ответы. Я немного по другому сделал, но правда верность метода пока не проверял (сил уже нет )). Проверю завтра если не работает, возьму ваши способы. Формула
Dark™ больше всего приглянулась, все так нода будет, а там чем меньше телодвижений тем лучше.

v1, v2, v3 = Om.MVector(p1), Om.MVector(p2), Om.MVector(p3)



dist1 = Om.MVector(v2-v1).length()
dist2 = Om.MVector(v3-v2).length()
dist3 = Om.MVector(v3-v1).length()

p=(dist1+dist2+dist3)/2

he = 2/(dist1 * math.sqrt(p*(p-dist1)*(p-dist2)*(p-dist3)))


trx = math.sqrt(dist3 - he)

Clvvect = v1+(trx/dist1*ds)
 

4i4ikov

Знаток
Рейтинг
37
#11
Andots, потом, когда у вас заработает, напишите координаты каких нибудь 4-х точек для проверки (три исходные и найденную), я проверю свою писанину.
 

Andots

Знаток
Рейтинг
66
#12
Andots, потом, когда у вас заработает, напишите координаты каких нибудь 4-х точек для проверки (три исходные и найденную), я проверю свою писанину.
Да без проблем. Моя формула правда не совсем корректно заработала ,где то ребра перепутал, поэтому я не сильно мучаясь совестью взял формулу Dark .

Вот с принтов в некий момент времени, (p1 , p2) вектор на котором ищем.
p1 (5.111 , -2.046, -1.956)

p2 (-5.419 , -0.070 , -1.225)

p3 ( -0.246 , 0 , -6.764)

(искомая)intp = (-0.088 , -1,071, -1.595 )

Или с видео с атрибутов можно скатать в разных моментах. Как удобней вам

 
Последнее редактирование:

Andots

Знаток
Рейтинг
66
#14
Ну в данном виде конечно особо незачем. Это всего лишь малая составная часть. Есть просто у меня одна задумка, но для ее реализации мне нужно понимать саму суть подобных операций и уметь это использовать в нодах или в простых скриптах. Делать это все стд средствами майки очень неудобно и тяжко в моем случае.

Ну а если даже у меня ничего путного не получится в итоге, то как минимум + к шансу не страдать от маразма в старости.
 
Последнее редактирование:

4i4ikov

Знаток
Рейтинг
37
#15
p1 (5.111 , -2.046, -1.956)

p2 (-5.419 , -0.070 , -1.225)

p3 ( -0.246 , 0 , -6.764)

(искомая)intp = (-0.088 , -1,071, -1.595 )
Нормалёк, моя тоже работает:
Код:
import maya.OpenMaya as Om

def vectorTest(v1,v2,v3):
     a = Om.MVector(v1-v3).length()
     b = Om.MVector(v2-v3).length()
     c = Om.MVector(v2-v1).length()
     if c:
         x = (a*a - b*b + c*c)/(2*c)
         k = x/c
         v = v2*k+v1*(1-k)
     else:
         v=v1
     return v

v1 = Om.MVector(5.111 , -2.046, -1.956) 
v2 = Om.MVector(-5.419 , -0.070 , -1.225)
v3 = Om.MVector( -0.246 , 0 , -6.764)
v = vectorTest(v1,v2,v3)
print v.x,v.y,v.z
Код:
-0.0880312190608 -1.07037932679 -1.59507959913
Померить бы скорости.
 

Andots

Знаток
Рейтинг
66
#16
Да, в принципе замерить было бы интересно.
Вот что у меня. Но вектора с апи 2.0

import maya.api.OpenMaya as Om

def vectorTest(p1,p2,p3):

v1, v2, v3 = Om.MVector(p1), Om.MVector(p2), Om.MVector(p3)
dist1 = Om.MVector(v2-v1).length()
p4 = v1 + (v3-v1)*(v2-v1)/dist1**2*(v2-v1)
return p4
 
Последнее редактирование:

4i4ikov

Знаток
Рейтинг
37
#17
Да, в принципе замерить было бы интересно.
Вот что у меня. Но вектора с апи 2.0

import maya.api.OpenMaya as Om

def vectorTest(p1,p2,p3):

v1, v2, v3 = Om.MVector(p1), Om.MVector(p2), Om.MVector(p3)
dist1 = Om.MVector(v2-v1).length()
p4 = v1 + (v3-v1)*(v2-v1)/dist1**2*(v2-v1)
return p4
Вектора почти в два раза быстрее.

Замерялка:
Код:
import maya.api.OpenMaya as Om

def vectorTest_4i4ikov(v1,v2,v3):
    a = Om.MVector(v1-v3).length()
    b = Om.MVector(v2-v3).length()
    c = Om.MVector(v2-v1).length()
    k = (a*a - b*b)/(2*c*c) + 0.5
    return v2*k+v1*(1-k)

def vectorTest_Dark(v1,v2,v3):
    v21 = v2-v1
    d = Om.MVector(v21).length()
    return v1+(v3-v1)*v21*v21/(d*d)

import time
class new_Bench:
    mera = time.time
    #mera = time.clock
    def __init__(self):
        self.time=self.mera()
    def reset(self):
        self.__init__()
    def get(self):
        self.time = self.mera() - self.time
        return self.time

v1 = Om.MVector(5.111 , -2.046, -1.956)
v2 = Om.MVector(-5.419 , -0.070 , -1.225)
v3 = Om.MVector( -0.246 , 0 , -6.764)
print '\n','-'*20,'check'
print 'Dark    (vector):',vectorTest_Dark(v1,v2,v3)
print '4i4ikov (scalar):',vectorTest_4i4ikov(v1,v2,v3)

Bench = new_Bench()
N = 100000
print '\n','-'*20,'bench',N

Bench.reset()
for i in xrange(1,N): vectorTest_Dark(v1/i,v2/i,v3/i)
print 'Dark    (vector):',Bench.get()

Bench.reset()
for i in xrange(1,N): vectorTest_4i4ikov(v1/i,v2/i,v3/i)
print '4i4ikov (scalar):',Bench.get()

Bench.reset()
for i in xrange(1,N): vectorTest_Dark(v1/i,v2/i,v3/i)
print 'Dark    (vector):',Bench.get()

Bench.reset()
for i in xrange(1,N): vectorTest_4i4ikov(v1/i,v2/i,v3/i)
print '4i4ikov (scalar):',Bench.get()
Код:
-------------------- check
Dark    (vector): (-0.0880312, -1.07038, -1.59508)
4i4ikov (scalar): (-0.0880312, -1.07038, -1.59508)

-------------------- bench 100000
Dark    (vector): 0.391000032425
4i4ikov (scalar): 0.766000032425
Dark    (vector): 0.390000104904
4i4ikov (scalar): 0.734000205994
Формулы оптимизировал.
Если v1 и v2 совпадут, то там и там будет ошибка деления на ноль.

API 2.0 просто няшка!
 
Последнее редактирование:

Andots

Знаток
Рейтинг
66
#18
Прикольно, честно говоря не думал что разница будет почти в 2 раза. Интересно было бы сравнить ноду на питонской Апи с абсолютно аналогичной скомпиленой на с++
 

4i4ikov

Знаток
Рейтинг
37
#19
Прикольно, честно говоря не думал что разница будет почти в 2 раза. Интересно было бы сравнить ноду на питонской Апи с абсолютно аналогичной скомпиленой на с++
Тоже не думал что такая сильная разница будет.

Мне вот интересно по железу, как на разных машинах будет.
Вот две машинки, на i7 и c2d.
До этого был замер на c2d E5700 @ 3750 MHz (maya 2013x32)

Вот замер на i7 2600k @ 4500 MHz (maya 2014x64):
Код:
-------------------- check
Dark    (vector): (-0.0880312, -1.07038, -1.59508)
4i4ikov (scalar): (-0.0880312, -1.07038, -1.59508)

-------------------- bench 100000
Dark    (vector): 0.254999876022
4i4ikov (scalar): 0.486999988556
Dark    (vector): 0.24599981308
4i4ikov (scalar): 0.487999916077
Быстрее ровно в 1.5 раза (между машинами).
Это одно ядро считает, ну и разрядность разная.
Но всё равно не сильно быстрее.

А по рендеру одна быстрее другой в 4.4 раза (все ядра работают).
 

Andots

Знаток
Рейтинг
66
#20
Не повезло, у меня тоже 2600к. Стоит правда без буста (чтоб ноги просто так не грел :) )

3.4 гц
-------------------- bench 100000
Dark (vector): 0.375
4i4ikov (scalar): 0.707000017166
Dark (vector): 0.358999967575
4i4ikov (scalar): 0.68799996376
 
Сверху