2011-10-16 20 views
19

Profesörün atadığı bir problem üzerinde çalışıyorum ve 3 nokta arasındaki açının 180 dereceden fazla olup olmadığını saptamanın bir yolunu arıyorum, örneğin:Açı 180 dereceden fazla olup olmadığını belirleme

, alfa 180 dereceden fazla olup olmadığını algılamak istiyoruz. Her neyse, profesörüm sorunu çözen bir kod var, ama zcross adlı bir işlevi var, ama nasıl çalıştığını tam olarak bilmiyorum. Birisi bana söyleyebilir mi? Onun kod burada:

#include <fstream.h> 
#include <math.h> 
#include <stdlib.h> 

struct point { 
    double x; 
    double y; 
    double angle; 
}; 

struct vector { 
    double i; 
    double j; 
}; 

point P[10000]; 
int  hull[10000]; 

int 
zcross (vector * u, vector * v) 
{ 
    double p = u->i * v->j - v->i * u->j; 
    if (p > 0) 
    return 1; 
    if (p < 0) 
    return -1; 
    return 0; 
} 

int 
cmpP (const void *a, const void *b) 
{ 
    if (((point *) a)->angle < ((point *) b)->angle) 
    return -1; 
    if (((point *) a)->angle > ((point *) b)->angle) 
    return 1; 
    return 0; 
} 

void 
main() 
{ 
    int  N, i, hullstart, hullend, a, b; 
    double midx, midy, length; 
    vector v1, v2; 

    ifstream fin ("fc.in"); 
    fin >> N; 
    midx = 0, midy = 0; 
    for (i = 0; i < N; i++) { 
     fin >> P[i].x >> P[i].y; 
     midx += P[i].x; 
     midy += P[i].y; 
    } 
    fin.close(); 
    midx = (double) midx/N; 
    midy = (double) midy/N; 
    for (i = 0; i < N; i++) 
     P[i].angle = atan2 (P[i].y - midy, P[i].x - midx); 
    qsort (P, N, sizeof (P[0]), cmpP); 

    hull[0] = 0; 
    hull[1] = 1; 
    hullend = 2; 
    for (i = 2; i < N - 1; i++) { 
     while (hullend > 1) { 
      v1.i = P[hull[hullend - 2]].x - P[hull[hullend - 1]].x; 
      v1.j = P[hull[hullend - 2]].y - P[hull[hullend - 1]].y; 
      v2.i = P[i].x - P[hull[hullend - 1]].x; 
      v2.j = P[i].y - P[hull[hullend - 1]].y; 
      if (zcross (&v1, &v2) < 0) 
       break; 
      hullend--; 
     } 
     hull[hullend] = i; 
     hullend++; 
    } 

    while (hullend > 1) { 
     v1.i = P[hull[hullend - 2]].x - P[hull[hullend - 1]].x; 
     v1.j = P[hull[hullend - 2]].y - P[hull[hullend - 1]].y; 
     v2.i = P[i].x - P[hull[hullend - 1]].x; 
     v2.j = P[i].y - P[hull[hullend - 1]].y; 
     if (zcross (&v1, &v2) < 0) 
      break; 
     hullend--; 
    } 
    hull[hullend] = i; 

    hullstart = 0; 
    while (true) { 
     v1.i = P[hull[hullend - 1]].x - P[hull[hullend]].x; 
     v1.j = P[hull[hullend - 1]].y - P[hull[hullend]].y; 
     v2.i = P[hull[hullstart]].x - P[hull[hullend]].x; 
     v2.j = P[hull[hullstart]].y - P[hull[hullend]].y; 
     if (hullend - hullstart > 1 && zcross (&v1, &v2) >= 0) { 
      hullend--; 
      continue; 
     } 
     v1.i = P[hull[hullend]].x - P[hull[hullstart]].x; 
     v1.j = P[hull[hullend]].y - P[hull[hullstart]].y; 
     v2.i = P[hull[hullstart + 1]].x - P[hull[hullstart]].x; 
     v2.j = P[hull[hullstart + 1]].y - P[hull[hullstart]].y; 
     if (hullend - hullstart > 1 && zcross (&v1, &v2) >= 0) { 
      hullstart++; 
      continue; 
     } 
     break; 
    } 

    length = 0; 
    for (i = hullstart; i <= hullend; i++) { 
     a = hull[i]; 
     if (i == hullend) 
      b = hull[hullstart]; 
     else 
      b = hull[i + 1]; 
     length += sqrt ((P[a].x - P[b].x) * (P[a].x - P[b].x) + (P[a].y - P[b].y) * (P[a].y - P[b].y)); 
    } 

    ofstream fout ("fc.out"); 
    fout.setf (ios: :fixed); 
    fout.precision (2); 
    fout << length << '\n'; 
    fout.close(); 
} 

cevap

36

İlk olarak, sin(a)'un negatif olması durumunda açının 180 dereceden fazla olduğunu biliyoruz.

sin(a) işaretini nasıl buluruz? Burada çapraz ürün devreye giriyor.

İlk olarak, iki vektör tanımlayalım:

v1 = p1-p2 
v2 = p3-p2 

Bu iki vektör p2 ve bir p1 kadardır ve p3 diğer noktalarda başlangıç ​​anlamına gelir.

Çapraz ürün olarak tanımlanır: En vektörler 2d olduğundan

(x1, y1, z1) x (x2, y2, z2) = (y1z2-y2z1, z1x2-z2x1, x1y2-x2y1) 

ardından z1 ve z2 0 ve dolayısıyla şunlardır:

(x1, y1, 0) x (x2, y2, 0) = (0, 0, x1y2-x2y1) 

onlar zcross çünkü diyoruz yüzden bu Ürünün sadece z elementinin 0'dan farklı bir değeri vardır. Diğer taraftan, w,

e biliyoruz:

||v|| vektör v norm (boyut)
||v1 x v2|| = ||v1|| * ||v2|| * abs(sin(a)) 

. Ayrıca, a açısının 180'den küçük olması durumunda, v1 x v2'un yukarı doğru (sağdaki yön) gösterileceğini biliyoruz, 180'den büyükse aşağıya doğru işaret edecektir. özel durumlarda Yani:

(v1 x v2).z = ||v1|| * ||v2|| * sin(a) 

Basitçe söylemek gerekirse v1 x v2 z değeri pozitif ise, o zaman a o negatif ise, o zaman (z değeri x1y2-x2y1 idi) büyük olan 180 daha küçüktür. Eğer çapraz ürün 0 ise, bu iki vektör paraleldir ve açı iki vektörün sırasıyla aynı mı yoksa ters yönde mi olduğuna bağlı olarak 0 veya 180'dir.

+0

teşekkür içine bakacağız. güzel ve bilgilendirici bir cevap. –

+2

2B'de, gerçekten yaptığınız şey, çapraz ürüne göre daha genel bir kavram olan ve herhangi bir sayıda boyutta çalışan "dış ürün" i hesaplamaktır. Bunu, utanç verici olan, lineer cebir sınıflarında öğretmiyorlar. (Formül çoğunlukla aynıdır, sadece "z" koordinatlarından bahsetmeden, daha basittir.) –

+0

Güzel cevap. Tam olarak aradığım şey buydu. –

3

zcross açısı daha fazla veya en az 180 derece olup olmadığını koyduk olarak belirlemek için vector cross product (z yönünde artı veya eksi) işareti kullanıyor.

+0

Hmm, şimdi –

0

aşağıdaki gibi olur yapmanın bir başka yolu:

hesaplamak vektör V1 = P2-P1, v2 = p2 -P3. Sonra çapraz ürün formülünü kullanın: u.v = || u || || V || cos (theta)

+0

Açıları> 180 ° nasıl tutuyorsunuz? – Vertexwahn

+0

İşaret, 180 dereceden fazla olup olmadığını söyler, değil mi? –

1

3B'de vektörlerin çapraz çarpımını bulun, temel olarak en az x, y ve z sayısını bulmak için çapraz ürün için minimum uzunluğu bulun.

En küçük değer 0'dan küçükse, vektörlerin açısı negatiftir. kodunda Yani

:

float Vector3::Angle(const Vector3 &v) const 
{ 
    float a = SquareLength(); 
    float b = v.SquareLength(); 
    if (a > 0.0f && b > 0.0f) 
    { 
     float sign = (CrossProduct(v)).MinLength(); 
     if (sign < 0.0f) 
      return -acos(DotProduct(v)/sqrtf(a * b)); 
     else 
      return acos(DotProduct(v)/sqrtf(a * b)); 
    } 
    return 0.0f; 
} 
+0

Sanırım önemli olan, fonksiyonun [-180 °; 180 °] - [0; 360 °] arasındaki bir açı değil - bir açı döndürdüğü - mükemmel çalışıyor! – Vertexwahn

İlgili konular