İki vektör arasında açı elde etmek için nokta ürününü nasıl kullanırım?


16

Oyunlarımda normalize edilmiş vektörleri kullanmayı öğreniyorum.

İki vektör arasındaki açıyı bilmek için nokta ürünü kullanabileceğimi öğrendim. Bu bana -1 ile 1 arasında bir değer verir, burada

  • Şekil 1, vektörlerin paralel ve aynı yöne baktığı anlamına gelir (açı 180 derecedir).
  • -1, paralel olduklarını ve ters yönlere (hala 180 derece) bakacakları anlamına gelir.
  • 0 aralarındaki açının 90 derece olduğu anlamına gelir.

İki vektörün nokta ürününün derece cinsinden gerçek bir açıya nasıl dönüştürüleceğini bilmek istiyorum. Örneğin, iki vektörün nokta çarpımı 0.280 ve 360 ​​derece arasındaki karşılık gelen açı nedir?


1
Nokta ürünü kullanım amacınız yalnızca ilk vektörler birim vektörler olduğunda işe yarar.
sam hocevar

@SamHocevar Evet, demek istediğim buydu.
user3150201


1
@ user3150201 Alex'in yanıtı doğru, ancak gerçek açıyı derece olarak almanız gerekip gerekmediğini de düşünmelisiniz. Bunun gerçekten gerekli olduğunu düşünebildiğim tek durum, kullanıcı arayüzünde derece olarak bir şey göstermek olacaktır. Aksi takdirde, doğrudan sinüsler ve kosinüslerle çalışamayacağınız birkaç uygulama olabilir.
TravisG

Yanıtlar:


22

dot(A,B) = |A| * |B| * cos(angle)
yeniden düzenlenebilir
angle = arccos(dot(A,B) / (|A|* |B|)).

Bu formülle, iki vektör arasındaki 0 ​​ile 180 derece arasında en küçük açıyı bulabilirsiniz. Eğer 0 ile 360 ​​derece arasında ihtiyacınız varsa bu soru size yardımcı olabilir.


Bu arada, aynı yönü gösteren iki paralel vektör arasındaki açı 180 değil, 0 derece olmalıdır.


+1 "Bu arada, aynı yönü gösteren iki paralel vektör arasındaki açı 180 değil, 0 derece olmalıdır."
Tara

8

TravisG'nin yorumunda biraz genişleyeceğim ve sorunuzun "2D" etiketine sahip olduğu gerçeğinden yararlanarak başka bir cevap vereceğim.

Nokta ürününü kullanarak iki vektör arasındaki açıyı elde edebilirsiniz, ancak iki vektör arasındaki işaretli açıyı kullanarak elde edemezsiniz . Başka bir deyişle, zaman içinde bir karakteri bir noktaya çevirmek istiyorsanız, nokta ürün size ne kadar döneceğinizi, ancak hangi yöne dönmeyeceğinizi söyleyecektir. Bununla birlikte, nokta ürünle birleştirildiğinde çok yararlı olan başka bir basit formül vardır. Sadece sahip değil

dot(A,B) = |A| * |B| * cos(angle)

Başka bir formülünüz de olabilir (adını politik doğruluk için oluşturduğum):

pseudoCross(A,B) = |A| * |B| * sin(angle)

burada A = (a, b), B = (x, y) ise pseudoCross (A, B), çapraz ürünün (a, b, 0) x (x, y, 0) üçüncü bileşeni olarak tanımlanır ). Diğer bir deyişle:

a*x+b*y = |A| * |B| * cos(angle)

-b*x+a*y = |A| * |B| * sin(angle)

Ardından tam işaretli açı angle=atanfull(-b*x+a*y,a*x+b*y)(normalflaştırılmamış değerlerden geçerseniz atanfull veya atan2 işlevleri sizi affeder). A ve B normalleştirilirse, yani |A|=|B|=1bunlar basitçe:

a*x+b*y = cos(angle)

-b*x+a*y = sin(angle)


Daha derin bir açıklama için yukarıdaki denklemlerin matris denklemi ile ifade edilebileceğini unutmayın:

[ a,b]   [x]   [cos(angle)]
[-b,a] * [y] = [sin(angle)]

Ancak a ve b olarak ifade edilebilir a=cos(ang1), b=sin(ang1)bazı değeri ang1(değil angle). Bu nedenle, soldaki matris, vektörü (x, y) -ang1 miktarı ile döndüren bir döndürme matrisidir. Bu, birim vektörü (A) vektör / eksen (1,0) olarak değerlendirildiği bir referans çerçevesine geçişle eşdeğerdir! Böylece, sadece bu çerçevede birim daire / sağ üçgeni çizerek, o ürünün ortaya çıkan vektörün neden (cos (açı), günah (açı)) olduğunu görebilirsiniz.

Kutup biçiminde (a, b) ve (x, y) yazarsanız cos(l)*cos(m)+sin(l)*sin(m)=cos(l-m)ve açı farkı formüllerini uygularsanız, sin(l)*cos(m)-cos(l)*sin(m)=sin(l-m)(lm) = açı olduğundan sinüslerin / kosinüslerin bu ürün tarafından verildiğini tekrar ifade edersiniz. Alternatif olarak, bu kimlikler yukarıda verilen doğrusal ürünün neden bir vektörü döndürdüğünü görmek için kullanılabilir.

Tüm bu kimlikler nadiren açılara ihtiyacınız olduğu anlamına gelir. Açılar garip olabilir - radyan / derece, ters sinüs / kosinüs için kurallar, her 2 * pi tekrarladıkları gerçeği - bu aslında daha yararlı olabilir ve bir sürü "if (ang <180)" vb mantıktan kurtarabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.