On Jan 2, 6:18 am, Barend Gehrels <bar...@geodan.nl> 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; }; }}}
}}