i am currently implementing a simple ray tracer in c++. I have a class named OrthonormalBasis, which generates three orthogonal unit vectors from one or two specified vectors, for example:
开发者_开发知识库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_);
}
I am testing all my methods with the Unittest++ framework. The Problem is, that there is more than one possible solution for a valid orthonormal basis. For example this 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() );
}
sometimes it succeeds, sometimes it fails, because the vectors v and w could also have a negative 1, and still represent a valid orthonormal basis. Is there a way to specify multiple expected values? Or do you know another way to do that?
It is important, that i get the actual and expected values printed to the stdout, in order to debug the methods so this solution won't do the job:
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() );
}
Surely if all you are testing is whether your basis is orthonormal, then that's what you need to test?
// 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));
One possibility is to create your own CHECK_MULTI function:
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);
}
I'd use a utility function or class so you can do something like this:
CHECK_EQUAL(VectorList(0,0,1)(0,0,-1), onb.v());
Given, that interpretation of equality is somewhat weird, but it should print you all values you want to see without the need to introduce a custom macro.
If you are worried about EQUAL
in that context, a custom macro like CHECK_CONTAINS()
shouldn't be too hard to do.
VectorList
would be constructed as a temporary and operator()
be used to insert values into the contained list of Vector
s, similar to Boost.Assign.
Basic approach:
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();
}
};
精彩评论