Boost logo

Boost Users :

Subject: Re: [Boost-users] [units][geometry] subtract_typeof_helper<> help!
From: alfC (alfredo.correa_at_[hidden])
Date: 2011-01-02 18:21:47


On Jan 2, 6:18 am, Barend Gehrels <bar..._at_[hidden]> wrote:
> Hi Alfredo,
>
> > Great, please keep me (us) posted
>
> Actually the timing is convenient because this indeed was still an
> action to be taken, mentioned in the review report.
>
> > What I have so far is for example
> > using namespace boost::geometry;
> > using namespace boost::units;
> > model::point<double, 3, cs::units_cartesian<si::length> >
> > p1(1.*si::meter,2.*si::meter,3.*si::meter);
> > std::clog << distance(p1,p1) << std::endl; // outputs 0. * meter
>
> This does not work for me. The type declaration works, but coordinates
> are still doubles here. The construction effectively translates to
> "double d = 1.*si::meter". This gives me the message "cannot convert
> from 'boost::units::quantity<Unit>' to 'double'". So how does this work
> for you?

as I told you, my implementation is a total mock up and I am not sure
I am doing it with the right philosophy.
I added the code of boost_geometry_units.hpp file at the end of this
post. I guess it works for me because I specialised the class
model::point<double, 3, cs::units_cartesian<...> > and its
constructor.

The logic is that once you introduce units, the types of the
coordinates are not uniform types, for example, a real space vector
can have its cartesian coordinates in meters, but in spherical
coordinates, only the radial part is in meters, (the others are
angles). But maybe you are right the coordinates should be double upon
constructions and the metric and units is only contained in the type.

>
> > #include<boost/geometry/geometries/adapted/boost_array_units_cartesian.hpp>
> > ...
> > using namespace boost::units;
> > boost::array<quantity<si::length>, 3>
> > p5={{10.*si::meter,11.*si::meter,12.*si::meter}};
> > std::clog << distance(p5,p5) << std::endl; //outputs 0. * meter
>

(yes, I adapted boost::array< ... > in this way because it can be a
handy and the only way the boost::array can carry units is in its
values.)

> Construction works here for me, but calculating distance does not.
> Because distance behind the screens takes the square root, after
> squaring. This requires thorough integration with Boost.Units at those
> places, which is not planned.

I understand that integrations with Boost.Units is not planned and
even not desirable.
But making the implicit assumption that
typeof(sqrt(s)) == typeof(s) or that typeof(s*s)==type(s)
makes it incompatible with Boost.units. Those assumptions are good as
defaults but there should be a way to tell Boost.Geometry that
sometimes it is not the case.

>
> > the implementation I have is very primitive and it is practically a
> > mockup because it bypasses most of the features of the Boost.Geometry
> > library; mainly because I didn't understand them internally.
>
> So Boost.Geometry is not dependant on Boost.Units. I think the way to go
> is define a point type using a coordinate system using Boost.Units, like
> you did, and also add quantities there.

yes. Even at the interface level I am not sure for example if
constructors should carry units or not. I added the units to my
constructors to make it more dimensionally type safe. Maybe the
boost.units people will have clearer idea.

> I just tried that. However, the output is then still in values, so
> distance will result a value (e.g. double). It runs like this:
>
> // Note that the last 3 template parameters have defaults
> typedef model::quantity_point<si::length, 2, double,
> cs::units_cartesian<si::length> > point;
> point p1(1 * meter, 2 * meter); // only quantities expected
> point p2(3 * meter, 4 * meter);
> quantity<si::length> d = distance(p1, p2) * si::meter;

distance should return the quantity directly in my opinion.

> Then it IS possible to create a set of overloaded functions, e.g.
> boost::geometry::units::set(point, quantity) to set it from a quantity
> boost::geometry::units::get(point) to return a quantity
> boost::geometry::units::distance(a,b) -> returns a quantity in the
> coordinate dimensions from the measured distance

yes, like this.

> boost::geometry::units::area(a) -> returns a quantity e.g. in
> square_meters from a polygon
>
> So I added two of these functions as well, giving:
>
> std::cout << units::get<0>(p2) << std::endl;
> quantity<si::length> d = units::distance(p1, p2);
> std::cout << d << std::endl;
>
> reporting all quantities including units. It required some small
> additional metafunctions as well.

yes, I the same thing in my first implementation, with a namespace
boost::geometry::units that have all the overloaded functions but then
I though it would have a lot a repeated code.

>
> I just committed it, for the moment as a new example (including
> definitions), here:http://bit.ly/dEip8s

regarding the second part of the example, I think that the library in
principle can be generalized to put all the unit aware stuff in the
coordinate system. i.e. using the plain
model::point< ???, 3, cs::unit_cartesian<si::length> >. The first step
would be to allow for the library to accept that typeof(t*t) !=
typeof(t).

(by the way, I think part of the confusion comes from the fact that
if ??? are *coordinates* types, then it should potentially be a list
of types, for example imagine that I want to implement a spherical
coordinates with the radial coordinate being of type positive<double>,
and the radial coordinates being double, all this with out even
involving units. for example, fusion<double, double, double> can be
adapted as cartesian vector and fusion<positive<double>, double,
double> can be adapted as spherical coordinates but not as cartesian).

Thank you for the good discussion,
Alfredo
below the "mock up" code for boost_geometry_units.hpp. It is not good
code, it is just barely enough to make it work with
model::point<double, 3, cs::units_cartesian<Unit> >

#ifndef BOOST_GEOMETRY_UNITS_HPP
#define BOOST_GEOMETRY_UNITS_HPP
// units/tags.hpp, similar to core/tags.hpp
namespace boost{namespace geometry{
        template<class Unit>
        struct units_cartesian_tag {};
}}

// units/cs.hpp, similar to core/cs.hpp
#include<boost/geometry/core/cs.hpp>
namespace boost{namespace geometry{
namespace cs{
        template<class Unit>
        struct units_cartesian{};
}
namespace traits{
        template<class Unit>
        struct cs_tag<cs::units_cartesian<Unit> >{
                typedef units_cartesian_tag<Unit> type;
        };
}
}}
// similar to
#include<boost/geometry/strategies/distance.hpp>
#include<boost/geometry/geometries/point.hpp>
#include<boost/units/systems/si.hpp>

#include<boost/geometry/geometry.hpp>
namespace boost { namespace geometry{
namespace model{
template<class T, std::size_t Dimension, class Unit>
struct point<T, Dimension, cs::units_cartesian<Unit> > : protected
model::point<T, Dimension, cs::cartesian >{
};
template<class T, class Unit>
struct point<T, 2, cs::units_cartesian<Unit> > : protected
model::point<T, 2, cs::cartesian >{
        point(
                boost::units::quantity<Unit, T> const& x,
                boost::units::quantity<Unit, T> const& y
        ) : model::point<T, 2, cs::cartesian >(x.value(), y.value()){}
};
template<class T, class Unit>
struct point<T, 3, cs::units_cartesian<Unit> > : protected
model::point<T, 3, cs::cartesian >{
        point(
                boost::units::quantity<Unit, T> const& x,
                boost::units::quantity<Unit, T> const& y,
                boost::units::quantity<Unit, T> const& z
        ) : model::point<T, 3, cs::cartesian >(x.value(), y.value(),
z.value() ){}
};
}

template<class T, std::size_t Dimension, class Unit>
boost::units::quantity<Unit, T> distance(
        model::point<T, Dimension, cs::units_cartesian<Unit> > const& p1,
        model::point<T, Dimension, cs::units_cartesian<Unit> > const& p2
){
        return boost::units::quantity<Unit, T>::from_value(
                boost::geometry::distance(
                        (model::point<T, Dimension, cs::cartesian > const&)p1,
                        (model::point<T, Dimension, cs::cartesian > const&)p2
                )
        );
}

namespace strategy{namespace distance{namespace services{

template<class Unit> struct
return_type<boost::geometry::units_cartesian_tag<Unit> >{
        typedef boost::units::quantity<Unit> type;
};

template<std::size_t Dimension, class Unit>
struct default_strategy<
        boost::geometry::point_tag,
        boost::geometry::model::point<
                double,
                Dimension,
                boost::geometry::cs::units_cartesian<Unit>
>,
        boost::geometry::model::point<
                double,
                Dimension,
                boost::geometry::cs::units_cartesian<Unit>
>,
        boost::geometry::units_cartesian_tag<Unit>,
        boost::geometry::units_cartesian_tag<Unit>,
        void
>{
        typedef boost::geometry::units_cartesian_tag<Unit> type;
};
}}}

}}


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net