HTML

Despina

Sugárkövetés (raytracing) megvalósítása c++ nyelvben.

Friss topikok

  • tormanator: Az internet nagy hátránya, hogy még szabadidődben is beleszólnak abba, amit csinálsz. float oké, ... (2011.09.03. 19:26) 3D-s vektor osztály
  • tormanator: Látványosan elakadtál, akkor majd én folytatom. sugarkovetes.blog.hu/ (2011.09.03. 14:34) Metszéspontszámítás 1
  • sirpalee: Ne írj saját bmp mentőt. 1. OIIO - win alá macerás fordítani de megéri 2. devIL - egyszerű, fapad... (2010.12.08. 17:31) bmp fájlba mentés

Linkblog

3D-s vektor osztály

2010.12.02. 21:18 despina

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() )) );
}

3 komment

A bejegyzés trackback címe:

https://despina.blog.hu/api/trackback/id/tr502489284

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

sirpalee 2010.12.08. 17:29:48

Jaj.

1. inline.
2. float, a te eseteid nagy részében nem kell a double pontossága.
3. ha már vektor osztály írsz akkor az legyen már template -.-"
4. ha írsz operátorokat, akkor ne a matematikai operátoroknak megfelelően írd meg őket, hanem a float számoknak megfelelően. ez a programozási szabvány. ergo a dot-ra csináljsz függvényt.
5. egyenlővétevésnél felesleges egyenlőséget vizsgálni, csak ott van egy if, ami az esetek 100%-ban nem csinál semmit sem (ki az a hülye aki saját magával tesz egyenlővé bármit is?)
6. a == és a != is const...
7. NE legyen privát a point, ez primitív class itt simán belenyúlhatsz, nem kell fv-kel szarakodni.

Így első pillantásra...

sirpalee 2010.12.08. 19:36:47

Még apróság, amit nekem mondott ismerős, miután áttárgyaltuk az = operátornál érdemes-e uarra csekkolni témát (végeredményben, debugban esetleg...)

Sok helyen lehagyod a referenciát (ajánlott a const= használata), és azt a fordító nem optimalizálja ki... Tehát másolás, és konstruktor hívás történik, nem pedig közvetlen eléred az adatot.

tormanator · http://sugarkovetes.blog.hu/ 2011.09.03. 19:26:29

Az internet nagy hátránya, hogy még szabadidődben is beleszólnak abba, amit csinálsz.

float oké, de a többit úgy irod, ahogy akarod.
A template felesleges, a "programozási szabvány" fogalomra meg inkább nem írok semmit.
süti beállítások módosítása