Boost logo

Boost :

From: Matthias Schabel (boost_at_[hidden])
Date: 2007-02-10 15:55:02


Hi Michael,

> When working in 3d simulations it is necessary to transform vectors to
> different spaces. Bugs sometimes crop up when, for instance, adding a
> object space vector to a world space vector or adding a vector from
> object a's object space to one from object b's object space. It would
> be nice to catch such inconsistencies at compile-time. I have a
> feeling
> a units-like library would be able to handle this but I have no
> idea how
> it would work.

Here are two ways to do it, with the quantity wrapping the vector or the
vector containing quantities:

// mcs::units - A C++ library for zero-overhead dimensional analysis and
// unit/quantity manipulation and conversion
//
// Copyright (C) 2003-2007 Matthias Christian Schabel
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

// unit_example_15.cpp

#include <iostream>

#include <boost/array.hpp>

#include <boost/units/quantity.hpp>

namespace boost {

namespace units {

namespace wo {

struct world_space_tag : public ordinal<1> { };
struct object_space_tag : public ordinal<2> { };

typedef fundamental_dimension<world_space_tag>::type world_space_type;
typedef fundamental_dimension<object_space_tag>::type object_space_type;

/// placeholder class defining test unit system
struct system { };

/// unit typedefs
typedef unit<system,dimensionless_type> dimensionless;

typedef unit<system,world_space_type> world_space_unit;
typedef unit<system,object_space_type> object_space_unit;

static const world_space_unit world_space;
static const object_space_unit object_space;

} // namespace wo

} // namespace units

} // namespace boost

int main(void)
{
        using namespace boost::units;
    using namespace boost::units::wo;
        
        {
        typedef boost::array<double,3> vector;
        
        const vector vec1 = { 0, 0, 0 },
                                        vec2 = { 1, 1, 1 };
                                        
        quantity<world_space_unit,vector> wsv1(vec1*world_space),
                                                                                        wsv2(vec2*world_space);
        quantity<object_space_unit,vector> osv1(vec1*object_space),
                                                                                        osv2(vec2*object_space);
        
        quantity<world_space_unit,vector> wsv3(wsv1);
        quantity<object_space_unit,vector> osv3(osv1);
        
        // compile-time error if either of these is uncommented
// quantity<world_space_unit,vector> wsv4(osv1);
// quantity<object_space_unit,vector> osv4(wsv1);
        }
        
        {
        typedef quantity<world_space_unit> world_space_quantity;
        typedef quantity<object_space_unit> object_space_quantity;
        
        typedef boost::array<world_space_quantity,3> world_space_vector;
        typedef boost::array<object_space_quantity,3> object_space_vector;
        
        world_space_vector wsv1 = { 0*world_space, 0*world_space,
0*world_space },
                                                        wsv2 = { 1*world_space, 1*world_space, 1*world_space };
        object_space_vector osv1 = { 0*object_space, 0*object_space,
0*object_space },
                                                        osv2 = { 1*object_space, 1*object_space, 1*object_space };
        
        world_space_vector wsv3(wsv1);
        object_space_vector osv3(osv1);
        
        // compile-time error if either of these is uncommented
// world_space_vector wsv4(osv1);
// object_space_vector osv4(wsv1);
        }

     return 0;
}

You should be able to drop any well-defined vector class into this
and have it work...
Naturally, you can also define your own conversion function (see
conversion.hpp for the
default implementation). Because quantities obey the laws of
dimensional analysis, the
only operations supported by them are addition, subtraction,
multiplication, division, and
rational powers and roots. If you want to do other things, you will
need to extract the raw
value_type using the value() member function... Another way to do
this would be to define
two unit systems, the world unit system and the object unit system
and define conversions
between the two of them. For this sort of application, there are many
paths to Rome. The
right one probably depends on the details of the application.

Cheers,

Matthias


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk