
Bruno Lalande wrote:
Hopefully these can avoid the boost minefield relating to 'point' types
because trees only work on coordinates (no need to intepret them as "points" per se), and meshes are entirely topological.
I don't see anything wrong with a CartesianCoordinateConcept that requires x(), y(), z() along with typedefs or something to that effect. I think the consensus that was reached with the "point" discussion is that too many people want too many different things out of a generic point class, but the algorithms are concerned with very few details of the point class, mainly just "expose x, y, and z, and the types of each" - so don't try to make the perfect generic point class, let people use their own. Just provide algorithms that will work with their point classes, as well as the default (very basic) point class provided by the library.
This is exactly what I think too. The lack is not about the structure (everybody has one and is happy with it) but the algebra applied to them (everybody reinvents the wheel on his own structure). Just one point: requiring named accessors (x(), y(), z()) would bind us to a specific number of dimensions. One very common need is to be dimension-agnostic. In terms of structure we already have that : Boost.Tuple. So the idea would be to have your CartesianCoordinateConcept requiring templated accessors get<0>(), get<1>(), etc... instead, this way the algorithms could work by default on tuples.
Bruno
The Geometry Library as we prepare it for Boost/Open Source takes this approach now, as suggested by Hervé Brönnimann. The accessors as get<0> are useful, but limited: they do not work in loops ("expected compile-time constant expression"). So there have to be also a second accessor get(index). We have the point now defined like this (named "value"). template<typename T, size_t D> class point { public: /* ... */ template <size_t K> inline void value(const T& v) { BOOST_STATIC_ASSERT(K < D); _values[K] = v; } template <size_t K> inline const T& value() const { BOOST_STATIC_ASSERT(K < D); return _values[K]; } inline void value(size_t index, const T& v) { BOOST_ASSERT(index < D); _values[index] = v; } inline const T& value(size_t index) const { BOOST_ASSERT(index < D); return _values[index]; } private: T _values[D]; }; And a derived point like this: template <typename T> class point_xy : public point<T, 2> { public : inline const T& x() const { return value<0>(); } inline const T& y() const { return value<1>(); } inline void x(const T& v) { value<0>(v); } inline void y(const T& v) { value<1>(v); } }; template <typename T> class point_latlong : public point<T, 2> { public : /* ... */ inline const T& lon() const { return value<0>(); } inline const T& lat() const { return value<1>(); } inline void lon(const T& v) { value<0>(v); } inline void lat(const T& v) { value<1>(v); } }; (It is presented like this for clarity here, in GCC this doesn't yet compile and has to be slightly different). For each derived point class we defined some basic strategies. So for point_xy there is a strategy pythagoras to calculate the distance, and for point_latlong there is a strategy greatcircle. For a point_xyz there would be a 3D pythagoras calculation, or that one could be made dimension-independant. In this way the distance algorithm implementation can use the distance-strategy for the point-type, and the distance algorithm is itself coordinate free, works for any point. The strategy_traits class selects the strategy to be used by default. But the library user can also select an own strategy, for example to calculate more precise distances with latlong coordinates. Best regards, Barend