//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "obraz.h"
#include "math.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)

//---------------------------------------------------------------------------
//  Konstruktor podstawowy
TTrojkat :: TTrojkat( TPunkt Ap1, TPunkt Ap2, TPunkt Ap3)
{
 p1 = Ap1;
 p2 = Ap2;
 p3 = Ap3;
}
//---------------------------------------------------------------------------
//  Konstruktor kopiujący
TTrojkat :: TTrojkat( const TTrojkat &t)
{
 p1 = t.p1;
 p2 = t.p2;
 p3 = t.p3;
}
//---------------------------------------------------------------------------
//  Operator przypisania
TTrojkat & TTrojkat :: operator= (const TTrojkat &t)
{
 if( this != &t)
 {
    p1 = t.p1;
    p2 = t.p2;
    p3 = t.p3;
 }
 return *this;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//  Konstruktor podstawowy. Promien z punktu Ar0, skierowany w Akierunek
TPromien :: TPromien( TPunkt Ar0, TWektor Akierunek)
{
 r0 = Ar0;
 kierunek = Akierunek;
}
//---------------------------------------------------------------------------
//  Inny konstruktor. Promien skierowany od a do b.
TPromien :: TPromien( TPunkt Aa, TPunkt Ab)
{
 r0 = Aa;
 kierunek = TWektor( Ab.x - Aa.x, Ab.y - Aa.y, Ab.z - Aa.z);
 kierunek.unormuj();
}
//---------------------------------------------------------------------------
//  Konstruktor kopiujący
TPromien :: TPromien( const TPromien &p)
{
 r0 = p.r0;
 kierunek = p.kierunek;
}
//---------------------------------------------------------------------------
//  Operator przypisania
TPromien & TPromien :: operator= (const TPromien &p)
{
 if( this != &p)
 {
    r0 = p.r0;
    kierunek = p.kierunek;
 }
 return *this;
}
//---------------------------------------------------------------------------
//  Wyznaczenie punktu przecięcia promienia z płaszczyzną trójkąta.
//  Za chwilę wyznaczymy, czy punkt ten leży wewnątrz trójkąta,
//  tzn, czy promień trafia w trójkąt.
//  Parametry referencyjne są wypełniane, o ile przecięcie istnieje.
bool TPromien :: czy_trafia_w_plaszczyzne( TTrojkat t, TPunkt &p)
{
 TWektor v1( t.p1, t.p2), v2( t.p1, t.p3);  //wektory rozpinające trójkąt

 TWektor N = iloczyn_wektorowy( v1, v2);
 N.unormuj();                   //unormowany wektor prostopadły do płaszczyzny trójkąta

 double D = -(N.x*t.p1.x + N.y*t.p1.y + N.z*t.p1.z);//współczynnik D r-nia płaszczyzny Ax+By+Cz+D=0
 double a = N.x*kierunek.x + N.y*kierunek.y + N.z*kierunek.z;  //pomocnicze
 if( a == 0)
    return false;                                   //promień równoległy do płaszczyzny trójkąta
                                                    //poniższe wynika z podstawienia równania
                                                    //promienia do równania płaszczyzny
 double b = (-D - iloczyn_skalarny( N, TWektor( TPunkt(), r0))) / a;
 if( b < 0)
    return false;                                   //trójkąt leży z niewłaściwiej strony ekranu

 p.x = r0.x + kierunek.x * b;
 p.y = r0.y + kierunek.y * b;
 p.z = r0.z + kierunek.z * b;
 return true;
}
//---------------------------------------------------------------------------
//  Szukanie przecięcia promienia z trójkątem zabudowy sceny.
//  Parametry referencyjne są wypełniane, o ile przecięcie istnieje.
bool TPromien :: czy_trafia_w_trojkat( TTrojkat t, TPunkt &trafienie, TPromien &odbicie)
{
 return czy_trafia_w_plaszczyzne( t, trafienie);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//  Konstruktor merytoryczny. Uruchamia konstruktora klasy bazowej
//  obs - pozycja obserwatora,
//  eszer, ewys - rozmiary pikselowe pola obrazowego,
//  odl_ekr - odległość pola obrazowego [m],
//  szer, wys - rozmiar pola obrazowego [m].
TObraz :: TObraz( TPunkt Aobs, int eszer, int ewys,
            double Aodl_ekr, double szer, double wys) :
            TSkalowanie( 0, 0, eszer, ewys, 0, 0, szer, wys)
{
 obs = Aobs;
 Rxy = sqrt( obs.x * obs.x + obs.y * obs.y);
 R = sqrt( Rxy * Rxy + obs.z * obs.z);
 odl_ekr = Aodl_ekr;
 if( Rxy != 0)
    sf = obs.y / Rxy, cf = obs.x / Rxy;    //współczynniki macierzy obrotu
 else
    sf = 0, cf = 1;

 st = Rxy / R, ct = obs.z / R;
}
//---------------------------------------------------------------------------
//  Prywatna f. pomocnicza, konstruująca promien wychodzący
//  od obserwatora i biegnący przez piksel (i, j) płaszczyzny obrazowej.
TPromien TObraz :: daj_promien( int i, int j)
{
 double eh, ev;                 //metryczne współrzędne piksela (i, j) w płaszczyźnie ekranu
 TPunkt e;                      //metryczne współrzędne piksela w przestrzeni 3d

 eh = daj_real_x( i);           //funkcje odziedziczone z klasy bazowej
 ev = daj_real_y( j);

 TPunkt z( -ev, eh, R-odl_ekr); //gdy ekran jest w zenicie, piksel ma takie współrzędne

 e.x = cf * ct * z.x - sf * z.y + cf * st * z.z;
 e.y = sf * ct * z.x + cf * z.y + sf * st * z.z;
 e.z = -st * z.x + ct * z.z;

 return TPromien( obs, e);
}
//---------------------------------------------------------------------------
// Raczej niepotrzebne. Do testowania.
TPunkt TObraz :: daj_punkt( int i, int j)
{
 double eh, ev;                 //metryczne współrzędne piksela (i, j) w płaszczyźnie ekranu
 TPunkt e;                      //metryczne współrzędne piksela w przestrzeni 3d

 eh = daj_real_x( i);           //funkcje odziedziczone z klasy bazowej
 ev = daj_real_y( j);

 TPunkt z( -ev, eh, R-odl_ekr); //gdy ekran jest w zenicie, piksel ma takie współrzędne

 e.x = cf * ct * z.x - sf * z.y + cf * st * z.z;
 e.y = sf * ct * z.x + cf * z.y + sf * st * z.z;
 e.z = -st * z.x + ct * z.z;

 return e;
}
//---------------------------------------------------------------------------
//  Główna funkcja algorytmu
TColor TObraz :: kolor_piksela( int i, int j)
{
 TColor k = clBlack;
 TPromien p = daj_promien( i, j);
 return k;
}
