Analitička geometrija i C# programiranje dio 6/n


Problem 6: Ugao između prave i ravni.

Pretpostavimo da imamo pravu p na kojoj poznajemo koordinate tačaka A i B. Također pretpostavimo da imamo ravan Π koja je definisana tačkom na ravni R i vektorom normale V. Potrebno je izračunati ugao alpha  kojeg obrazuje prava i ravan.

angprogr_slproblem6

Rješenje: Rješenje zadatka svodi se na izračunavanje ugla između vekktora prave p i njene projektcije na ravan Π p'. Kako već imamo vektor prave p, još je samo potrebno da se odredi vektor prave p’ koja predstavlja projekciju prave na ravan. S druge strane znamo da je vektor normale okomut na vektor smijera projektovane prave, pa je traženi ugao komplement ugla koji zatvara parava i vektor normale. Na osnovu ovog imamo:

cos (90- \alpha) = \frac {|p \cdot V|}{\left | p \right |\left | V \right |}

Implementacija u C# izgleda kao na sljedećem listingu:

static void Main(string[] args)
{
    //Zadatak 1: data je ravan 2x-y+z-6=0 i prava (x)/-1 = (y-1)/-1 ) (z-6)/1
    //ulazni podaci za zadatak 1.
    Point B  = new Point(2f,  4f,  0f);      //tacka na pravoj
    Point A  = new Point(0f,  1f, -1f);   //tačka na pravoj
    Point R  = new Point(0f,  0f,  6f);     //tacka na ravni
    Point Vn = new Point(2f, -1f,  1f);   //vektor normalne ravni

    //izracunavanje ugla
    //Vektor pravca kojeg obrazuju tacke A i B
    Point zraka = Point.Vector(A,B);
    //
    var vec = Point.CrossProduct(zraka, Vn);
    float scos_alpha = (float)(Point.Modul(vec) / (Point.Modul(Vn) * Point.Modul(zraka)));
    Console.WriteLine("Cosinus ugla alpha iznosi={0}", scos_alpha);
    Console.Read();
}

Klasa Point je implementirana u prethodnom postu.

Advertisement

Analitička geometrija i C# programiranje dio 5/n


Problem 6: Presjek prave i ravni.

Pretpostavimo da imamo pravu p na kojoj poznajemo koordinate tačaka A i B. Također pretpostavimo da imamo ravan Π koja je definisana tačkom na ravni R i vektorom normale V. Potrebno je izračunati koordinate tačke A’ odnosno probodišta.

angprogr_slproblem5

Rješenje:

Za rješenje ovog problem potrebno je da znamo parametarski oblik jednačine prave, odnosno jednačinu ravi. Pored toga potrebno je da znamo vektorski odnosno skalarni proizvod dva vektora.

Ukoliko imamo dvije tačke A i B, jednačina prave kroz dvije tačke data je kao:

\frac{x-X_A}{X_B-X_A}=\frac{y-Y_A}{Y_B-Y_A}=\frac{z-Z_A}{Z_B-Z_A},

gdje je (X_A,Y_A,Z_A) koordinate tačke A, a (X_B,Y_B,Z_B) koordinate tačke B.

Opći oblik jednačine ravni koja je definisana jednom tačkom i vektorom normale data je u obliku:

A(x-X_R)+B(y-Y_R)+C(z-Z_R)=0 ,

gdje je (A,B,C) predstavlja koordinate vektora normale, a R(X_R,Y_R, Z_R) koordinate tačke R koja pripada toj ravni.

Postupak rješavanje probojne tačke je slijedeći:

 

1. Formirajmo parametarski oblike jednačine prave p, gdje t predstavlja parametar.

p(t)=A+t(B-A), ………(1)

2. Uvrštavajući gornju jednačinu prave u jednačinu ravni imamo:

V x (A'-V)=0. ………(2).

Zamjenom 1 u 2 možemo izračunati parametar t:

t= V x (V-A)/(N x (B-A)) .

Kada imamo vrijednost parametra t, sada je moguće izračunati koordinate tražene tačke A’.

C#  implementacija problema 6 izgleda na slijedeći način.

Implementacije klase Point koja implementira tačku u 3D prostoru preko koordinata x,z,y, te skupa metoda za skalarni, vektorski proizvod, kao i modul vektora.

class Point
{
    public float x;
    public float y;
    public float z;
    public Point() { }
    public Point(float xx, float yy, float zz)
    {
        x = xx;
        y = yy;
        z = zz;
    }

    /// <summary>
    /// Izracunavanje vektorskog proizvoda dva vektora
    /// </summary>
    /// <param name="vectorA"></param>
    /// <param name="vectorB"></param>
    /// <returns>vektorski proizvod</returns>
    public static Point CrossProduct(Point vectorA, Point vectorB)
    {
//                | i  j  k  |
//                | x1 y1 z1 |=i*(y1*z2-z1*y2)-j*(x1*z2-z1*x2)+k*(x1*y2-y1*x2)
//                | x2 y2 z2 |

        return new Point()
        {
            x = vectorA.y * vectorB.z - vectorA.z * vectorB.y,
            y = -vectorA.x * vectorB.z + vectorA.z * vectorB.x,
            z = vectorA.x * vectorB.y - vectorA.y * vectorB.x
        };
    }

    /// <summary>
    /// Izracunavanje skalarnog proizvoda dva vektora
    /// </summary>
    /// <param name="vectorA"></param>
    /// <param name="vectorB"></param>
    /// <returns></returns>
    public static float ScalarProduct(Point vectorA, Point vectorB)
    {
//      proizvod=x1*x2+y1*y2+z1*z2
        float retVal = vectorA.x * vectorB.x + vectorA.y * vectorB.y + vectorA.z * vectorB.z;
        return retVal;
    }
    /// <summary>
    /// Odredjivanje vektora kroz dvije tacke
    /// </summary>
    /// <param name="A"></param>
    /// <param name="B"></param>
    /// <returns></returns>
    public static Point Vector(Point A, Point B)
    {
        //referentni vektor ili pravac kroz referentne tačke na pravoj
        Point vektor = new Point();
        vektor.x = B.x - A.x;
        vektor.y = B.y - A.y;
        vektor.z = B.z - A.z;

        return vektor;
    }

    /// <summary>
    /// Odredjivanje modula vektora
    /// </summary>
    /// <param name="A"></param>
    /// <returns></returns>
    public static float Modul(Point A)
    {
        return (float)Math.Sqrt(A.x*A.x+A.y*A.y);
    }
}

Kada imamo ovako implementiranu klasu onda je određivanje probojne tačke prave i ravni dato kao:

static void Main(string[] args)
{
    //Zadatak 1: data je ravan 2x-y+z-6=0 i prava (x)/-1 = (y-1)/-1 ) (z-6)/1
    //ulazni podaci za zadatak 1.
    Point B  = new Point(2f,  4f,  0f);      //tacka na pravoj
    Point A  = new Point(0f,  1f, -1f);   //tačka na pravoj
    Point R  = new Point(0f,  0f,  6f);     //tacka na ravni
    Point Vn = new Point(2f, -1f,  1f);   //vektor normalne ravni

    //Zadatak 2: data je ravan 2x-y+z-6=0 i prava (x-1)/-1 = (y+1)/-1 ) = (z-4)/1
    //ulazni podaci za zadatak 2.
    //Point B = new Point(0f, -2f, 5f);      //tacka na pravoj
    //Point A = new Point(1f, -1f, 4f);   //tačka na pravoj
    //Point R = new Point(0f, 0f, 6f);     //tacka na ravni
    //Point Vn = new Point(2f, -1f, 1f);   //vektor normalne ravni
           
    //Probojna tačka koju treba odrediti
    Point proboj = new Point();
          
    //Vektor pravca kojeg obrazuju tacke A i B
    Point zraka = Point.Vector(A,B);

    //ako je skalarni proizvod vektora prave i normale jednak nuli
    // tada prava ne sijece ravan
    float scalVal = Point.ScalarProduct(Vn,zraka);
    if(scalVal==0)
    {
        Console.WriteLine("Prava ne sijece ravan");
        Console.Read();
        return;
    }

    //skalarni proizvod tačke na ravni sa
    float D = Point.ScalarProduct(Vn,R);
    float AR = Point.ScalarProduct(A,Vn);
    float zrakaR = Point.ScalarProduct(zraka,Vn);
    //
    float t = (D - AR) / (zrakaR);

    //tacka probodistva
    proboj.x = A.x + zraka.x * t;
    proboj.y = A.y + zraka.y * t;
    proboj.z = A.z + zraka.z * t;

    Console.WriteLine("Tacka probodista je A'({0},{1},{2})",proboj.x,proboj.y,proboj.z);
    Console.Read();
}

Analitička geometrija i C# programiranje dio 4/n


Problem 5: Potrebno je pronaći najkraću udaljenost između tačke i prave.

shortestpointLine

Iz analitičke geometrije znamo da je najkraća udaljenost između prave i tačke ona udaljenost koja se poklapa sa pravom koja prolazi tačkom A i normalna je na pravu p.  U tom smislu pretpostavimo da normala povučena iz tačke A siječe pravu p u tački A’ . Posmatrajmo vektore \vec{P_{1}A} i \vec{P_{1}P_{2}'} .

Izračunavanjem vektorskog proizvoda ova dva vektora dobićemo površinu paralelograma razapetog na tim vektorima. Kako znamo da je površina paralelograma u našem slučaju: P=AA’ x P1P2, to lahko možemo izračunati dužinu stranice AA’. U stvari ona predstavlja visinu paralelograma.

Sada možemo pisati:

AA' = \frac{P1A x P1P2}{|P1A|}. Ovim smo izračunali najkraću udaljenost između tačke i prave. Implementacija u C# programskom jeziku moze izgledati na sljedeći način:

static float shortestDistance(Point A, Point P1, Point P2)
{
    //referentni vektor ili pravac kroz referentne tačke na pravoj
    Point vektor = new Point();
    vektor.x = P2.x - P1.x;
    vektor.y = P2.y - P1.y;

    //Pravimo vektor od referentne tacke 1 i date tacke a
    Point vektor2 = new Point();
    vektor2.x = P1.x - A.x;
    vektor2.y = P1.y - A.y;

    //Izračunavamo vektorski proizvod dva verktora
    float vecProd = vektor.y * vektor2.x - vektor.x * vektor2.y;
    //Izračunavamo modul vektora P1P2
    float mod1=(float)Math.Sqrt(vektor.x * vektor.x + vektor.y * vektor.y);

    //udaljenost d== vektorski proizvod/dizina vektora P1P2
    float dist = vecProd / mod1;

    return dist;
}

Analitička geometrija i C# programiranje dio 3/n


Problem 3 i 4: Pripadnost tačke kružnici ili pravilnom poligonu

 

tacka_u_kruznici tacka_u_poligonu

 

Implementacija problema pripadnosti tačke u kružnici je vrlo prosta i zahtjeva samo provjeru da li je dužina centra kružnice do posmatrane tačke manja ili jednaka radijusu kružnice. Implementacija se može napisati na sljedeci način:

/// <summary>
/// provjerava da i se tačka nalazi u kružnici
/// </summary>
/// <param name="a">koordinate tačke </param>
/// <param name="o1">koordinate centra kružnice</param>
/// <param name="radius">radijus kružnica</param>
/// <returns></returns>
bool isInCircle(Point a, Point o1, float radius)
{
    float length = (float)Math.Sqrt((a.x - o1.x) * (a.x - o1.x) + (a.y - o1.y) * (a.y - o1.y));

    if (radius >= length)
        return true;
    else
        return false;
}

Implementacija problema tačke u pravilnom poligonu je malo komplikovanija, a bazira se na činjenici da u koliko je tačka unutar poligona, tada tačka mora biti sa desne strane svih njegovih stranica, u koliko se stranica obilaze u smjeru kretanja kazaljke na satu. Implementacija izgleda kao na sljedećem listingu:

/// <summary>
/// vraća true ako se tačka A nalazi u poligonu
/// </summary>
/// <param name="a"></param>
/// <param name="o1">centar poligona</param>
/// <param name="polyedges">tačke tjemena poligona poredane u smjeru kretanja kazaljke na satu.</param>
/// <returns></returns>
bool isInPolygon(Point a, Point o1, Point[]polyedges)
{
    for (int i = 0; i < polyedges.Length; i++)
    {
        int j = i++;
        if (j == polyedges.Length)
            j = 0;
        if (isOnRightSide(a, polyedges[i], polyedges[j])==-1)
            return false;
    }
    return true;
}

Iz zadnjeg listinga vidimo da smo koristili metodu isOnRightSide iz prethodnog posta.