|
Geometry : |
Subject: [geometry] Run-Time specified geometries
From: Samuel Debionne (samuel.debionne_at_[hidden])
Date: 2014-04-25 05:50:01
Hello,
This thread follows the discussion started here
http://lists.boost.org/geometry/2013/10/2612.php
about a runtime extension of the library that would deal with geometry
types that are not available at compile time.
Short version :
Algorithms must report compile time errors in a specified way when
invoked with not supported types (not just rise an MPL assertion) -
easier said than done.
Long version :
So far, some algorithms accept variant parameters, variants that are
resolved and dispatched to actual implementation and that is a first
step in this direction.
Boost.Geometry is heavily using concept checking techniques to make sure
that any code that does not make sense does not compile (e.g
intersection of two linestring of different dimensions) and that's the
beauty of compile time error handling.
But what if we want to allow every possible OGC types in a variant,
variant that would be feed from an input of unknown geometry type ?
typedef boost::variant<
point_xy_t, point_xyz_t, point_xy_m_t, point_xyz_m_t
, linestring_xy_t, linestring_xyz_t, linestring_xy_m_t,
//, who knows what
> geometries_t;
Any calls with this type should be "filtered" before instantiating the
Boost.Geometry algorithms according to the underlying implementation status.
So far I had some success with simple algorithms filtered with a meta
function that checks if the dispatcher (the class in the dispatch
namespace) has not_implemented_tag as a base class and if the dimensions
are the same for all parameters, like :
template <typename Geometry1, typename Geometry2>
struct not_implemented
{
typedef typename boost::mpl::or_<
typename boost::is_base_of<
nyi::not_implemented_tag,
dispatch::distance<Geometry1, Geometry2>
>::type,
typename boost::mpl::not_<
typename boost::is_same<
typename dimension<Geometry1>::type,
typename dimension<Geometry2>::type
>::type
>::type
>::type
type;
};
and with boost::enable_if to include/exclude a specialization that
throws a runtime exception when no actual implementation is available
for the given types :
template <typename Geometry1, typename Geometry2>
double operator()(
const Geometry1& geometry1,
const Geometry2& geometry2,
typename boost::disable_if<typename not_implemented<Geometry1,
Geometry2>::type >::type* = 0) const
{
return distance(geometry1, geometry2);
}
template <typename Geometry1, typename Geometry2>
double operator()(
const Geometry1& geometry1,
const Geometry2& geometry2,
typename boost::enable_if<typename not_implemented<Geometry1,
Geometry2>::type >::type* = 0) const
{
throw not_implemented_exception();
return 0.0;
}
On a side note that also requires defining the
BOOST_GEOMETRY_IMPLEMENTATION_STATUS_BUILD macro to workaround an MPL
assertion within the not_implemented_error class.
Now the questions :
1. Testing if not_implemented_tag is a base class of the dispatcher is
not (yet) reliable. For simple algorithms like distance it works but for
algorithms that depend on others it won't. Concrete example : intersects
calls extreme_points. extreme_points is not implemented for anything
else than rings, polygons and boxes. Yet this limitation is not
"reported" to the intersects dispatcher.
2. The dispatcher is an implementation detail (not a public interface)
so should we rely on it ?
3. The filtering should happend after the variant resolution that means
rewriting all the variant code in the runtime extension. Unless a hook
is implemented to augment this code with "runtime filtering".
4. Maybe an extension is not a good idea and runtime support should be a
core functionality of the library. I think so because it seems to
require an extra requirements : the algorithms must report compile time
errors in a specified way when invoked with not supported types not just
rise an MPL assertion.
I'm working with the develop branch.
Sorry for the quite long post,
Samuel
Geometry list run by mateusz at loskot.net