Frage

Ich bin derzeit ein einfaches Raytracer in C ++ Implementierung. Ich habe eine Klasse mit dem Namen Orthonormalbasis, das drei orthogonale Einheitsvektoren, die von einer oder zwei festgelegten Vektoren erzeugt, zum Beispiel:

void
OrthonormalBasis::init_from_u ( const Vector& u )
{
    Vector n(1,0,0);
    Vector m(0,1,0);
    u_ = unify(u);
    v_ = cross(u_,n);
    if ( v_.length() < ONB_EPSILON )
        v_ = cross(u_,m);
    w_ = cross(u_,v_);
}

Ich teste alle meine Methoden mit dem Unittest ++ Framework. Das Problem ist, dass es mehr als eine mögliche Lösung für eine gültige Orthonormalbasis ist. Zum Beispiel dieses Test:

TEST ( orthonormalbasis__should_init_from_u )
{
    Vector u(1,0,0);
    OrthonormalBasis onb;

    onb.init_from_u(u);

    CHECK_EQUAL( Vector( 1, 0, 0 ), onb.u() );
    CHECK_EQUAL( Vector( 0, 0, 1 ), onb.v() );
    CHECK_EQUAL( Vector( 0, 1, 0 ), onb.w() );
}

Manchmal gelingt es, manchmal ist es nicht, weil die Vektoren v und w auch eine negative 1 haben könnte und immer noch eine gültige Orthonormalbasis darstellen. Gibt es eine Möglichkeit, mehrere erwarteten Werte angeben? Oder kennen Sie einen anderen Weg, das zu tun?

Es ist wichtig, dass ich auf dem stdout gedruckt, die tatsächlichen und erwarteten Werte erhalten, um die Methoden zu debuggen so dass diese Lösung wird die Arbeit nicht tun:

TEST ( orthonormalbasis__should_init_from_u )
{
    Vector u(1,0,0);
    OrthonormalBasis onb;

    onb.init_from_u(u);

    CHECK_EQUAL( Vector( 1, 0, 0 ), onb.u() );
    CHECK(
        Vector( 0, 0, 1 ) == onb.v() ||
        Vector( 0, 0,-1 ) == onb.v() );
    CHECK(
        Vector( 0, 1, 0 ) == onb.w() ||
        Vector( 0,-1, 0 ) == onb.w() );
}
War es hilfreich?

Lösung

Sicher, wenn alles, was Sie testen, ob Ihre Basis orthonormal ist, dann ist das, was Sie testen müssen?

// check orthogonality

CHECK_EQUAL( 0, dot(onb.u(), onb.v));
CHECK_EQUAL( 0, dot(onb.u(), onb.w));
CHECK_EQUAL( 0, dot(onb.v(), onb.w));

// check normality

CHECK_EQUAL( 1, dot(onb.u(), onb.u));
CHECK_EQUAL( 1, dot(onb.v(), onb.v));
CHECK_EQUAL( 1, dot(onb.w(), onb.w));

Andere Tipps

Eine Möglichkeit ist, Ihre eigene check_multi Funktion zu erstellen:

void CHECK_MULTI(TYPE actual, vector<TYPE> expected, const char* message)
{
  for (element in expected) {
    if (element == actual) {
      // there's a test here so the test count is correct
      CHECK(actual, element);
      return;   
    }
  }
  CHECK(actual, expected);
}

würde ich eine Nutzenfunktion oder Klasse verwenden, so dass Sie etwas tun können:

CHECK_EQUAL(VectorList(0,0,1)(0,0,-1), onb.v());

In Anbetracht, dass die Auslegung der Gleichheit ist etwas seltsam, aber es sollten alle Werte drucken Sie ohne die Notwendigkeit sehen wollen ein eigenes Makro einzuführen.
Wenn Sie sich über EQUAL in diesem Zusammenhang besorgt sind, sollten Sie eine benutzerdefinierte Makro wie CHECK_CONTAINS() nicht allzu schwer zu tun.

VectorList würde als temporäres und operator() konstruiert werden, verwendet werden, um Werte zum Einfügen in die enthaltenen Liste von Vectors, ähnlich wie Boost.Assign .

Grundansatz:

class VectorList {
    std::vector<Vector> data_;
public:
    VectorList(double a, double b, double c) {
        data_.push_back(Vector(a,b,c));
    }
    VectorList& operator()(double a, double b, double c) {
        data_.push_back(Vector(a,b,c));
        return *this;
    }
    bool operator==(const Vector& rhs) const {
        return std::find(data_.begin(), data_.end(), rhs) != data_.end();
    }
};
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top