mirror of
https://github.com/boostorg/geometry.git
synced 2025-05-09 23:24:02 +00:00
149 lines
8.7 KiB
Plaintext
149 lines
8.7 KiB
Plaintext
[/==============================================================================
|
|
Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
|
|
Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
|
|
Copyright (c) 2009-2012 Mateusz Loskot, London, UK., London, UK
|
|
|
|
Use, modification and distribution is subject to 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)
|
|
===============================================================================/]
|
|
|
|
[section:strategy Strategy Rationale]
|
|
|
|
[@http://en.wikipedia.org/wiki/Strategy_pattern Strategy] is a [@http://en.wikipedia.org/wiki/Design_pattern_(computer_science) software design pattern] used to
|
|
achieve algorithms slection at runtime. An idiomatic variation of the Strategy pattern specific
|
|
to C++ programming language is known as Policy pattern with related technique of [@http://en.wikipedia.org/wiki/Policy-based_design Policy-based design]. Thus, in the C++ template
|
|
contexts, policy is usually meant as selection of algorithms at compile time.
|
|
|
|
['TODO: the two sentences below need to be clarified, what is "another context", etc. --mloskot]
|
|
|
|
__boost_geometry__ uses (sparsely) the term policy in a broader, or in another, context. The term
|
|
Strategy is used specificly for a computation method targeted to a specific coordinate system.
|
|
|
|
In __boost_geometry__ strategies do have the following purposes:
|
|
|
|
* for each coordinate system, a default strategy is selected by compile time, using the coordinate
|
|
system tag. This is effectively tag dispatching.
|
|
* users can override the default choice by using the overloaded function, which has a strategy
|
|
as an extra parameter, and take another strategy
|
|
* users can override the default choice by using the overloaded function, to use the default
|
|
strategy, but constructed with specific parameters
|
|
* users can override the default choice by using the overloaded function, to use the default
|
|
strategy (which can be a templated structure), with other template parameters then the default ones
|
|
* users can override the default choice by using the overloaded function, to use the default
|
|
strategy, which can be a class template, with other template parameters then the default ones,
|
|
with the specific purpose as to select another calculation type (e.g. __gmp__ or another
|
|
arbitrary precision number type)
|
|
|
|
All these decisions and choices listed above occur at compile-time.
|
|
|
|
Let's discuss a short example to explaining how strategies work in __boost_geometry__.
|
|
Note, it is also explained in the design rationale section.
|
|
|
|
Considering calculation of distance in three common coordinate systems, for each of the coordinate
|
|
systems a default strategy implementing distance calculation has been assigned:
|
|
|
|
* __wiki_cs_cartesian__ uses Pythagoras as default strategy for point-point distance calculations
|
|
* __wiki_cs_spherical__ uses Haversine strategy a default
|
|
* __wiki_cs_geographic__ uses Andoyer.
|
|
|
|
The Haversine works on the unit sphere, radius `1`. Library users can use the distance function,
|
|
specifying haversine strategy constructed with a radius of `2`. Or, for example, they can
|
|
use the distance function, specifying the more precise Vincenty strategy
|
|
(for __wiki_cs_geographic__, but that might not even be checked there).
|
|
|
|
Specifying strategies is useful, even if not point-point distance is to be calculated, for
|
|
example, point-polygon distance. In the end, it will call the elementary specified functionality.
|
|
Note, that for this example, the point-segment distance strategy is also considered as "elementary".
|
|
Note also, that it can have an optional template parameter defining the underlying
|
|
point-point-distance-strategy.
|
|
|
|
[section:properties Properties of Strategies]
|
|
|
|
Strategies can be constructed outside a calling function, thus they can be specified as an
|
|
optional parameter (implemented as an overloaded function), and not only as a template parameter.
|
|
Furthermore, strategies can be reused number of times, in subsequent function calls.
|
|
Therefore strategies as function parameter are declared as reference to `const` and they
|
|
should be stateless, except that they can be provided with some initialization details
|
|
during construction.
|
|
|
|
The strategy needs to access construction information (member variables), its calculation method
|
|
is therefore usually not a `static` method but a non-static `const` method. It can then access
|
|
member variables, while still being `const`, non-mutable, stateless and read-only object, and
|
|
being able to be called across several function calls.
|
|
|
|
['TODO: The next 2-3 paragraphs might need some refactoring, to rephrase what is said in
|
|
clearer and simple manner --mloskot]
|
|
|
|
For some algorithms, strategies may need to store some intermediate results of calculation
|
|
(a state). For this purpose, strategies should declare a `state_type`. An instance of the `state_type`
|
|
is created before first call is performed and specified in each call.
|
|
|
|
The calculation method is always called apply (as convention in __boost_geometry__) and gets the
|
|
most elementary information as a parameter: a point, a segment, a range. It depends on the
|
|
algorithm and, sometimes, on the source geometry passed. That should actually be the case as
|
|
least as possisble.
|
|
In most cases, there is an additional method result which returns the calculated result.
|
|
That result-method is a also non-static const method, and the state is passed. Note that the
|
|
methods might be non-static const, but they might also be static. That is not checked by the
|
|
concept-checker.
|
|
|
|
A strategy for a specific algorithm has a concept. The distance-strategy should follow the
|
|
distance-strategy-concept. The point-in-polygon strategy should follow the
|
|
point-in-polygon-strategy-concept. Those concepts are not modelled as traits classes (contrary
|
|
to the geometries). The reason for this is that it seems not necessary to use legacy classes
|
|
as concepts, without modification. A wrapper can be built. So the strategies should have a method
|
|
apply and should define some types.
|
|
|
|
Which types, and which additional methods (often a method result), is dependant on the algorithm
|
|
and type of strategy.
|
|
|
|
Strategies are checked by a strategy-concept-checker. For this checker (and sometimes for
|
|
checking alone), they should define some types. Because if no types are defined, the
|
|
cannot be checked at compile time... The strategy-concept-checkers are thus implemented per
|
|
algorithm and they use the __boost_concept__ for concepts checking.
|
|
|
|
According to what was explained above, the essentials of the design are:
|
|
|
|
* function determines default-strategy, or is called with specified strategy
|
|
* function calls dispatch (dispatching is done on geometry tag)
|
|
* dispatch calls implementation (in namespace detail), which can be shared for different geometry
|
|
types, for single as well as for aggregate geometries (multi-geometries)
|
|
* implementation calls strategy (if applicable), with the smallest common (geometric)
|
|
element applicable for all calculation method, the common denominator.
|
|
|
|
[endsect] [/ end of section Properties of Strategies]
|
|
|
|
[section:alternative Alternative Design]
|
|
|
|
Some calculations (strategies) might need to take the whole geometry, instead of working on
|
|
point-per-point or segment-per-segment base. This would bypass the dispatch functionality.
|
|
Because all strategies would take the whole geometry, it is not necessary to dispatch per
|
|
geometry type. In fact this dispatching on geometry-type is moved to the strategy_traits class
|
|
(which are specialized per coordinate system in the current design). So in this alternative design,
|
|
the strategy traits class specializes on both geometry-tag and coordinate-system-tag, to select
|
|
the default strategy. For the default strategy, this move from "dispatch" to another dispatch
|
|
called `strategy_XXX` (XXX is the algorithm) might make sense. However, if library users would
|
|
call the overloaded function and specify a strategy, the only thing what would happen is that
|
|
that specified strategy is called.
|
|
|
|
For example:
|
|
|
|
template <typename G1, typename G2, typename S>
|
|
bool within(G1 const& g1, G2 const& g2, S& const strategy)
|
|
{
|
|
return strategy.apply(g1, g2);
|
|
}
|
|
|
|
The library user could call just this `strategy.apply()` method directly. If more strategies are
|
|
provided by the library or its extensions, it would still make sense: the user can still call
|
|
within and does not have to call the apply method of the strategy.
|
|
|
|
The convex hull strategy currently works on a whole geometry. However, it is possible that it will
|
|
be reshaped to work per range (the algorithm internally works per range), plus a mechanism to
|
|
pass ranges multiple times (it currently is two-pass).
|
|
|
|
[endsect] [/ end of section Alternative Design]
|
|
|
|
[endsect] [/ end of section Strategies]
|