A sugárkövetés megvalósításához szükségem van egy 3d-s helyvektort megvalósító osztályra, annak minden műveletével. A c_vector3d egy érték típusú osztály. Ezért van neki nyílvános konstruktora, másoló konstruktora, destruktora, viszont nincs virtuális függvénye és nem használom alaposztálynak semmihez. Egyetlen private tagja van ami point (részletesebben global_math-ban van kifejtve) típusú. Ez tartalmazza a vektor végpontjának koordinátáit. Kezdőpontja - lévén helyvektor - minden esetben a 0,0,0.
A másoló konstruktorral kicsit tanácstalannak érzem magam. Bjarne Stroustrup szerint, ha az alapértelmezett működés megfelelő nem szükséges létrehozni, hiszen a kódot olvasóról joggal feltételezhetjük, hogy ismeri azt. Jelen esetben nem tartalmaz mutatót c_vector3d ezért az alap működés megfelelő. Viszont Andrei Alexandrescu, Herb Sutter C++ kódolási szabályok könyve szerint meg kell valósítani. Ha figyelembe veszem Occam borotváját („általában az egyszerűbb megoldás a helyes”) akkor nem írom meg. Én mégis megtettem. Úgy gondolom jobb az ilyesminek szem előtt lennie.
Legyen egyenlő operátort is túlterheltem a szokásos módon. Megvizsgálja nem-e saját magával szeretném egyenlővé tenni. Ha nem, akkor az értéket átmásolja.
Az aritmetikai operátorokat Stroustrup ajánlása szerint készítettem el. Általános elv, hogy egy osztálynak csak az legyen tagfüggvénye aminek feltétlenül annak kell lennie. Másképpen megfogalmazva ha egy függvénynek nem szükséges elérni az osztály privát tagját, akkor felesleges taggá tenni. Itt a +=, -=, *=, %= operátorok tagfüggvények és ezek értékadás nélküli megfelelőjük az előbbiek segítségével osztályon kívüliként valósulnak meg. %= operátor a vektorális (kereszt) szorzást jelenti. A *= operátor a lambda számmal (vagyis skalárral) való szorzást jelenti.
A double operator*(c_vector3d) a skaláris szorzást valósítja meg. Jól látszik a végeredménye skalár (double) típusú. Ezért nem lehet itt a *= operátort használni.
Megvalósítom az egynelő és nem egyenlő operátorokat is. Két vektor akkor egyenlő, ha hosszuk és irányuk megegyezik. Mivel jelen esetben helyvektorokról van szó, elegendő a csúcspontjuk koordinátáit megvizsgálni.
A stream operátorokat is túlterhelem. Ehhez nagy segítségemre vannak a point struktúránál megírt túlterhelések.
Vektor osztályomnak még két fontos tagfüggvénye van. Az egyik a vektor abszulút értékét számolja ki, a másik normalizálja azt. Illetve van egy nem tagfüggvénye ami két vektor közötti hajlásszöget számolja ki.
// vector3d.h
class c_vector3d { public: c_vector3d(double, double, double); // construct c_vector3d(point V = point(0,0,0)); // construct c_vector3d(const c_vector3d& v3d); // copy construct ~c_vector3d(); // destruct c_vector3d& operator=(const c_vector3d& v3d); // assignment c_vector3d& operator+=(c_vector3d); // addition assignment c_vector3d& operator-=(c_vector3d); // subtraction assignment c_vector3d& operator*=(double); // lambda multiplication assignment c_vector3d& operator%=(c_vector3d); // cross product assignment double operator*(c_vector3d); // scalar multiplication bool operator==(c_vector3d&); // equal to bool operator!=(c_vector3d&); // not equal to friend std::ostream& operator<<(std::ostream& out, c_vector3d v3d); friend std::istream& operator>>(std::istream& is, c_vector3d &v3d); double abs() const; friend c_vector3d normalize(const c_vector3d); private: point v; }; //--------------------------------------------------------- c_vector3d operator+(c_vector3d, c_vector3d); c_vector3d operator-(c_vector3d, c_vector3d); c_vector3d operator*(c_vector3d, double); c_vector3d operator*(double, c_vector3d); c_vector3d operator%(c_vector3d, c_vector3d); //--------------------------------------------------------- double tiltangle(c_vector3d v1, c_vector3d v2);
// vector3d.cpp
// vector3d.cpp c_vector3d::c_vector3d(double x, double y, double z) // construct { v = point(x,y,z); } c_vector3d::c_vector3d(point V) // construct { v = V; } c_vector3d::c_vector3d(const c_vector3d& v3d) // copy construct { v = v3d.v; } c_vector3d::~c_vector3d() // destruct { } c_vector3d& c_vector3d::operator=(const c_vector3d& v3d) // assignment { if (this != &v3d) { v = v3d.v; } return *this; } //--------------------------------------------------------- c_vector3d& c_vector3d::operator+=(c_vector3d v3d) // addition assignment { v.x += v3d.v.x; v.y += v3d.v.y; v.z += v3d.v.z; return *this; } c_vector3d& c_vector3d::operator-=(c_vector3d v3d) // subtraction assignment { v.x -= v3d.v.x; v.y -= v3d.v.y; v.z -= v3d.v.z; return *this; } c_vector3d& c_vector3d::operator*=(double lambda) { // lambda multiplication assignment v.x *= lambda; v.y *= lambda; v.z *= lambda; return *this; } c_vector3d& c_vector3d::operator%=(c_vector3d v3d) // cross product assignment { c_vector3d out; out.v.x = v.y*v3d.v.z - v.z*v3d.v.y; out.v.y = v.x*v3d.v.x - v.z*v3d.v.x; out.v.z = v.x*v3d.v.y - v.y*v3d.v.x; *this = out; return *this; } double c_vector3d::operator*(c_vector3d v3d) // scalar multiplication { return v.x*v3d.v.x + v.y*v3d.v.y + v.z*v3d.v.z; } //--------------------------------------------------------- bool c_vector3d::operator==(c_vector3d& v3d) // equal to { return ( (v.x == v3d.v.x) && (v.y == v3d.v.y) && (v.z == v3d.v.z) ); } bool c_vector3d::operator!=(c_vector3d& v3d) // not equal to { return !( (v.x == v3d.v.x) && (v.y == v3d.v.y) && (v.z == v3d.v.z) ); } //--------------------------------------------------------- //--------------------------------------------------------- std::ostream& operator<<(std::ostream& out, c_vector3d v3d) { out << v3d.v; return out; } std::istream& operator>>(std::istream& is, c_vector3d& v3d) { point p = (0,0,0); is >> p; if (is) v3d.v = p; return is; } //--------------------------------------------------------- //--------------------------------------------------------- double c_vector3d::abs() const { return sqrt(v.x*v.x + v.y*v.y + v.z*v.z); } c_vector3d normalize(const c_vector3d v3d) { double a = v3d.abs(); double x = v3d.v.x / a; double y = v3d.v.y / a; double z = v3d.v.z / a; return c_vector3d(x,y,z); } //--------------------------------------------------------- c_vector3d operator+(c_vector3d v1, c_vector3d v2) { c_vector3d out = v1; return out += v2; } c_vector3d operator-(c_vector3d v1, c_vector3d v2) { c_vector3d out = v1; return out -= v2; } c_vector3d operator*(c_vector3d v1, double lambda) { return v1 *= lambda; } c_vector3d operator*(double lambda, c_vector3d v1) { return v1 *= lambda; } c_vector3d operator%(c_vector3d v1, c_vector3d v2) { c_vector3d out = v1; return v1 %= v2; } //--------------------------------------------------------- double tiltangle(c_vector3d v1, c_vector3d v2) { return double( acos((v1 * v2) / (v1.abs() * v2.abs() )) ); }