stabilize build system: depends, installer, boost/bdb fixes, cross targets groundwork

This commit is contained in:
2026-02-24 18:38:47 +00:00
parent da8c28aaeb
commit 65cb2619a7
13106 changed files with 2484322 additions and 1804 deletions
@@ -0,0 +1,114 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_BUFFER_DISTANCE_ASYMMETRIC_HPP
#define BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_BUFFER_DISTANCE_ASYMMETRIC_HPP
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/strategies/buffer.hpp>
#include <boost/geometry/util/math.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace buffer
{
/*!
\brief Let the buffer for linestrings be asymmetric
\ingroup strategies
\tparam NumericType \tparam_numeric
\details This strategy can be used as DistanceStrategy for the buffer algorithm.
It can be applied for (multi)linestrings. It uses a (potentially) different
distances for left and for right. This means the (multi)linestrings are
interpreted having a direction.
\qbk{
[heading Example]
[buffer_distance_asymmetric]
[heading Output]
[$img/strategies/buffer_distance_asymmetric.png]
[heading See also]
\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)]
\* [link geometry.reference.strategies.strategy_buffer_distance_symmetric distance_symmetric]
}
*/
template<typename NumericType>
class distance_asymmetric
{
public :
//! \brief Constructs the strategy, two distances must be specified
//! \param left The distance (or radius) of the buffer on the left side
//! \param right The distance on the right side
distance_asymmetric(NumericType const& left,
NumericType const& right)
: m_left(left)
, m_right(right)
{}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
//! Returns the distance-value for the specified side
template <typename Point>
inline NumericType apply(Point const& , Point const& ,
buffer_side_selector side) const
{
NumericType result = side == buffer_side_left ? m_left : m_right;
return negative() ? math::abs(result) : result;
}
//! Used internally, returns -1 for deflate, 1 for inflate
inline int factor() const
{
return negative() ? -1 : 1;
}
//! Returns true if both distances are negative
inline bool negative() const
{
return m_left < 0 && m_right < 0;
}
//! Returns the max distance distance up to the buffer will reach
template <typename JoinStrategy, typename EndStrategy>
inline NumericType max_distance(JoinStrategy const& join_strategy,
EndStrategy const& end_strategy) const
{
boost::ignore_unused(join_strategy, end_strategy);
NumericType const left = geometry::math::abs(m_left);
NumericType const right = geometry::math::abs(m_right);
NumericType const dist = (std::max)(left, right);
return (std::max)(join_strategy.max_distance(dist),
end_strategy.max_distance(dist));
}
//! Returns the distance at which the input is simplified before the buffer process
inline NumericType simplify_distance() const
{
NumericType const left = geometry::math::abs(m_left);
NumericType const right = geometry::math::abs(m_right);
return (std::min)(left, right) / 1000.0;
}
#endif // DOXYGEN_SHOULD_SKIP_THIS
private :
NumericType m_left;
NumericType m_right;
};
}} // namespace strategy::buffer
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_BUFFER_DISTANCE_ASYMMETRIC_HPP
@@ -0,0 +1,107 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_BUFFER_DISTANCE_SYMMETRIC_HPP
#define BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_BUFFER_DISTANCE_SYMMETRIC_HPP
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/strategies/buffer.hpp>
#include <boost/geometry/util/math.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace buffer
{
/*!
\brief Let the buffer algorithm create buffers with same distances
\ingroup strategies
\tparam NumericType \tparam_numeric
\details This strategy can be used as DistanceStrategy for the buffer algorithm.
It can be applied for all geometries. It uses one distance for left and
for right.
If the distance is negative and used with a (multi)polygon or ring, the
geometry will shrink (deflate) instead of expand (inflate).
\qbk{
[heading Example]
[buffer_distance_symmetric]
[heading Output]
[$img/strategies/buffer_distance_symmetric.png]
[heading See also]
\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)]
\* [link geometry.reference.strategies.strategy_buffer_distance_asymmetric distance_asymmetric]
}
*/
template<typename NumericType>
class distance_symmetric
{
public :
//! \brief Constructs the strategy, a distance must be specified
//! \param distance The distance (or radius) of the buffer
explicit inline distance_symmetric(NumericType const& distance)
: m_distance(distance)
{}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
//! Returns the distance-value
template <typename Point>
inline NumericType apply(Point const& , Point const& ,
buffer_side_selector ) const
{
return negative() ? geometry::math::abs(m_distance) : m_distance;
}
//! Used internally, returns -1 for deflate, 1 for inflate
inline int factor() const
{
return negative() ? -1 : 1;
}
//! Returns true if distance is negative
inline bool negative() const
{
return m_distance < 0;
}
//! Returns the max distance distance up to the buffer will reach
template <typename JoinStrategy, typename EndStrategy>
inline NumericType max_distance(JoinStrategy const& join_strategy,
EndStrategy const& end_strategy) const
{
boost::ignore_unused(join_strategy, end_strategy);
NumericType const dist = geometry::math::abs(m_distance);
return (std::max)(join_strategy.max_distance(dist),
end_strategy.max_distance(dist));
}
//! Returns the distance at which the input is simplified before the buffer process
inline NumericType simplify_distance() const
{
return geometry::math::abs(m_distance) / 1000.0;
}
#endif // DOXYGEN_SHOULD_SKIP_THIS
private :
NumericType m_distance;
};
}} // namespace strategy::buffer
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_BUFFER_DISTANCE_SYMMETRIC_HPP
@@ -0,0 +1,390 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_CONVEX_GRAHAM_ANDREW_HPP
#define BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_CONVEX_GRAHAM_ANDREW_HPP
#include <cstddef>
#include <algorithm>
#include <vector>
#include <boost/range.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/strategies/convex_hull.hpp>
#include <boost/geometry/views/detail/range_type.hpp>
#include <boost/geometry/policies/compare.hpp>
#include <boost/geometry/algorithms/detail/for_each_range.hpp>
#include <boost/geometry/views/reversible_view.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace convex_hull
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template
<
typename InputRange,
typename RangeIterator,
typename StrategyLess,
typename StrategyGreater
>
struct get_extremes
{
typedef typename point_type<InputRange>::type point_type;
point_type left, right;
bool first;
StrategyLess less;
StrategyGreater greater;
inline get_extremes()
: first(true)
{}
inline void apply(InputRange const& range)
{
if (boost::size(range) == 0)
{
return;
}
// First iterate through this range
// (this two-stage approach avoids many point copies,
// because iterators are kept in memory. Because iterators are
// not persistent (in MSVC) this approach is not applicable
// for more ranges together)
RangeIterator left_it = boost::begin(range);
RangeIterator right_it = boost::begin(range);
for (RangeIterator it = boost::begin(range) + 1;
it != boost::end(range);
++it)
{
if (less(*it, *left_it))
{
left_it = it;
}
if (greater(*it, *right_it))
{
right_it = it;
}
}
// Then compare with earlier
if (first)
{
// First time, assign left/right
left = *left_it;
right = *right_it;
first = false;
}
else
{
// Next time, check if this range was left/right from
// the extremes already collected
if (less(*left_it, left))
{
left = *left_it;
}
if (greater(*right_it, right))
{
right = *right_it;
}
}
}
};
template
<
typename InputRange,
typename RangeIterator,
typename Container,
typename SideStrategy
>
struct assign_range
{
Container lower_points, upper_points;
typedef typename point_type<InputRange>::type point_type;
point_type const& most_left;
point_type const& most_right;
inline assign_range(point_type const& left, point_type const& right)
: most_left(left)
, most_right(right)
{}
inline void apply(InputRange const& range)
{
typedef SideStrategy side;
// Put points in one of the two output sequences
for (RangeIterator it = boost::begin(range);
it != boost::end(range);
++it)
{
// check if it is lying most_left or most_right from the line
int dir = side::apply(most_left, most_right, *it);
switch(dir)
{
case 1 : // left side
upper_points.push_back(*it);
break;
case -1 : // right side
lower_points.push_back(*it);
break;
// 0: on line most_left-most_right,
// or most_left, or most_right,
// -> all never part of hull
}
}
}
};
template <typename Range>
static inline void sort(Range& range)
{
typedef typename boost::range_value<Range>::type point_type;
typedef geometry::less<point_type> comparator;
std::sort(boost::begin(range), boost::end(range), comparator());
}
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
/*!
\brief Graham scan strategy to calculate convex hull
\ingroup strategies
\note Completely reworked version inspired on the sources listed below
\see http://www.ddj.com/architect/201806315
\see http://marknelson.us/2007/08/22/convex
*/
template <typename InputGeometry, typename OutputPoint>
class graham_andrew
{
public :
typedef OutputPoint point_type;
typedef InputGeometry geometry_type;
private:
typedef typename cs_tag<point_type>::type cs_tag;
typedef typename std::vector<point_type> container_type;
typedef typename std::vector<point_type>::const_iterator iterator;
typedef typename std::vector<point_type>::const_reverse_iterator rev_iterator;
class partitions
{
friend class graham_andrew;
container_type m_lower_hull;
container_type m_upper_hull;
container_type m_copied_input;
};
public:
typedef partitions state_type;
inline void apply(InputGeometry const& geometry, partitions& state) const
{
// First pass.
// Get min/max (in most cases left / right) points
// This makes use of the geometry::less/greater predicates
// For the left boundary it is important that multiple points
// are sorted from bottom to top. Therefore the less predicate
// does not take the x-only template parameter (this fixes ticket #6019.
// For the right boundary it is not necessary (though also not harmful),
// because points are sorted from bottom to top in a later stage.
// For symmetry and to get often more balanced lower/upper halves
// we keep it.
typedef typename geometry::detail::range_type<InputGeometry>::type range_type;
typedef typename boost::range_iterator
<
range_type const
>::type range_iterator;
detail::get_extremes
<
range_type,
range_iterator,
geometry::less<point_type>,
geometry::greater<point_type>
> extremes;
geometry::detail::for_each_range(geometry, extremes);
// Bounding left/right points
// Second pass, now that extremes are found, assign all points
// in either lower, either upper
detail::assign_range
<
range_type,
range_iterator,
container_type,
typename strategy::side::services::default_strategy<cs_tag>::type
> assigner(extremes.left, extremes.right);
geometry::detail::for_each_range(geometry, assigner);
// Sort both collections, first on x(, then on y)
detail::sort(assigner.lower_points);
detail::sort(assigner.upper_points);
//std::cout << boost::size(assigner.lower_points) << std::endl;
//std::cout << boost::size(assigner.upper_points) << std::endl;
// And decide which point should be in the final hull
build_half_hull<-1>(assigner.lower_points, state.m_lower_hull,
extremes.left, extremes.right);
build_half_hull<1>(assigner.upper_points, state.m_upper_hull,
extremes.left, extremes.right);
}
template <typename OutputIterator>
inline void result(partitions const& state,
OutputIterator out,
bool clockwise,
bool closed) const
{
if (clockwise)
{
output_ranges(state.m_upper_hull, state.m_lower_hull, out, closed);
}
else
{
output_ranges(state.m_lower_hull, state.m_upper_hull, out, closed);
}
}
private:
template <int Factor>
static inline void build_half_hull(container_type const& input,
container_type& output,
point_type const& left, point_type const& right)
{
output.push_back(left);
for(iterator it = input.begin(); it != input.end(); ++it)
{
add_to_hull<Factor>(*it, output);
}
add_to_hull<Factor>(right, output);
}
template <int Factor>
static inline void add_to_hull(point_type const& p, container_type& output)
{
typedef typename strategy::side::services::default_strategy<cs_tag>::type side;
output.push_back(p);
std::size_t output_size = output.size();
while (output_size >= 3)
{
rev_iterator rit = output.rbegin();
point_type const last = *rit++;
point_type const& last2 = *rit++;
if (Factor * side::apply(*rit, last, last2) <= 0)
{
// Remove last two points from stack, and add last again
// This is much faster then erasing the one but last.
output.pop_back();
output.pop_back();
output.push_back(last);
output_size--;
}
else
{
return;
}
}
}
template <typename OutputIterator>
static inline void output_ranges(container_type const& first, container_type const& second,
OutputIterator out, bool closed)
{
std::copy(boost::begin(first), boost::end(first), out);
BOOST_GEOMETRY_ASSERT(closed ? !boost::empty(second) : boost::size(second) > 1);
std::copy(++boost::rbegin(second), // skip the first Point
closed ? boost::rend(second) : --boost::rend(second), // skip the last Point if open
out);
typedef typename boost::range_size<container_type>::type size_type;
size_type const count = boost::size(first) + boost::size(second) - 1;
// count describes a closed case but comparison with min size of closed
// gives the result compatible also with open
// here core_detail::closure::minimum_ring_size<closed> could be used
if (count < 4)
{
// there should be only one missing
*out++ = *boost::begin(first);
}
}
};
}} // namespace strategy::convex_hull
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
template <typename InputGeometry, typename OutputPoint>
struct strategy_convex_hull<InputGeometry, OutputPoint, cartesian_tag>
{
typedef strategy::convex_hull::graham_andrew<InputGeometry, OutputPoint> type;
};
#endif
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_CONVEX_GRAHAM_ANDREW_HPP
@@ -0,0 +1,103 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_POINT_IN_BOX_BY_SIDE_HPP
#define BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_POINT_IN_BOX_BY_SIDE_HPP
#include <boost/array.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/within.hpp>
namespace boost { namespace geometry { namespace strategy
{
namespace within
{
struct decide_within
{
static inline bool apply(int side, bool& result)
{
if (side != 1)
{
result = false;
return false;
}
return true; // continue
}
};
struct decide_covered_by
{
static inline bool apply(int side, bool& result)
{
if (side != 1)
{
result = side >= 0;
return false;
}
return true; // continue
}
};
// WARNING
// This strategy is not suitable for boxes in non-cartesian CSes having edges
// longer than 180deg because e.g. the SSF formula picks the side of the closer
// longitude, so for long edges the side is the opposite.
template <typename Point, typename Box, typename Decide = decide_within>
struct point_in_box_by_side
{
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Box>::type
>::type side_strategy_type;
static inline bool apply(Point const& point, Box const& box)
{
// Create (counterclockwise) array of points, the fifth one closes it
// Every point should be on the LEFT side (=1), or ON the border (=0),
// So >= 1 or >= 0
boost::array<typename point_type<Box>::type, 5> bp;
geometry::detail::assign_box_corners_oriented<true>(box, bp);
bp[4] = bp[0];
bool result = true;
side_strategy_type strategy;
boost::ignore_unused_variable_warning(strategy);
for (int i = 1; i < 5; i++)
{
int const side = strategy.apply(point, bp[i - 1], bp[i]);
if (! Decide::apply(side, result))
{
return result;
}
}
return result;
}
};
} // namespace within
}}} // namespace boost::geometry::strategy
#endif // BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_POINT_IN_BOX_BY_SIDE_HPP
@@ -0,0 +1,77 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POINT_HPP
#define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POINT_HPP
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/within.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace within
{
template
<
typename Point1, typename Point2
>
struct point_in_point
{
static inline bool apply(Point1 const& point1, Point2 const& point2)
{
return detail::equals::equals_point_point(point1, point2);
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename Point, typename PointLike, typename Tag2, typename AnyCS1, typename AnyCS2>
struct default_strategy<Point, PointLike, point_tag, Tag2, pointlike_tag, pointlike_tag, AnyCS1, AnyCS2>
{
typedef strategy::within::point_in_point<Point, typename point_type<PointLike>::type> type;
};
} // namespace services
#endif
}} // namespace strategy::within
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace strategy { namespace covered_by { namespace services
{
template <typename Point, typename PointLike, typename Tag2, typename AnyCS1, typename AnyCS2>
struct default_strategy<Point, PointLike, point_tag, Tag2, pointlike_tag, pointlike_tag, AnyCS1, AnyCS2>
{
typedef strategy::within::point_in_point<Point, typename point_type<PointLike>::type> type;
};
}}} // namespace strategy::covered_by::services
#endif
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POINT_HPP
@@ -0,0 +1,208 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2011-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POLY_ORIENTED_WINDING_HPP
#define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POLY_ORIENTED_WINDING_HPP
#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/strategies/within.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace within
{
/*!
\brief Within detection using winding rule, but checking if enclosing ring is
counter clockwise and, if so, reverses the result
\ingroup strategies
\tparam Point \tparam_point
\tparam Reverse True if parameter should be reversed
\tparam PointOfSegment \tparam_segment_point
\tparam CalculationType \tparam_calculation
\author Barend Gehrels
\note The implementation is inspired by terralib http://www.terralib.org (LGPL)
\note but totally revised afterwards, especially for cases on segments
\note Only dependant on "side", -> agnostic, suitable for spherical/latlong
\qbk{
[heading See also]
[link geometry.reference.algorithms.within.within_3_with_strategy within (with strategy)]
}
*/
template
<
bool Reverse,
typename Point,
typename PointOfSegment = Point,
typename CalculationType = void
>
class oriented_winding
{
typedef typename select_calculation_type
<
Point,
PointOfSegment,
CalculationType
>::type calculation_type;
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Point>::type
>::type strategy_side_type;
/*! subclass to keep state */
class counter
{
int m_count;
bool m_touches;
calculation_type m_sum_area;
inline int code() const
{
return m_touches ? 0 : m_count == 0 ? -1 : 1;
}
inline int clockwise_oriented_code() const
{
return (m_sum_area > 0) ? code() : -code();
}
inline int oriented_code() const
{
return Reverse
? -clockwise_oriented_code()
: clockwise_oriented_code();
}
public :
friend class oriented_winding;
inline counter()
: m_count(0)
, m_touches(false)
, m_sum_area(0)
{}
inline void add_to_area(calculation_type triangle)
{
m_sum_area += triangle;
}
};
template <size_t D>
static inline int check_touch(Point const& point,
PointOfSegment const& seg1, PointOfSegment const& seg2,
counter& state)
{
calculation_type const p = get<D>(point);
calculation_type const s1 = get<D>(seg1);
calculation_type const s2 = get<D>(seg2);
if ((s1 <= p && s2 >= p) || (s2 <= p && s1 >= p))
{
state.m_touches = true;
}
return 0;
}
template <size_t D>
static inline int check_segment(Point const& point,
PointOfSegment const& seg1, PointOfSegment const& seg2,
counter& state)
{
calculation_type const p = get<D>(point);
calculation_type const s1 = get<D>(seg1);
calculation_type const s2 = get<D>(seg2);
// Check if one of segment endpoints is at same level of point
bool eq1 = math::equals(s1, p);
bool eq2 = math::equals(s2, p);
if (eq1 && eq2)
{
// Both equal p -> segment is horizontal (or vertical for D=0)
// The only thing which has to be done is check if point is ON segment
return check_touch<1 - D>(point, seg1, seg2, state);
}
return
eq1 ? (s2 > p ? 1 : -1) // Point on level s1, UP/DOWN depending on s2
: eq2 ? (s1 > p ? -1 : 1) // idem
: s1 < p && s2 > p ? 2 // Point between s1 -> s2 --> UP
: s2 < p && s1 > p ? -2 // Point between s2 -> s1 --> DOWN
: 0;
}
public :
// Typedefs and static methods to fulfill the concept
typedef Point point_type;
typedef PointOfSegment segment_point_type;
typedef counter state_type;
static inline bool apply(Point const& point,
PointOfSegment const& s1, PointOfSegment const& s2,
counter& state)
{
state.add_to_area(get<0>(s2) * get<1>(s1) - get<0>(s1) * get<1>(s2));
int count = check_segment<1>(point, s1, s2, state);
if (count != 0)
{
int side = strategy_side_type::apply(s1, s2, point);
if (side == 0)
{
// Point is lying on segment
state.m_touches = true;
state.m_count = 0;
return false;
}
// Side is NEG for right, POS for left.
// The count is -2 for down, 2 for up (or -1/1)
// Side positive thus means UP and LEFTSIDE or DOWN and RIGHTSIDE
// See accompagnying figure (TODO)
if (side * count > 0)
{
state.m_count += count;
}
}
return ! state.m_touches;
}
static inline int result(counter const& state)
{
return state.oriented_code();
}
};
}} // namespace strategy::within
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POLY_ORIENTED_WINDING_HPP
@@ -0,0 +1,529 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2013, 2014, 2016, 2017.
// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POLY_WINDING_HPP
#define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POLY_WINDING_HPP
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/within.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace within
{
// 1 deg or pi/180 rad
template <typename Point,
typename CalculationType = typename coordinate_type<Point>::type>
struct winding_small_angle
{
typedef typename coordinate_system<Point>::type cs_t;
typedef math::detail::constants_on_spheroid
<
CalculationType,
typename cs_t::units
> constants;
static inline CalculationType apply()
{
return constants::half_period() / CalculationType(180);
}
};
// Fix for https://svn.boost.org/trac/boost/ticket/9628
// For floating point coordinates, the <D> coordinate of a point is compared
// with the segment's points using some EPS. If the coordinates are "equal"
// the sides are calculated. Therefore we can treat a segment as a long areal
// geometry having some width. There is a small ~triangular area somewhere
// between the segment's effective area and a segment's line used in sides
// calculation where the segment is on the one side of the line but on the
// other side of a segment (due to the width).
// Below picture assuming D = 1, if D = 0 horiz<->vert, E<->N, RIGHT<->UP.
// For the s1 of a segment going NE the real side is RIGHT but the point may
// be detected as LEFT, like this:
// RIGHT
// ___----->
// ^ O Pt __ __
// EPS __ __
// v__ __ BUT DETECTED AS LEFT OF THIS LINE
// _____7
// _____/
// _____/
// In the code below actually D = 0, so segments are nearly-vertical
// Called when the point is on the same level as one of the segment's points
// but the point is not aligned with a vertical segment
template <typename CSTag>
struct winding_side_equal
{
typedef typename strategy::side::services::default_strategy
<
CSTag
>::type strategy_side_type;
template <typename Point, typename PointOfSegment>
static inline int apply(Point const& point,
PointOfSegment const& se,
int count)
{
typedef typename coordinate_type<PointOfSegment>::type scoord_t;
typedef typename coordinate_system<PointOfSegment>::type::units units_t;
if (math::equals(get<1>(point), get<1>(se)))
return 0;
// Create a horizontal segment intersecting the original segment's endpoint
// equal to the point, with the derived direction (E/W).
PointOfSegment ss1, ss2;
set<1>(ss1, get<1>(se));
set<0>(ss1, get<0>(se));
set<1>(ss2, get<1>(se));
scoord_t ss20 = get<0>(se);
if (count > 0)
{
ss20 += winding_small_angle<PointOfSegment>::apply();
}
else
{
ss20 -= winding_small_angle<PointOfSegment>::apply();
}
math::normalize_longitude<units_t>(ss20);
set<0>(ss2, ss20);
// Check the side using this vertical segment
return strategy_side_type::apply(ss1, ss2, point);
}
};
// The optimization for cartesian
template <>
struct winding_side_equal<cartesian_tag>
{
template <typename Point, typename PointOfSegment>
static inline int apply(Point const& point,
PointOfSegment const& se,
int count)
{
// NOTE: for D=0 the signs would be reversed
return math::equals(get<1>(point), get<1>(se)) ?
0 :
get<1>(point) < get<1>(se) ?
// assuming count is equal to 1 or -1
-count : // ( count > 0 ? -1 : 1) :
count; // ( count > 0 ? 1 : -1) ;
}
};
template <typename Point,
typename CalculationType,
typename CSTag = typename cs_tag<Point>::type>
struct winding_check_touch
{
typedef CalculationType calc_t;
typedef typename coordinate_system<Point>::type::units units_t;
typedef math::detail::constants_on_spheroid<CalculationType, units_t> constants;
template <typename PointOfSegment, typename State>
static inline int apply(Point const& point,
PointOfSegment const& seg1,
PointOfSegment const& seg2,
State& state,
bool& eq1,
bool& eq2)
{
calc_t const pi = constants::half_period();
calc_t const pi2 = pi / calc_t(2);
calc_t const px = get<0>(point);
calc_t const s1x = get<0>(seg1);
calc_t const s2x = get<0>(seg2);
calc_t const py = get<1>(point);
calc_t const s1y = get<1>(seg1);
calc_t const s2y = get<1>(seg2);
// NOTE: lat in {-90, 90} and arbitrary lon
// it doesn't matter what lon it is if it's a pole
// so e.g. if one of the segment endpoints is a pole
// then only the other lon matters
bool eq1_strict = math::equals(s1x, px);
bool eq2_strict = math::equals(s2x, px);
eq1 = eq1_strict // lon strictly equal to s1
|| math::equals(s1y, pi2) || math::equals(s1y, -pi2); // s1 is pole
eq2 = eq2_strict // lon strictly equal to s2
|| math::equals(s2y, pi2) || math::equals(s2y, -pi2); // s2 is pole
// segment overlapping pole
calc_t s1x_anti = s1x + constants::half_period();
math::normalize_longitude<units_t, calc_t>(s1x_anti);
bool antipodal = math::equals(s2x, s1x_anti);
if (antipodal)
{
eq1 = eq2 = eq1 || eq2;
// segment overlapping pole and point is pole
if (math::equals(py, pi2) || math::equals(py, -pi2))
{
eq1 = eq2 = true;
}
}
// Both equal p -> segment vertical
// The only thing which has to be done is check if point is ON segment
if (eq1 && eq2)
{
// segment endpoints on the same sides of the globe
if (! antipodal
// p's lat between segment endpoints' lats
? (s1y <= py && s2y >= py) || (s2y <= py && s1y >= py)
// going through north or south pole?
: (pi - s1y - s2y <= pi
? (eq1_strict && s1y <= py) || (eq2_strict && s2y <= py) // north
|| math::equals(py, pi2) // point on north pole
: (eq1_strict && s1y >= py) || (eq2_strict && s2y >= py)) // south
|| math::equals(py, -pi2) // point on south pole
)
{
state.m_touches = true;
}
return true;
}
return false;
}
};
// The optimization for cartesian
template <typename Point, typename CalculationType>
struct winding_check_touch<Point, CalculationType, cartesian_tag>
{
typedef CalculationType calc_t;
template <typename PointOfSegment, typename State>
static inline bool apply(Point const& point,
PointOfSegment const& seg1,
PointOfSegment const& seg2,
State& state,
bool& eq1,
bool& eq2)
{
calc_t const px = get<0>(point);
calc_t const s1x = get<0>(seg1);
calc_t const s2x = get<0>(seg2);
eq1 = math::equals(s1x, px);
eq2 = math::equals(s2x, px);
// Both equal p -> segment vertical
// The only thing which has to be done is check if point is ON segment
if (eq1 && eq2)
{
calc_t const py = get<1>(point);
calc_t const s1y = get<1>(seg1);
calc_t const s2y = get<1>(seg2);
if ((s1y <= py && s2y >= py) || (s2y <= py && s1y >= py))
{
state.m_touches = true;
}
return true;
}
return false;
}
};
// Called if point is not aligned with a vertical segment
template <typename Point,
typename CalculationType,
typename CSTag = typename cs_tag<Point>::type>
struct winding_calculate_count
{
typedef CalculationType calc_t;
typedef typename coordinate_system<Point>::type::units units_t;
static inline bool greater(calc_t const& l, calc_t const& r)
{
calc_t diff = l - r;
math::normalize_longitude<units_t, calc_t>(diff);
return diff > calc_t(0);
}
static inline int apply(calc_t const& p,
calc_t const& s1, calc_t const& s2,
bool eq1, bool eq2)
{
// Probably could be optimized by avoiding normalization for some comparisons
// e.g. s1 > p could be calculated from p > s1
// If both segment endpoints were poles below checks wouldn't be enough
// but this means that either both are the same or that they are N/S poles
// and therefore the segment is not valid.
// If needed (eq1 && eq2 ? 0) could be returned
return
eq1 ? (greater(s2, p) ? 1 : -1) // Point on level s1, E/W depending on s2
: eq2 ? (greater(s1, p) ? -1 : 1) // idem
: greater(p, s1) && greater(s2, p) ? 2 // Point between s1 -> s2 --> E
: greater(p, s2) && greater(s1, p) ? -2 // Point between s2 -> s1 --> W
: 0;
}
};
// The optimization for cartesian
template <typename Point, typename CalculationType>
struct winding_calculate_count<Point, CalculationType, cartesian_tag>
{
typedef CalculationType calc_t;
static inline int apply(calc_t const& p,
calc_t const& s1, calc_t const& s2,
bool eq1, bool eq2)
{
return
eq1 ? (s2 > p ? 1 : -1) // Point on level s1, E/W depending on s2
: eq2 ? (s1 > p ? -1 : 1) // idem
: s1 < p && s2 > p ? 2 // Point between s1 -> s2 --> E
: s2 < p && s1 > p ? -2 // Point between s2 -> s1 --> W
: 0;
}
};
/*!
\brief Within detection using winding rule
\ingroup strategies
\tparam Point \tparam_point
\tparam PointOfSegment \tparam_segment_point
\tparam SideStrategy Side strategy
\tparam CalculationType \tparam_calculation
\author Barend Gehrels
\note The implementation is inspired by terralib http://www.terralib.org (LGPL)
\note but totally revised afterwards, especially for cases on segments
\note Only dependant on "side", -> agnostic, suitable for spherical/latlong
\qbk{
[heading See also]
[link geometry.reference.algorithms.within.within_3_with_strategy within (with strategy)]
}
*/
template
<
typename Point,
typename PointOfSegment = Point,
typename SideStrategy = typename strategy::side::services::default_strategy
<
typename cs_tag<Point>::type
>::type,
typename CalculationType = void
>
class winding
{
typedef typename select_calculation_type
<
Point,
PointOfSegment,
CalculationType
>::type calculation_type;
/*! subclass to keep state */
class counter
{
int m_count;
bool m_touches;
inline int code() const
{
return m_touches ? 0 : m_count == 0 ? -1 : 1;
}
public :
friend class winding;
template <typename P, typename CT, typename CST>
friend struct winding_check_touch;
inline counter()
: m_count(0)
, m_touches(false)
{}
};
static inline int check_segment(Point const& point,
PointOfSegment const& seg1, PointOfSegment const& seg2,
counter& state, bool& eq1, bool& eq2)
{
if (winding_check_touch<Point, calculation_type>
::apply(point, seg1, seg2, state, eq1, eq2))
{
return 0;
}
calculation_type const p = get<0>(point);
calculation_type const s1 = get<0>(seg1);
calculation_type const s2 = get<0>(seg2);
return winding_calculate_count<Point, calculation_type>
::apply(p, s1, s2, eq1, eq2);
}
public:
winding()
{}
explicit winding(SideStrategy const& side_strategy)
: m_side_strategy(side_strategy)
{}
// Typedefs and static methods to fulfill the concept
typedef Point point_type;
typedef PointOfSegment segment_point_type;
typedef counter state_type;
inline bool apply(Point const& point,
PointOfSegment const& s1, PointOfSegment const& s2,
counter& state) const
{
typedef typename cs_tag<Point>::type cs_t;
bool eq1 = false;
bool eq2 = false;
boost::ignore_unused(eq2);
int count = check_segment(point, s1, s2, state, eq1, eq2);
if (count != 0)
{
int side = 0;
if (count == 1 || count == -1)
{
side = winding_side_equal<cs_t>::apply(point, eq1 ? s1 : s2, count);
}
else // count == 2 || count == -2
{
// 1 left, -1 right
side = m_side_strategy.apply(s1, s2, point);
}
if (side == 0)
{
// Point is lying on segment
state.m_touches = true;
state.m_count = 0;
return false;
}
// Side is NEG for right, POS for left.
// The count is -2 for down, 2 for up (or -1/1)
// Side positive thus means UP and LEFTSIDE or DOWN and RIGHTSIDE
// See accompagnying figure (TODO)
if (side * count > 0)
{
state.m_count += count;
}
}
return ! state.m_touches;
}
static inline int result(counter const& state)
{
return state.code();
}
private:
SideStrategy m_side_strategy;
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename Point, typename Geometry, typename AnyTag>
struct default_strategy<Point, Geometry, point_tag, AnyTag, pointlike_tag, polygonal_tag, cartesian_tag, cartesian_tag>
{
typedef winding<Point, typename geometry::point_type<Geometry>::type> type;
};
template <typename Point, typename Geometry, typename AnyTag>
struct default_strategy<Point, Geometry, point_tag, AnyTag, pointlike_tag, polygonal_tag, spherical_tag, spherical_tag>
{
typedef winding<Point, typename geometry::point_type<Geometry>::type> type;
};
template <typename Point, typename Geometry, typename AnyTag>
struct default_strategy<Point, Geometry, point_tag, AnyTag, pointlike_tag, linear_tag, cartesian_tag, cartesian_tag>
{
typedef winding<Point, typename geometry::point_type<Geometry>::type> type;
};
template <typename Point, typename Geometry, typename AnyTag>
struct default_strategy<Point, Geometry, point_tag, AnyTag, pointlike_tag, linear_tag, spherical_tag, spherical_tag>
{
typedef winding<Point, typename geometry::point_type<Geometry>::type> type;
};
} // namespace services
#endif
}} // namespace strategy::within
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace strategy { namespace covered_by { namespace services
{
template <typename Point, typename Geometry, typename AnyTag>
struct default_strategy<Point, Geometry, point_tag, AnyTag, pointlike_tag, polygonal_tag, cartesian_tag, cartesian_tag>
{
typedef strategy::within::winding<Point, typename geometry::point_type<Geometry>::type> type;
};
template <typename Point, typename Geometry, typename AnyTag>
struct default_strategy<Point, Geometry, point_tag, AnyTag, pointlike_tag, polygonal_tag, spherical_tag, spherical_tag>
{
typedef strategy::within::winding<Point, typename geometry::point_type<Geometry>::type> type;
};
template <typename Point, typename Geometry, typename AnyTag>
struct default_strategy<Point, Geometry, point_tag, AnyTag, pointlike_tag, linear_tag, cartesian_tag, cartesian_tag>
{
typedef strategy::within::winding<Point, typename geometry::point_type<Geometry>::type> type;
};
template <typename Point, typename Geometry, typename AnyTag>
struct default_strategy<Point, Geometry, point_tag, AnyTag, pointlike_tag, linear_tag, spherical_tag, spherical_tag>
{
typedef strategy::within::winding<Point, typename geometry::point_type<Geometry>::type> type;
};
}}} // namespace strategy::covered_by::services
#endif
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POLY_WINDING_HPP
@@ -0,0 +1,321 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 1995, 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 1995 Maarten Hilferink, Amsterdam, the Netherlands
// This file was modified by Oracle on 2015.
// Modifications copyright (c) 2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGY_AGNOSTIC_SIMPLIFY_DOUGLAS_PEUCKER_HPP
#define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_SIMPLIFY_DOUGLAS_PEUCKER_HPP
#include <cstddef>
#ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
#include <iostream>
#endif
#include <vector>
#include <boost/range.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/strategies/distance.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
#include <boost/geometry/io/dsv/write.hpp>
#endif
namespace boost { namespace geometry
{
namespace strategy { namespace simplify
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
/*!
\brief Small wrapper around a point, with an extra member "included"
\details
It has a const-reference to the original point (so no copy here)
\tparam the enclosed point type
*/
template<typename Point>
struct douglas_peucker_point
{
Point const& p;
bool included;
inline douglas_peucker_point(Point const& ap)
: p(ap)
, included(false)
{}
// Necessary for proper compilation
inline douglas_peucker_point<Point> operator=(douglas_peucker_point<Point> const& )
{
return douglas_peucker_point<Point>(*this);
}
};
template
<
typename Point,
typename PointDistanceStrategy,
typename LessCompare
= std::less
<
typename strategy::distance::services::return_type
<
PointDistanceStrategy,
Point, Point
>::type
>
>
class douglas_peucker
: LessCompare // for empty base optimization
{
public :
// See also ticket 5954 https://svn.boost.org/trac/boost/ticket/5954
// Comparable is currently not possible here because it has to be compared to the squared of max_distance, and more.
// For now we have to take the real distance.
typedef PointDistanceStrategy distance_strategy_type;
// typedef typename strategy::distance::services::comparable_type<PointDistanceStrategy>::type distance_strategy_type;
typedef typename strategy::distance::services::return_type
<
distance_strategy_type,
Point, Point
>::type distance_type;
douglas_peucker()
{}
douglas_peucker(LessCompare const& less_compare)
: LessCompare(less_compare)
{}
private :
typedef detail::douglas_peucker_point<Point> dp_point_type;
typedef typename std::vector<dp_point_type>::iterator iterator_type;
LessCompare const& less() const
{
return *this;
}
inline void consider(iterator_type begin,
iterator_type end,
distance_type const& max_dist,
int& n,
distance_strategy_type const& ps_distance_strategy) const
{
std::size_t size = end - begin;
// size must be at least 3
// because we want to consider a candidate point in between
if (size <= 2)
{
#ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
if (begin != end)
{
std::cout << "ignore between " << dsv(begin->p)
<< " and " << dsv((end - 1)->p)
<< " size=" << size << std::endl;
}
std::cout << "return because size=" << size << std::endl;
#endif
return;
}
iterator_type last = end - 1;
#ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
std::cout << "find between " << dsv(begin->p)
<< " and " << dsv(last->p)
<< " size=" << size << std::endl;
#endif
// Find most far point, compare to the current segment
//geometry::segment<Point const> s(begin->p, last->p);
distance_type md(-1.0); // any value < 0
iterator_type candidate;
for(iterator_type it = begin + 1; it != last; ++it)
{
distance_type dist = ps_distance_strategy.apply(it->p, begin->p, last->p);
#ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
std::cout << "consider " << dsv(it->p)
<< " at " << double(dist)
<< ((dist > max_dist) ? " maybe" : " no")
<< std::endl;
#endif
if ( less()(md, dist) )
{
md = dist;
candidate = it;
}
}
// If a point is found, set the include flag
// and handle segments in between recursively
if ( less()(max_dist, md) )
{
#ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
std::cout << "use " << dsv(candidate->p) << std::endl;
#endif
candidate->included = true;
n++;
consider(begin, candidate + 1, max_dist, n, ps_distance_strategy);
consider(candidate, end, max_dist, n, ps_distance_strategy);
}
}
public :
template <typename Range, typename OutputIterator>
inline OutputIterator apply(Range const& range,
OutputIterator out,
distance_type max_distance) const
{
#ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
std::cout << "max distance: " << max_distance
<< std::endl << std::endl;
#endif
distance_strategy_type strategy;
// Copy coordinates, a vector of references to all points
std::vector<dp_point_type> ref_candidates(boost::begin(range),
boost::end(range));
// Include first and last point of line,
// they are always part of the line
int n = 2;
ref_candidates.front().included = true;
ref_candidates.back().included = true;
// Get points, recursively, including them if they are further away
// than the specified distance
consider(boost::begin(ref_candidates), boost::end(ref_candidates), max_distance, n, strategy);
// Copy included elements to the output
for(typename std::vector<dp_point_type>::const_iterator it
= boost::begin(ref_candidates);
it != boost::end(ref_candidates);
++it)
{
if (it->included)
{
// copy-coordinates does not work because OutputIterator
// does not model Point (??)
//geometry::convert(it->p, *out);
*out = it->p;
out++;
}
}
return out;
}
};
}
#endif // DOXYGEN_NO_DETAIL
/*!
\brief Implements the simplify algorithm.
\ingroup strategies
\details The douglas_peucker strategy simplifies a linestring, ring or
vector of points using the well-known Douglas-Peucker algorithm.
\tparam Point the point type
\tparam PointDistanceStrategy point-segment distance strategy to be used
\note This strategy uses itself a point-segment-distance strategy which
can be specified
\author Barend and Maarten, 1995/1996
\author Barend, revised for Generic Geometry Library, 2008
*/
/*
For the algorithm, see for example:
- http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
- http://www2.dcs.hull.ac.uk/CISRG/projects/Royal-Inst/demos/dp.html
*/
template
<
typename Point,
typename PointDistanceStrategy
>
class douglas_peucker
{
public :
typedef PointDistanceStrategy distance_strategy_type;
typedef typename detail::douglas_peucker
<
Point,
PointDistanceStrategy
>::distance_type distance_type;
template <typename Range, typename OutputIterator>
static inline OutputIterator apply(Range const& range,
OutputIterator out,
distance_type const& max_distance)
{
namespace services = strategy::distance::services;
typedef typename services::comparable_type
<
PointDistanceStrategy
>::type comparable_distance_strategy_type;
return detail::douglas_peucker
<
Point, comparable_distance_strategy_type
>().apply(range, out,
services::result_from_distance
<
comparable_distance_strategy_type, Point, Point
>::apply(comparable_distance_strategy_type(),
max_distance)
);
}
};
}} // namespace strategy::simplify
namespace traits {
template <typename P>
struct point_type<geometry::strategy::simplify::detail::douglas_peucker_point<P> >
{
typedef P type;
};
} // namespace traits
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGY_AGNOSTIC_SIMPLIFY_DOUGLAS_PEUCKER_HPP
@@ -0,0 +1,50 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_AREA_HPP
#define BOOST_GEOMETRY_STRATEGIES_AREA_HPP
#include <boost/mpl/assert.hpp>
#include <boost/geometry/strategies/tags.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace area { namespace services
{
/*!
\brief Traits class binding a default area strategy to a coordinate system
\ingroup area
\tparam Tag tag of coordinate system
\tparam PointOfSegment point-type
*/
template <typename Tag, typename PointOfSegment>
struct default_strategy
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_IMPLEMENTED_FOR_THIS_POINT_TYPE
, (types<PointOfSegment>)
);
};
}}} // namespace strategy::area::services
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_AREA_HPP
@@ -0,0 +1,44 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2016-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fisikopoulos, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_AZIMUTH_HPP
#define BOOST_GEOMETRY_STRATEGIES_AZIMUTH_HPP
#include <boost/mpl/assert.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace azimuth { namespace services
{
/*!
\brief Traits class binding a default azimuth strategy to a coordinate system
\ingroup util
\tparam CSTag tag of coordinate system
\tparam CalculationType \tparam_calculation
*/
template <typename CSTag, typename CalculationType = void>
struct default_strategy
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_IMPLEMENTED_FOR_THIS_TYPE
, (types<CSTag>)
);
};
}}} // namespace strategy::azimuth::services
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_AZIMUTH_HPP
@@ -0,0 +1,103 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_HPP
namespace boost { namespace geometry
{
namespace strategy { namespace buffer
{
/*
A Buffer-join strategy gets 4 input points.
On the two consecutive segments s1 and s2 (joining at vertex v):
The lines from parallel at s1, s2 (at buffer-distance) end/start
in two points perpendicular to the segments: p1 and p2.
These parallel lines interesct in point ip
(s2)
|
|
^
|
(p2) |(v)
* +----<--- (s1)
x(ip) *(p1)
So, in clockwise order:
v : vertex point
p1: perpendicular on left side of segment1<1> (perp1)
ip: intersection point
p2: perpendicular on left side of segment2<0> (perp2)
*/
/*!
\brief Enumerates options for side of buffer (left/right w.r.t. directed
segment)
\ingroup enum
\details Around a linestring, a buffer can be defined left or right.
Around a polygon, assumed clockwise internally,
a buffer is either on the left side (inflates the polygon), or on the
right side (deflates the polygon)
*/
enum buffer_side_selector { buffer_side_left, buffer_side_right };
/*!
\brief Enumerates types of pieces (parts of buffer) around geometries
\ingroup enum
*/
enum piece_type
{
buffered_segment,
buffered_join,
buffered_round_end,
buffered_flat_end,
buffered_point,
buffered_concave, // always on the inside
piece_type_unknown
};
/*!
\brief Enumerates types of joins
\ingroup enum
*/
enum join_selector
{
join_convex,
join_concave,
join_continue, // collinear, next segment touches previous segment
join_spike // collinear, with overlap, next segment goes back
};
/*!
\brief Enumerates types of result codes from buffer strategies
\ingroup enum
*/
enum result_code
{
result_normal,
result_error_numerical,
result_no_output
};
}} // namespace strategy::buffer
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_HPP
@@ -0,0 +1,152 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// This file was modified by Oracle on 2016, 2017.
// Modifications copyright (c) 2016-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_AREA_SURVEYOR_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_AREA_SURVEYOR_HPP
#include <boost/mpl/if.hpp>
//#include <boost/geometry/arithmetic/determinant.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/strategies/area.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace area
{
/*!
\brief Area calculation for cartesian points
\ingroup strategies
\details Calculates area using the Surveyor's formula, a well-known
triangulation algorithm
\tparam PointOfSegment \tparam_segment_point
\tparam CalculationType \tparam_calculation
\qbk{
[heading See also]
[link geometry.reference.algorithms.area.area_2_with_strategy area (with strategy)]
}
*/
template
<
typename PointOfSegment,
typename CalculationType = void
>
class surveyor
{
public :
// If user specified a calculation type, use that type,
// whatever it is and whatever the point-type is.
// Else, use the pointtype, but at least double
typedef typename
boost::mpl::if_c
<
boost::is_void<CalculationType>::type::value,
typename select_most_precise
<
typename coordinate_type<PointOfSegment>::type,
double
>::type,
CalculationType
>::type return_type;
private :
class summation
{
friend class surveyor;
return_type sum;
public :
inline summation() : sum(return_type())
{
// Strategy supports only 2D areas
assert_dimension<PointOfSegment, 2>();
}
inline return_type area() const
{
return_type result = sum;
return_type const two = 2;
result /= two;
return result;
}
};
public :
typedef summation state_type;
typedef PointOfSegment segment_point_type;
static inline void apply(PointOfSegment const& p1,
PointOfSegment const& p2,
summation& state)
{
// Below formulas are equivalent, however the two lower ones
// suffer less from accuracy loss for great values of coordinates.
// See: https://svn.boost.org/trac/boost/ticket/11928
// SUM += x2 * y1 - x1 * y2;
// state.sum += detail::determinant<return_type>(p2, p1);
// SUM += (x2 - x1) * (y2 + y1)
//state.sum += (return_type(get<0>(p2)) - return_type(get<0>(p1)))
// * (return_type(get<1>(p2)) + return_type(get<1>(p1)));
// SUM += (x1 + x2) * (y1 - y2)
state.sum += (return_type(get<0>(p1)) + return_type(get<0>(p2)))
* (return_type(get<1>(p1)) - return_type(get<1>(p2)));
}
static inline return_type result(summation const& state)
{
return state.area();
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename Point>
struct default_strategy<cartesian_tag, Point>
{
typedef strategy::area::surveyor<Point> type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::area
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_AREA_SURVEYOR_HPP
@@ -0,0 +1,49 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2016-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fisikopoulos, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_AZIMUTH_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_AZIMUTH_HPP
#include <boost/geometry/core/tags.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace azimuth
{
template
<
typename CalculationType = void
>
class cartesian
{};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename CalculationType>
struct default_strategy<cartesian_tag, CalculationType>
{
typedef strategy::azimuth::cartesian<CalculationType> type;
};
}
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::azimuth
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_AZIMUTH_HPP
@@ -0,0 +1,311 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2015, 2016, 2017.
// Modifications copyright (c) 2016-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BOX_IN_BOX_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BOX_IN_BOX_HPP
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/within.hpp>
#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
namespace boost { namespace geometry { namespace strategy
{
namespace within
{
struct box_within_coord
{
template <typename BoxContainedValue, typename BoxContainingValue>
static inline bool apply(BoxContainedValue const& bed_min,
BoxContainedValue const& bed_max,
BoxContainingValue const& bing_min,
BoxContainingValue const& bing_max)
{
return bing_min <= bed_min && bed_max <= bing_max // contained in containing
&& bed_min < bed_max; // interiors overlap
}
};
struct box_covered_by_coord
{
template <typename BoxContainedValue, typename BoxContainingValue>
static inline bool apply(BoxContainedValue const& bed_min,
BoxContainedValue const& bed_max,
BoxContainingValue const& bing_min,
BoxContainingValue const& bing_max)
{
return bed_min >= bing_min && bed_max <= bing_max;
}
};
template <typename Geometry, std::size_t Dimension, typename CSTag>
struct box_within_range
: box_within_coord
{};
template <typename Geometry, std::size_t Dimension, typename CSTag>
struct box_covered_by_range
: box_covered_by_coord
{};
struct box_within_longitude_diff
{
template <typename CalcT>
static inline bool apply(CalcT const& diff_ed)
{
return diff_ed > CalcT(0);
}
};
struct box_covered_by_longitude_diff
{
template <typename CalcT>
static inline bool apply(CalcT const&)
{
return true;
}
};
template <typename Geometry,
typename CoordCheck,
typename InteriorCheck>
struct box_longitude_range
{
template <typename BoxContainedValue, typename BoxContainingValue>
static inline bool apply(BoxContainedValue const& bed_min,
BoxContainedValue const& bed_max,
BoxContainingValue const& bing_min,
BoxContainingValue const& bing_max)
{
typedef typename select_most_precise
<
BoxContainedValue,
BoxContainingValue
>::type calc_t;
typedef typename coordinate_system<Geometry>::type::units units_t;
typedef math::detail::constants_on_spheroid<calc_t, units_t> constants;
if (CoordCheck::apply(bed_min, bed_max, bing_min, bing_max))
{
return true;
}
// min <= max <=> diff >= 0
calc_t const diff_ed = bed_max - bed_min;
calc_t const diff_ing = bing_max - bing_min;
// if containing covers the whole globe it contains all
if (diff_ing >= constants::period())
{
return true;
}
// if containing is smaller it cannot contain
// and check interior (within vs covered_by)
if (diff_ing < diff_ed || ! InteriorCheck::apply(diff_ed))
{
return false;
}
// calculate positive longitude translation with bing_min as origin
calc_t const diff_min = math::longitude_distance_unsigned<units_t>(bing_min, bed_min);
// max of contained translated into the containing origin must be lesser than max of containing
return bing_min + diff_min + diff_ed <= bing_max
/*|| bing_max - diff_min - diff_ed >= bing_min*/;
}
};
// spherical_equatorial_tag, spherical_polar_tag and geographic_cat are casted to spherical_tag
template <typename Geometry>
struct box_within_range<Geometry, 0, spherical_tag>
: box_longitude_range<Geometry, box_within_coord, box_within_longitude_diff>
{};
template <typename Geometry>
struct box_covered_by_range<Geometry, 0, spherical_tag>
: box_longitude_range<Geometry, box_covered_by_coord, box_covered_by_longitude_diff>
{};
template
<
template <typename, std::size_t, typename> class SubStrategy,
typename Box1,
typename Box2,
std::size_t Dimension,
std::size_t DimensionCount
>
struct relate_box_box_loop
{
static inline bool apply(Box1 const& b_contained, Box2 const& b_containing)
{
assert_dimension_equal<Box1, Box2>();
typedef typename tag_cast<typename cs_tag<Box1>::type, spherical_tag>::type cs_tag_t;
if (! SubStrategy<Box1, Dimension, cs_tag_t>::apply(
get<min_corner, Dimension>(b_contained),
get<max_corner, Dimension>(b_contained),
get<min_corner, Dimension>(b_containing),
get<max_corner, Dimension>(b_containing)
)
)
{
return false;
}
return relate_box_box_loop
<
SubStrategy,
Box1, Box2,
Dimension + 1, DimensionCount
>::apply(b_contained, b_containing);
}
};
template
<
template <typename, std::size_t, typename> class SubStrategy,
typename Box1,
typename Box2,
std::size_t DimensionCount
>
struct relate_box_box_loop<SubStrategy, Box1, Box2, DimensionCount, DimensionCount>
{
static inline bool apply(Box1 const& , Box2 const& )
{
return true;
}
};
template
<
typename Box1,
typename Box2,
template <typename, std::size_t, typename> class SubStrategy = box_within_range
>
struct box_in_box
{
static inline bool apply(Box1 const& box1, Box2 const& box2)
{
return relate_box_box_loop
<
SubStrategy,
Box1, Box2, 0, dimension<Box1>::type::value
>::apply(box1, box2);
}
};
} // namespace within
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace within { namespace services
{
template <typename BoxContained, typename BoxContaining>
struct default_strategy
<
BoxContained, BoxContaining,
box_tag, box_tag,
areal_tag, areal_tag,
cartesian_tag, cartesian_tag
>
{
typedef within::box_in_box<BoxContained, BoxContaining> type;
};
// spherical_equatorial_tag, spherical_polar_tag and geographic_cat are casted to spherical_tag
template <typename BoxContained, typename BoxContaining>
struct default_strategy
<
BoxContained, BoxContaining,
box_tag, box_tag,
areal_tag, areal_tag,
spherical_tag, spherical_tag
>
{
typedef within::box_in_box<BoxContained, BoxContaining> type;
};
}} // namespace within::services
namespace covered_by { namespace services
{
template <typename BoxContained, typename BoxContaining>
struct default_strategy
<
BoxContained, BoxContaining,
box_tag, box_tag,
areal_tag, areal_tag,
cartesian_tag, cartesian_tag
>
{
typedef within::box_in_box
<
BoxContained, BoxContaining,
within::box_covered_by_range
> type;
};
// spherical_equatorial_tag, spherical_polar_tag and geographic_cat are casted to spherical_tag
template <typename BoxContained, typename BoxContaining>
struct default_strategy
<
BoxContained, BoxContaining,
box_tag, box_tag,
areal_tag, areal_tag,
spherical_tag, spherical_tag
>
{
typedef within::box_in_box
<
BoxContained, BoxContaining,
within::box_covered_by_range
> type;
};
}} // namespace covered_by::services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}}} // namespace boost::geometry::strategy
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BOX_IN_BOX_HPP
@@ -0,0 +1,112 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_FLAT_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_FLAT_HPP
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/strategies/tags.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
#include <boost/geometry/strategies/buffer.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace buffer
{
/*!
\brief Let the buffer create flat ends
\ingroup strategies
\details This strategy can be used as EndStrategy for the buffer algorithm.
It creates a flat end for each linestring-end. It can be applied
for (multi)linestrings. Also it is applicable for spikes in (multi)polygons.
This strategy is only applicable for Cartesian coordinate systems.
\qbk{
[heading Example]
[buffer_end_flat]
[heading Output]
[$img/strategies/buffer_end_flat.png]
[heading See also]
\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)]
\* [link geometry.reference.strategies.strategy_buffer_end_round end_round]
}
*/
class end_flat
{
public :
#ifndef DOXYGEN_SHOULD_SKIP_THIS
//! Fills output_range with a flat end
template <typename Point, typename RangeOut, typename DistanceStrategy>
inline void apply(Point const& penultimate_point,
Point const& perp_left_point,
Point const& ultimate_point,
Point const& perp_right_point,
buffer_side_selector side,
DistanceStrategy const& distance,
RangeOut& range_out) const
{
typedef typename coordinate_type<Point>::type coordinate_type;
typedef typename geometry::select_most_precise
<
coordinate_type,
double
>::type promoted_type;
promoted_type const dist_left = distance.apply(penultimate_point, ultimate_point, buffer_side_left);
promoted_type const dist_right = distance.apply(penultimate_point, ultimate_point, buffer_side_right);
bool reversed = (side == buffer_side_left && dist_right < 0 && -dist_right > dist_left)
|| (side == buffer_side_right && dist_left < 0 && -dist_left > dist_right)
;
if (reversed)
{
range_out.push_back(perp_right_point);
range_out.push_back(perp_left_point);
}
else
{
range_out.push_back(perp_left_point);
range_out.push_back(perp_right_point);
}
// Don't add the ultimate_point (endpoint of the linestring).
// The buffer might be generated completely at one side.
// In other cases it does no harm but is further useless
}
template <typename NumericType>
static inline NumericType max_distance(NumericType const& distance)
{
return distance;
}
//! Returns the piece_type (flat end)
static inline piece_type get_piece_type()
{
return buffered_flat_end;
}
#endif // DOXYGEN_SHOULD_SKIP_THIS
};
}} // namespace strategy::buffer
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_FLAT_HPP
@@ -0,0 +1,178 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2015 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2015.
// Modifications copyright (c) 2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_ROUND_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_ROUND_HPP
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/strategies/tags.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
#include <boost/geometry/strategies/buffer.hpp>
#include <boost/geometry/io/wkt/wkt.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace buffer
{
/*!
\brief Let the buffer create rounded ends
\ingroup strategies
\details This strategy can be used as EndStrategy for the buffer algorithm.
It creates a rounded end for each linestring-end. It can be applied
for (multi)linestrings. Also it is applicable for spikes in (multi)polygons.
This strategy is only applicable for Cartesian coordinate systems.
\qbk{
[heading Example]
[buffer_end_round]
[heading Output]
[$img/strategies/buffer_end_round.png]
[heading See also]
\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)]
\* [link geometry.reference.strategies.strategy_buffer_end_flat end_flat]
}
*/
class end_round
{
private :
std::size_t m_points_per_circle;
template
<
typename Point,
typename PromotedType,
typename DistanceType,
typename RangeOut
>
inline void generate_points(Point const& point,
PromotedType alpha, // by value
DistanceType const& buffer_distance,
RangeOut& range_out) const
{
PromotedType const two_pi = geometry::math::two_pi<PromotedType>();
std::size_t point_buffer_count = m_points_per_circle;
PromotedType const diff = two_pi / PromotedType(point_buffer_count);
// For half circle:
point_buffer_count /= 2;
point_buffer_count++;
for (std::size_t i = 0; i < point_buffer_count; i++, alpha -= diff)
{
typename boost::range_value<RangeOut>::type p;
set<0>(p, get<0>(point) + buffer_distance * cos(alpha));
set<1>(p, get<1>(point) + buffer_distance * sin(alpha));
range_out.push_back(p);
}
}
template <typename T, typename P1, typename P2>
static inline T calculate_angle(P1 const& from_point, P2 const& to_point)
{
typedef P1 vector_type;
vector_type v = from_point;
geometry::subtract_point(v, to_point);
return atan2(geometry::get<1>(v), geometry::get<0>(v));
}
public :
//! \brief Constructs the strategy
//! \param points_per_circle points which would be used for a full circle
//! (if points_per_circle is smaller than 4, it is internally set to 4)
explicit inline end_round(std::size_t points_per_circle = 90)
: m_points_per_circle((points_per_circle < 4u) ? 4u : points_per_circle)
{}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
//! Fills output_range with a flat end
template <typename Point, typename RangeOut, typename DistanceStrategy>
inline void apply(Point const& penultimate_point,
Point const& perp_left_point,
Point const& ultimate_point,
Point const& perp_right_point,
buffer_side_selector side,
DistanceStrategy const& distance,
RangeOut& range_out) const
{
typedef typename coordinate_type<Point>::type coordinate_type;
typedef typename geometry::select_most_precise
<
coordinate_type,
double
>::type promoted_type;
promoted_type const alpha = calculate_angle<promoted_type>(perp_left_point, ultimate_point);
promoted_type const dist_left = distance.apply(penultimate_point, ultimate_point, buffer_side_left);
promoted_type const dist_right = distance.apply(penultimate_point, ultimate_point, buffer_side_right);
if (geometry::math::equals(dist_left, dist_right))
{
generate_points(ultimate_point, alpha, dist_left, range_out);
}
else
{
promoted_type const two = 2.0;
promoted_type dist_half_diff = (dist_left - dist_right) / two;
if (side == buffer_side_right)
{
dist_half_diff = -dist_half_diff;
}
Point shifted_point;
set<0>(shifted_point, get<0>(ultimate_point) + dist_half_diff * cos(alpha));
set<1>(shifted_point, get<1>(ultimate_point) + dist_half_diff * sin(alpha));
generate_points(shifted_point, alpha, (dist_left + dist_right) / two, range_out);
}
if (m_points_per_circle % 2 == 1)
{
// For a half circle, if the number of points is not even,
// we should insert the end point too, to generate a full cap
range_out.push_back(perp_right_point);
}
}
template <typename NumericType>
static inline NumericType max_distance(NumericType const& distance)
{
return distance;
}
//! Returns the piece_type (flat end)
static inline piece_type get_piece_type()
{
return buffered_round_end;
}
#endif // DOXYGEN_SHOULD_SKIP_THIS
};
}} // namespace strategy::buffer
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_ROUND_HPP
@@ -0,0 +1,142 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_MITER_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_MITER_HPP
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/policies/compare.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
#include <boost/geometry/strategies/buffer.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace buffer
{
/*!
\brief Let the buffer create sharp corners
\ingroup strategies
\details This strategy can be used as JoinStrategy for the buffer algorithm.
It creates a sharp corners around each convex vertex. It can be applied
for (multi)linestrings and (multi)polygons.
If corners are sharp by themselves, the miters might become very long. Therefore
there is a limit (miter_limit), in terms of the used distance, which limits
their length. The miter is not changed to a bevel form (as done in some
other software), it is just adapted to the specified miter_limit but keeps
its miter form.
If the buffer distance is 5.0, and the miter limit is 2.0, generated points
will be located at a distance of at most 10.0 (2*5) units.
This strategy is only applicable for Cartesian coordinate systems.
\qbk{
[heading Example]
[buffer_join_miter]
[heading Output]
[$img/strategies/buffer_join_miter.png]
[heading See also]
\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)]
\* [link geometry.reference.strategies.strategy_buffer_join_round join_round]
}
*/
class join_miter
{
public:
//! \brief Constructs the strategy
//! \param miter_limit The miter limit, to avoid excessively long miters around sharp corners
explicit inline join_miter(double miter_limit = 5.0)
: m_miter_limit(valid_limit(miter_limit))
{}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
//! Fills output_range with a sharp shape around a vertex
template <typename Point, typename DistanceType, typename RangeOut>
inline bool apply(Point const& ip, Point const& vertex,
Point const& perp1, Point const& perp2,
DistanceType const& buffer_distance,
RangeOut& range_out) const
{
geometry::equal_to<Point> equals;
if (equals(ip, vertex))
{
return false;
}
if (equals(perp1, perp2))
{
return false;
}
typedef typename coordinate_type<Point>::type coordinate_type;
typedef typename geometry::select_most_precise
<
coordinate_type,
double
>::type promoted_type;
Point p = ip;
// Check the distance ip-vertex (= miter distance)
// (We calculate it manually (not using Pythagoras strategy) to reuse
// dx and dy)
coordinate_type const dx = get<0>(p) - get<0>(vertex);
coordinate_type const dy = get<1>(p) - get<1>(vertex);
promoted_type const distance = geometry::math::sqrt(dx * dx + dy * dy);
promoted_type const max_distance
= m_miter_limit * geometry::math::abs(buffer_distance);
if (distance > max_distance)
{
BOOST_GEOMETRY_ASSERT(distance != 0.0);
promoted_type const proportion = max_distance / distance;
set<0>(p, get<0>(vertex) + dx * proportion);
set<1>(p, get<1>(vertex) + dy * proportion);
}
range_out.push_back(perp1);
range_out.push_back(p);
range_out.push_back(perp2);
return true;
}
template <typename NumericType>
inline NumericType max_distance(NumericType const& distance) const
{
return distance * m_miter_limit;
}
#endif // DOXYGEN_SHOULD_SKIP_THIS
private :
double valid_limit(double miter_limit) const
{
if (miter_limit < 1.0)
{
// It should always exceed the buffer distance
miter_limit = 1.0;
}
return miter_limit;
}
double m_miter_limit;
};
}} // namespace strategy::buffer
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_MITER_HPP
@@ -0,0 +1,187 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2015 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2015.
// Modifications copyright (c) 2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_ROUND_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_ROUND_HPP
#include <algorithm>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/policies/compare.hpp>
#include <boost/geometry/strategies/buffer.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_WARN
#include <iostream>
#include <boost/geometry/io/wkt/wkt.hpp>
#endif
namespace boost { namespace geometry
{
namespace strategy { namespace buffer
{
/*!
\brief Let the buffer create rounded corners
\ingroup strategies
\details This strategy can be used as JoinStrategy for the buffer algorithm.
It creates a rounded corners around each convex vertex. It can be applied
for (multi)linestrings and (multi)polygons.
This strategy is only applicable for Cartesian coordinate systems.
\qbk{
[heading Example]
[buffer_join_round]
[heading Output]
[$img/strategies/buffer_join_round.png]
[heading See also]
\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)]
\* [link geometry.reference.strategies.strategy_buffer_join_miter join_miter]
}
*/
class join_round
{
public :
//! \brief Constructs the strategy
//! \param points_per_circle points which would be used for a full circle
explicit inline join_round(std::size_t points_per_circle = 90)
: m_points_per_circle(points_per_circle)
{}
private :
template
<
typename PromotedType,
typename Point,
typename DistanceType,
typename RangeOut
>
inline void generate_points(Point const& vertex,
Point const& perp1, Point const& perp2,
DistanceType const& buffer_distance,
RangeOut& range_out) const
{
PromotedType const dx1 = get<0>(perp1) - get<0>(vertex);
PromotedType const dy1 = get<1>(perp1) - get<1>(vertex);
PromotedType const dx2 = get<0>(perp2) - get<0>(vertex);
PromotedType const dy2 = get<1>(perp2) - get<1>(vertex);
PromotedType const two_pi = geometry::math::two_pi<PromotedType>();
PromotedType const angle1 = atan2(dy1, dx1);
PromotedType angle2 = atan2(dy2, dx2);
while (angle2 > angle1)
{
angle2 -= two_pi;
}
PromotedType const angle_diff = angle1 - angle2;
// Divide the angle into an integer amount of steps to make it
// visually correct also for a low number of points / circle
// If a full circle is divided into 3 parts (e.g. angle is 125),
// the one point in between must still be generated
// The calculation below:
// - generates 1 point in between for an angle of 125 based on 3 points
// - generates 0 points in between for an angle of 90 based on 4 points
std::size_t const n = (std::max)(static_cast<std::size_t>(
ceil(m_points_per_circle * angle_diff / two_pi)), std::size_t(1));
PromotedType const diff = angle_diff / static_cast<PromotedType>(n);
PromotedType a = angle1 - diff;
// Walk to n - 1 to avoid generating the last point
for (std::size_t i = 0; i < n - 1; i++, a -= diff)
{
Point p;
set<0>(p, get<0>(vertex) + buffer_distance * cos(a));
set<1>(p, get<1>(vertex) + buffer_distance * sin(a));
range_out.push_back(p);
}
}
public :
#ifndef DOXYGEN_SHOULD_SKIP_THIS
//! Fills output_range with a rounded shape around a vertex
template <typename Point, typename DistanceType, typename RangeOut>
inline bool apply(Point const& ip, Point const& vertex,
Point const& perp1, Point const& perp2,
DistanceType const& buffer_distance,
RangeOut& range_out) const
{
typedef typename coordinate_type<Point>::type coordinate_type;
typedef typename boost::range_value<RangeOut>::type output_point_type;
typedef typename geometry::select_most_precise
<
typename geometry::select_most_precise
<
coordinate_type,
typename geometry::coordinate_type<output_point_type>::type
>::type,
double
>::type promoted_type;
geometry::equal_to<Point> equals;
if (equals(perp1, perp2))
{
#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_WARN
std::cout << "Corner for equal points " << geometry::wkt(ip) << " " << geometry::wkt(perp1) << std::endl;
#endif
return false;
}
// Generate 'vectors'
coordinate_type vix = (get<0>(ip) - get<0>(vertex));
coordinate_type viy = (get<1>(ip) - get<1>(vertex));
promoted_type length_i = geometry::math::sqrt(vix * vix + viy * viy);
DistanceType const bd = geometry::math::abs(buffer_distance);
promoted_type prop = bd / length_i;
Point bp;
set<0>(bp, get<0>(vertex) + vix * prop);
set<1>(bp, get<1>(vertex) + viy * prop);
range_out.push_back(perp1);
generate_points<promoted_type>(vertex, perp1, perp2, bd, range_out);
range_out.push_back(perp2);
return true;
}
template <typename NumericType>
static inline NumericType max_distance(NumericType const& distance)
{
return distance;
}
#endif // DOXYGEN_SHOULD_SKIP_THIS
private :
std::size_t m_points_per_circle;
};
}} // namespace strategy::buffer
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_ROUND_HPP
@@ -0,0 +1,154 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_ROUND_BY_DIVIDE_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_ROUND_BY_DIVIDE_HPP
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/policies/compare.hpp>
#include <boost/geometry/strategies/buffer.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_WARN
#include <boost/geometry/io/wkt/wkt.hpp>
#endif
namespace boost { namespace geometry
{
namespace strategy { namespace buffer
{
class join_round_by_divide
{
public :
inline join_round_by_divide(std::size_t max_level = 4)
: m_max_level(max_level)
{}
template
<
typename PromotedType,
typename Point,
typename DistanceType,
typename RangeOut
>
inline void mid_points(Point const& vertex,
Point const& p1, Point const& p2,
DistanceType const& buffer_distance,
RangeOut& range_out,
std::size_t level = 1) const
{
typedef typename coordinate_type<Point>::type coordinate_type;
// Generate 'vectors'
coordinate_type const vp1_x = get<0>(p1) - get<0>(vertex);
coordinate_type const vp1_y = get<1>(p1) - get<1>(vertex);
coordinate_type const vp2_x = (get<0>(p2) - get<0>(vertex));
coordinate_type const vp2_y = (get<1>(p2) - get<1>(vertex));
// Average them to generate vector in between
coordinate_type const two = 2;
coordinate_type const v_x = (vp1_x + vp2_x) / two;
coordinate_type const v_y = (vp1_y + vp2_y) / two;
PromotedType const length2 = geometry::math::sqrt(v_x * v_x + v_y * v_y);
PromotedType prop = buffer_distance / length2;
Point mid_point;
set<0>(mid_point, get<0>(vertex) + v_x * prop);
set<1>(mid_point, get<1>(vertex) + v_y * prop);
if (level < m_max_level)
{
mid_points<PromotedType>(vertex, p1, mid_point, buffer_distance, range_out, level + 1);
}
range_out.push_back(mid_point);
if (level < m_max_level)
{
mid_points<PromotedType>(vertex, mid_point, p2, buffer_distance, range_out, level + 1);
}
}
template <typename Point, typename DistanceType, typename RangeOut>
inline bool apply(Point const& ip, Point const& vertex,
Point const& perp1, Point const& perp2,
DistanceType const& buffer_distance,
RangeOut& range_out) const
{
typedef typename coordinate_type<Point>::type coordinate_type;
typedef typename geometry::select_most_precise
<
coordinate_type,
double
>::type promoted_type;
geometry::equal_to<Point> equals;
if (equals(perp1, perp2))
{
#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_WARN
std::cout << "Corner for equal points " << geometry::wkt(ip) << " " << geometry::wkt(perp1) << std::endl;
#endif
return false;
}
// Generate 'vectors'
coordinate_type const vix = (get<0>(ip) - get<0>(vertex));
coordinate_type const viy = (get<1>(ip) - get<1>(vertex));
promoted_type const length_i = geometry::math::sqrt(vix * vix + viy * viy);
promoted_type const bd = geometry::math::abs(buffer_distance);
promoted_type prop = bd / length_i;
Point bp;
set<0>(bp, get<0>(vertex) + vix * prop);
set<1>(bp, get<1>(vertex) + viy * prop);
range_out.push_back(perp1);
if (m_max_level > 1)
{
mid_points<promoted_type>(vertex, perp1, bp, bd, range_out);
range_out.push_back(bp);
mid_points<promoted_type>(vertex, bp, perp2, bd, range_out);
}
else if (m_max_level == 1)
{
range_out.push_back(bp);
}
range_out.push_back(perp2);
return true;
}
template <typename NumericType>
static inline NumericType max_distance(NumericType const& distance)
{
return distance;
}
private :
std::size_t m_max_level;
};
}} // namespace strategy::buffer
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_ROUND_BY_DIVIDE_HPP
@@ -0,0 +1,115 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2015 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2015.
// Modifications copyright (c) 2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_POINT_CIRCLE_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_POINT_CIRCLE_HPP
#include <cstddef>
#include <boost/range.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/strategies/buffer.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace buffer
{
/*!
\brief Create a circular buffer around a point
\ingroup strategies
\details This strategy can be used as PointStrategy for the buffer algorithm.
It creates a circular buffer around a point. It can be applied
for points and multi_points, but also for a linestring (if it is degenerate,
so consisting of only one point) and for polygons (if it is degenerate).
This strategy is only applicable for Cartesian coordinate systems.
\qbk{
[heading Example]
[buffer_point_circle]
[heading Output]
[$img/strategies/buffer_point_circle.png]
[heading See also]
\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)]
\* [link geometry.reference.strategies.strategy_buffer_point_square point_square]
}
*/
class point_circle
{
public :
//! \brief Constructs the strategy
//! \param count number of points for the created circle (if count
//! is smaller than 3, count is internally set to 3)
explicit point_circle(std::size_t count = 90)
: m_count((count < 3u) ? 3u : count)
{}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
//! Fills output_range with a circle around point using distance_strategy
template
<
typename Point,
typename OutputRange,
typename DistanceStrategy
>
inline void apply(Point const& point,
DistanceStrategy const& distance_strategy,
OutputRange& output_range) const
{
typedef typename boost::range_value<OutputRange>::type output_point_type;
typedef typename geometry::select_most_precise
<
typename geometry::select_most_precise
<
typename geometry::coordinate_type<Point>::type,
typename geometry::coordinate_type<output_point_type>::type
>::type,
double
>::type promoted_type;
promoted_type const buffer_distance = distance_strategy.apply(point, point,
strategy::buffer::buffer_side_left);
promoted_type const two_pi = geometry::math::two_pi<promoted_type>();
promoted_type const diff = two_pi / promoted_type(m_count);
promoted_type a = 0;
for (std::size_t i = 0; i < m_count; i++, a -= diff)
{
output_point_type p;
set<0>(p, get<0>(point) + buffer_distance * cos(a));
set<1>(p, get<1>(point) + buffer_distance * sin(a));
output_range.push_back(p);
}
// Close it:
output_range.push_back(output_range.front());
}
#endif // DOXYGEN_SHOULD_SKIP_THIS
private :
std::size_t m_count;
};
}} // namespace strategy::buffer
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_POINT_CIRCLE_HPP
@@ -0,0 +1,109 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_POINT_SQUARE_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_POINT_SQUARE_HPP
#include <cstddef>
#include <boost/range.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/strategies/buffer.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace buffer
{
/*!
\brief Create a squared form buffer around a point
\ingroup strategies
\details This strategy can be used as PointStrategy for the buffer algorithm.
It creates a square from each point, where the point lies in the center.
It can be applied for points and multi_points, but also for a linestring (if it is degenerate,
so consisting of only one point) and for polygons (if it is degenerate).
This strategy is only applicable for Cartesian coordinate systems.
\qbk{
[heading Example]
[buffer_point_square]
[heading Output]
[$img/strategies/buffer_point_square.png]
[heading See also]
\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)]
\* [link geometry.reference.strategies.strategy_buffer_point_circle point_circle]
}
*/
class point_square
{
template
<
typename Point,
typename DistanceType,
typename OutputRange
>
inline void add_point(Point const& point,
DistanceType const& distance,
DistanceType const& x,
DistanceType const& y,
OutputRange& output_range) const
{
typename boost::range_value<OutputRange>::type p;
set<0>(p, get<0>(point) + x * distance);
set<1>(p, get<1>(point) + y * distance);
output_range.push_back(p);
}
template
<
typename Point,
typename DistanceType,
typename OutputRange
>
inline void add_points(Point const& point,
DistanceType const& distance,
OutputRange& output_range) const
{
add_point(point, distance, -1.0, -1.0, output_range);
add_point(point, distance, -1.0, +1.0, output_range);
add_point(point, distance, +1.0, +1.0, output_range);
add_point(point, distance, +1.0, -1.0, output_range);
// Close it:
output_range.push_back(output_range.front());
}
public :
#ifndef DOXYGEN_SHOULD_SKIP_THIS
//! Fills output_range with a square around point using distance_strategy
template
<
typename Point,
typename DistanceStrategy,
typename OutputRange
>
inline void apply(Point const& point,
DistanceStrategy const& distance_strategy,
OutputRange& output_range) const
{
add_points(point, distance_strategy.apply(point, point,
strategy::buffer::buffer_side_left), output_range);
}
#endif // DOXYGEN_SHOULD_SKIP_THIS
};
}} // namespace strategy::buffer
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_POINT_SQUARE_HPP
@@ -0,0 +1,136 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_SIDE_STRAIGHT_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_SIDE_STRAIGHT_HPP
#include <cstddef>
#include <boost/math/special_functions/fpclassify.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
#include <boost/geometry/strategies/buffer.hpp>
#include <boost/geometry/strategies/side.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace buffer
{
/*!
\brief Let the buffer use straight sides along segments (the default)
\ingroup strategies
\details This strategy can be used as SideStrategy for the buffer algorithm.
It is currently the only provided strategy for this purpose
\qbk{
[heading Example]
See the examples for other buffer strategies\, for example
[link geometry.reference.strategies.strategy_buffer_join_round join_round]
[heading See also]
\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)]
}
*/
class side_straight
{
public :
#ifndef DOXYGEN_SHOULD_SKIP_THIS
template
<
typename Point,
typename OutputRange,
typename DistanceStrategy
>
static inline result_code apply(
Point const& input_p1, Point const& input_p2,
buffer_side_selector side,
DistanceStrategy const& distance,
OutputRange& output_range)
{
typedef typename coordinate_type<Point>::type coordinate_type;
typedef typename geometry::select_most_precise
<
coordinate_type,
double
>::type promoted_type;
// Generate a block along (left or right of) the segment
// Simulate a vector d (dx,dy)
coordinate_type const dx = get<0>(input_p2) - get<0>(input_p1);
coordinate_type const dy = get<1>(input_p2) - get<1>(input_p1);
// For normalization [0,1] (=dot product d.d, sqrt)
promoted_type const length = geometry::math::sqrt(dx * dx + dy * dy);
if (! boost::math::isfinite(length))
{
// In case of coordinates differences of e.g. 1e300, length
// will overflow and we should not generate output
#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_WARN
std::cout << "Error in length calculation for points "
<< geometry::wkt(input_p1) << " " << geometry::wkt(input_p2)
<< " length: " << length << std::endl;
#endif
return result_error_numerical;
}
if (geometry::math::equals(length, 0))
{
// Coordinates are simplified and therefore most often not equal.
// But if simplify is skipped, or for lines with two
// equal points, length is 0 and we cannot generate output.
return result_no_output;
}
promoted_type const d = distance.apply(input_p1, input_p2, side);
// Generate the normalized perpendicular p, to the left (ccw)
promoted_type const px = -dy / length;
promoted_type const py = dx / length;
if (geometry::math::equals(px, 0)
&& geometry::math::equals(py, 0))
{
// This basically should not occur - because of the checks above.
// There are no unit tests triggering this condition
#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_WARN
std::cout << "Error in perpendicular calculation for points "
<< geometry::wkt(input_p1) << " " << geometry::wkt(input_p2)
<< " length: " << length
<< " distance: " << d
<< std::endl;
#endif
return result_no_output;
}
output_range.resize(2);
set<0>(output_range.front(), get<0>(input_p1) + px * d);
set<1>(output_range.front(), get<1>(input_p1) + py * d);
set<0>(output_range.back(), get<0>(input_p2) + px * d);
set<1>(output_range.back(), get<1>(input_p2) + py * d);
return result_normal;
}
#endif // DOXYGEN_SHOULD_SKIP_THIS
};
}} // namespace strategy::buffer
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_SIDE_STRAIGHT_HPP
@@ -0,0 +1,126 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// This file was modified by Oracle on 2015.
// Modifications copyright (c) 2015 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_AVERAGE_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_AVERAGE_HPP
#include <cstddef>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/strategies/centroid.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace centroid
{
/*!
\brief Centroid calculation taking average of points
\ingroup strategies
*/
template
<
typename PointCentroid,
typename Point = PointCentroid
>
class average
{
private :
/*! subclass to keep state */
class sum
{
friend class average;
std::size_t count;
PointCentroid centroid;
public :
inline sum()
: count(0)
{
assign_zero(centroid);
}
};
public :
typedef sum state_type;
typedef PointCentroid centroid_point_type;
typedef Point point_type;
static inline void apply(Point const& p, sum& state)
{
add_point(state.centroid, p);
state.count++;
}
static inline bool result(sum const& state, PointCentroid& centroid)
{
centroid = state.centroid;
if ( state.count > 0 )
{
divide_value(centroid, state.count);
return true;
}
return false;
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename Point, std::size_t DimensionCount, typename Geometry>
struct default_strategy
<
cartesian_tag,
pointlike_tag,
DimensionCount,
Point,
Geometry
>
{
typedef average
<
Point,
typename point_type<Geometry>::type
> type;
};
} // namespace services
#endif
}} // namespace strategy::centroid
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_AVERAGE_HPP
@@ -0,0 +1,258 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2015.
// Modifications copyright (c) 2015 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_BASHEIN_DETMER_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_BASHEIN_DETMER_HPP
#include <cstddef>
#include <boost/math/special_functions/fpclassify.hpp>
#include <boost/mpl/if.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/type_traits/is_void.hpp>
#include <boost/geometry/arithmetic/determinant.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/strategies/centroid.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
namespace boost { namespace geometry
{
// Note: when calling the namespace "centroid", it sometimes,
// somehow, in gcc, gives compilation problems (confusion with function centroid).
namespace strategy { namespace centroid
{
/*!
\brief Centroid calculation using algorithm Bashein / Detmer
\ingroup strategies
\details Calculates centroid using triangulation method published by
Bashein / Detmer
\tparam Point point type of centroid to calculate
\tparam PointOfSegment point type of segments, defaults to Point
\tparam CalculationType \tparam_calculation
\author Adapted from "Centroid of a Polygon" by
Gerard Bashein and Paul R. Detmer<em>,
in "Graphics Gems IV", Academic Press, 1994</em>
\qbk{
[heading See also]
[link geometry.reference.algorithms.centroid.centroid_3_with_strategy centroid (with strategy)]
}
*/
/*
\par Research notes
The algorithm gives the same results as Oracle and PostGIS but
differs from MySQL
(tried 5.0.21 / 5.0.45 / 5.0.51a / 5.1.23).
Without holes:
- this: POINT(4.06923363095238 1.65055803571429)
- geolib: POINT(4.07254 1.66819)
- MySQL: POINT(3.6636363636364 1.6272727272727)'
- PostGIS: POINT(4.06923363095238 1.65055803571429)
- Oracle: 4.06923363095238 1.65055803571429
- SQL Server: POINT(4.06923362245959 1.65055804168294)
Statements:
- \b MySQL/PostGIS: select AsText(Centroid(GeomFromText(
'POLYGON((2 1.3,2.4 1.7,2.8 1.8,3.4 1.2,3.7 1.6,3.4 2,4.1 3,5.3 2.6
,5.4 1.2,4.9 0.8,2.9 0.7,2 1.3))')))
- \b Oracle: select sdo_geom.sdo_centroid(sdo_geometry(2003, null, null,
sdo_elem_info_array(1, 1003, 1), sdo_ordinate_array(
2,1.3,2.4,1.7,2.8,1.8,3.4,1.2,3.7,1.6,3.4,2,4.1,3,5.3,2.6
,5.4,1.2,4.9,0.8,2.9,0.7,2,1.3))
, mdsys.sdo_dim_array(mdsys.sdo_dim_element('x',0,10,.00000005)
,mdsys.sdo_dim_element('y',0,10,.00000005)))
from dual
- \b SQL Server 2008: select geometry::STGeomFromText(
'POLYGON((2 1.3,2.4 1.7,2.8 1.8,3.4 1.2,3.7 1.6,3.4 2,4.1 3,5.3 2.6
,5.4 1.2,4.9 0.8,2.9 0.7,2 1.3))',0)
.STCentroid()
.STAsText()
With holes:
- this: POINT(4.04663 1.6349)
- geolib: POINT(4.04675 1.65735)
- MySQL: POINT(3.6090580503834 1.607573932092)
- PostGIS: POINT(4.0466265060241 1.63489959839357)
- Oracle: 4.0466265060241 1.63489959839357
- SQL Server: POINT(4.0466264962959677 1.6348996057331333)
Statements:
- \b MySQL/PostGIS: select AsText(Centroid(GeomFromText(
'POLYGON((2 1.3,2.4 1.7,2.8 1.8,3.4 1.2
,3.7 1.6,3.4 2,4.1 3,5.3 2.6,5.4 1.2,4.9 0.8,2.9 0.7,2 1.3)
,(4 2,4.2 1.4,4.8 1.9,4.4 2.2,4 2))')));
- \b Oracle: select sdo_geom.sdo_centroid(sdo_geometry(2003, null, null
, sdo_elem_info_array(1, 1003, 1, 25, 2003, 1)
, sdo_ordinate_array(2,1.3,2.4,1.7,2.8,1.8,3.4,1.2,3.7,1.6,3.4,
2,4.1,3,5.3,2.6,5.4,1.2,4.9,0.8,2.9,0.7,2,1.3,4,2, 4.2,1.4,
4.8,1.9, 4.4,2.2, 4,2))
, mdsys.sdo_dim_array(mdsys.sdo_dim_element('x',0,10,.00000005)
,mdsys.sdo_dim_element('y',0,10,.00000005)))
from dual
*/
template
<
typename Point,
typename PointOfSegment = Point,
typename CalculationType = void
>
class bashein_detmer
{
private :
// If user specified a calculation type, use that type,
// whatever it is and whatever the point-type(s) are.
// Else, use the most appropriate coordinate type
// of the two points, but at least double
typedef typename
boost::mpl::if_c
<
boost::is_void<CalculationType>::type::value,
typename select_most_precise
<
typename select_coordinate_type
<
Point,
PointOfSegment
>::type,
double
>::type,
CalculationType
>::type calculation_type;
/*! subclass to keep state */
class sums
{
friend class bashein_detmer;
std::size_t count;
calculation_type sum_a2;
calculation_type sum_x;
calculation_type sum_y;
public :
inline sums()
: count(0)
, sum_a2(calculation_type())
, sum_x(calculation_type())
, sum_y(calculation_type())
{}
};
public :
typedef sums state_type;
static inline void apply(PointOfSegment const& p1,
PointOfSegment const& p2, sums& state)
{
/* Algorithm:
For each segment:
begin
ai = x1 * y2 - x2 * y1;
sum_a2 += ai;
sum_x += ai * (x1 + x2);
sum_y += ai * (y1 + y2);
end
return POINT(sum_x / (3 * sum_a2), sum_y / (3 * sum_a2) )
*/
// Get coordinates and promote them to calculation_type
calculation_type const x1 = boost::numeric_cast<calculation_type>(get<0>(p1));
calculation_type const y1 = boost::numeric_cast<calculation_type>(get<1>(p1));
calculation_type const x2 = boost::numeric_cast<calculation_type>(get<0>(p2));
calculation_type const y2 = boost::numeric_cast<calculation_type>(get<1>(p2));
calculation_type const ai = geometry::detail::determinant<calculation_type>(p1, p2);
state.count++;
state.sum_a2 += ai;
state.sum_x += ai * (x1 + x2);
state.sum_y += ai * (y1 + y2);
}
static inline bool result(sums const& state, Point& centroid)
{
calculation_type const zero = calculation_type();
if (state.count > 0 && ! math::equals(state.sum_a2, zero))
{
calculation_type const v3 = 3;
calculation_type const a3 = v3 * state.sum_a2;
typedef typename geometry::coordinate_type
<
Point
>::type coordinate_type;
// Prevent NaN centroid coordinates
if (boost::math::isfinite(a3))
{
// NOTE: above calculation_type is checked, not the centroid coordinate_type
// which means that the centroid can still be filled with INF
// if e.g. calculation_type is double and centroid contains floats
set<0>(centroid,
boost::numeric_cast<coordinate_type>(state.sum_x / a3));
set<1>(centroid,
boost::numeric_cast<coordinate_type>(state.sum_y / a3));
return true;
}
}
return false;
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
// Register this strategy for rings and (multi)polygons, in two dimensions
template <typename Point, typename Geometry>
struct default_strategy<cartesian_tag, areal_tag, 2, Point, Geometry>
{
typedef bashein_detmer
<
Point,
typename point_type<Geometry>::type
> type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::centroid
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_BASHEIN_DETMER_HPP
@@ -0,0 +1,174 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2009-2015 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2015.
// Modifications copyright (c) 2015, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_WEIGHTED_LENGTH_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_WEIGHTED_LENGTH_HPP
#include <boost/math/special_functions/fpclassify.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/geometry/algorithms/detail/distance/interface.hpp>
#include <boost/geometry/algorithms/detail/distance/point_to_geometry.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/util/for_each_coordinate.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
#include <boost/geometry/strategies/centroid.hpp>
#include <boost/geometry/strategies/default_distance_result.hpp>
// Helper geometry
#include <boost/geometry/geometries/point.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace centroid
{
namespace detail
{
template <typename Type, std::size_t DimensionCount>
struct weighted_length_sums
{
typedef typename geometry::model::point
<
Type, DimensionCount,
cs::cartesian
> work_point;
Type length;
work_point average_sum;
inline weighted_length_sums()
: length(Type())
{
geometry::assign_zero(average_sum);
}
};
}
template
<
typename Point,
typename PointOfSegment = Point
>
class weighted_length
{
private :
typedef typename select_most_precise
<
typename default_distance_result<Point>::type,
typename default_distance_result<PointOfSegment>::type
>::type distance_type;
public :
typedef detail::weighted_length_sums
<
distance_type,
geometry::dimension<Point>::type::value
> state_type;
static inline void apply(PointOfSegment const& p1,
PointOfSegment const& p2, state_type& state)
{
distance_type const d = geometry::distance(p1, p2);
state.length += d;
typename state_type::work_point weighted_median;
geometry::assign_zero(weighted_median);
geometry::add_point(weighted_median, p1);
geometry::add_point(weighted_median, p2);
geometry::multiply_value(weighted_median, d/2);
geometry::add_point(state.average_sum, weighted_median);
}
static inline bool result(state_type const& state, Point& centroid)
{
distance_type const zero = distance_type();
if (! geometry::math::equals(state.length, zero)
&& boost::math::isfinite(state.length)) // Prevent NaN centroid coordinates
{
// NOTE: above distance_type is checked, not the centroid coordinate_type
// which means that the centroid can still be filled with INF
// if e.g. distance_type is double and centroid contains floats
geometry::for_each_coordinate(centroid, set_sum_div_length(state));
return true;
}
return false;
}
struct set_sum_div_length
{
state_type const& m_state;
set_sum_div_length(state_type const& state)
: m_state(state)
{}
template <typename Pt, std::size_t Dimension>
void apply(Pt & centroid) const
{
typedef typename geometry::coordinate_type<Pt>::type coordinate_type;
geometry::set<Dimension>(
centroid,
boost::numeric_cast<coordinate_type>(
geometry::get<Dimension>(m_state.average_sum) / m_state.length
)
);
}
};
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
// Register this strategy for linear geometries, in all dimensions
template <std::size_t N, typename Point, typename Geometry>
struct default_strategy
<
cartesian_tag,
linear_tag,
N,
Point,
Geometry
>
{
typedef weighted_length
<
Point,
typename point_type<Geometry>::type
> type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::centroid
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_WEIGHTED_LENGTH_HPP
@@ -0,0 +1,320 @@
// Boost.Geometry
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2013-2017.
// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISJOINT_SEGMENT_BOX_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISJOINT_SEGMENT_BOX_HPP
#include <cstddef>
#include <utility>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/calculation_type.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
#include <boost/geometry/strategies/disjoint.hpp>
namespace boost { namespace geometry { namespace strategy { namespace disjoint
{
namespace detail
{
template <std::size_t I>
struct compute_tmin_tmax_per_dim
{
template <typename SegmentPoint, typename Box, typename RelativeDistance>
static inline void apply(SegmentPoint const& p0,
SegmentPoint const& p1,
Box const& box,
RelativeDistance& ti_min,
RelativeDistance& ti_max,
RelativeDistance& diff)
{
typedef typename coordinate_type<Box>::type box_coordinate_type;
typedef typename coordinate_type
<
SegmentPoint
>::type point_coordinate_type;
RelativeDistance c_p0 = boost::numeric_cast
<
point_coordinate_type
>( geometry::get<I>(p0) );
RelativeDistance c_p1 = boost::numeric_cast
<
point_coordinate_type
>( geometry::get<I>(p1) );
RelativeDistance c_b_min = boost::numeric_cast
<
box_coordinate_type
>( geometry::get<geometry::min_corner, I>(box) );
RelativeDistance c_b_max = boost::numeric_cast
<
box_coordinate_type
>( geometry::get<geometry::max_corner, I>(box) );
if ( geometry::get<I>(p1) >= geometry::get<I>(p0) )
{
diff = c_p1 - c_p0;
ti_min = c_b_min - c_p0;
ti_max = c_b_max - c_p0;
}
else
{
diff = c_p0 - c_p1;
ti_min = c_p0 - c_b_max;
ti_max = c_p0 - c_b_min;
}
}
};
template
<
typename RelativeDistance,
typename SegmentPoint,
typename Box,
std::size_t I,
std::size_t Dimension
>
struct disjoint_segment_box_impl
{
template <typename RelativeDistancePair>
static inline bool apply(SegmentPoint const& p0,
SegmentPoint const& p1,
Box const& box,
RelativeDistancePair& t_min,
RelativeDistancePair& t_max)
{
RelativeDistance ti_min, ti_max, diff;
compute_tmin_tmax_per_dim<I>::apply(p0, p1, box, ti_min, ti_max, diff);
if ( geometry::math::equals(diff, 0) )
{
if ( (geometry::math::equals(t_min.second, 0)
&& t_min.first > ti_max)
||
(geometry::math::equals(t_max.second, 0)
&& t_max.first < ti_min)
||
(math::sign(ti_min) * math::sign(ti_max) > 0) )
{
return true;
}
}
RelativeDistance t_min_x_diff = t_min.first * diff;
RelativeDistance t_max_x_diff = t_max.first * diff;
if ( t_min_x_diff > ti_max * t_min.second
|| t_max_x_diff < ti_min * t_max.second )
{
return true;
}
if ( ti_min * t_min.second > t_min_x_diff )
{
t_min.first = ti_min;
t_min.second = diff;
}
if ( ti_max * t_max.second < t_max_x_diff )
{
t_max.first = ti_max;
t_max.second = diff;
}
if ( t_min.first > t_min.second || t_max.first < 0 )
{
return true;
}
return disjoint_segment_box_impl
<
RelativeDistance,
SegmentPoint,
Box,
I + 1,
Dimension
>::apply(p0, p1, box, t_min, t_max);
}
};
template
<
typename RelativeDistance,
typename SegmentPoint,
typename Box,
std::size_t Dimension
>
struct disjoint_segment_box_impl
<
RelativeDistance, SegmentPoint, Box, 0, Dimension
>
{
static inline bool apply(SegmentPoint const& p0,
SegmentPoint const& p1,
Box const& box)
{
std::pair<RelativeDistance, RelativeDistance> t_min, t_max;
RelativeDistance diff;
compute_tmin_tmax_per_dim<0>::apply(p0, p1, box,
t_min.first, t_max.first, diff);
if ( geometry::math::equals(diff, 0) )
{
if ( geometry::math::equals(t_min.first, 0) ) { t_min.first = -1; }
if ( geometry::math::equals(t_max.first, 0) ) { t_max.first = 1; }
if (math::sign(t_min.first) * math::sign(t_max.first) > 0)
{
return true;
}
}
if ( t_min.first > diff || t_max.first < 0 )
{
return true;
}
t_min.second = t_max.second = diff;
return disjoint_segment_box_impl
<
RelativeDistance, SegmentPoint, Box, 1, Dimension
>::apply(p0, p1, box, t_min, t_max);
}
};
template
<
typename RelativeDistance,
typename SegmentPoint,
typename Box,
std::size_t Dimension
>
struct disjoint_segment_box_impl
<
RelativeDistance, SegmentPoint, Box, Dimension, Dimension
>
{
template <typename RelativeDistancePair>
static inline bool apply(SegmentPoint const&, SegmentPoint const&,
Box const&,
RelativeDistancePair&, RelativeDistancePair&)
{
return false;
}
};
} // namespace detail
// NOTE: This may be temporary place for this or corresponding strategy
// It seems to be more appropriate to implement the opposite of it
// e.g. intersection::segment_box because in disjoint() algorithm
// other strategies that are used are intersection and covered_by strategies.
struct segment_box
{
template <typename Segment, typename Box>
struct point_in_geometry_strategy
: services::default_strategy
<
typename point_type<Segment>::type,
Box
>
{};
template <typename Segment, typename Box>
static inline typename point_in_geometry_strategy<Segment, Box>::type
get_point_in_geometry_strategy()
{
typedef typename point_in_geometry_strategy<Segment, Box>::type strategy_type;
return strategy_type();
}
template <typename Segment, typename Box>
static inline bool apply(Segment const& segment, Box const& box)
{
assert_dimension_equal<Segment, Box>();
typedef typename util::calculation_type::geometric::binary
<
Segment, Box, void
>::type relative_distance_type;
typedef typename point_type<Segment>::type segment_point_type;
segment_point_type p0, p1;
geometry::detail::assign_point_from_index<0>(segment, p0);
geometry::detail::assign_point_from_index<1>(segment, p1);
return detail::disjoint_segment_box_impl
<
relative_distance_type, segment_point_type, Box,
0, dimension<Box>::value
>::apply(p0, p1, box);
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
// Currently used in all coordinate systems
template <typename Linear, typename Box, typename LinearTag>
struct default_strategy<Linear, Box, LinearTag, box_tag, 1, 2>
{
typedef disjoint::segment_box type;
};
template <typename Box, typename Linear, typename LinearTag>
struct default_strategy<Box, Linear, box_tag, LinearTag, 2, 1>
{
typedef disjoint::segment_box type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}}}} // namespace boost::geometry::strategy::disjoint
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISJOINT_SEGMENT_BOX_HPP
@@ -0,0 +1,278 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2008-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PROJECTED_POINT_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PROJECTED_POINT_HPP
#include <boost/concept_check.hpp>
#include <boost/mpl/if.hpp>
#include <boost/type_traits/is_void.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/arithmetic/dot_product.hpp>
#include <boost/geometry/strategies/tags.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/default_distance_result.hpp>
#include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
// Helper geometry (projected point on line)
#include <boost/geometry/geometries/point.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace distance
{
/*!
\brief Strategy for distance point to segment
\ingroup strategies
\details Calculates distance using projected-point method, and (optionally) Pythagoras
\author Adapted from: http://geometryalgorithms.com/Archive/algorithm_0102/algorithm_0102.htm
\tparam CalculationType \tparam_calculation
\tparam Strategy underlying point-point distance strategy
\par Concepts for Strategy:
- cartesian_distance operator(Point,Point)
\note If the Strategy is a "comparable::pythagoras", this strategy
automatically is a comparable projected_point strategy (so without sqrt)
\qbk{
[heading See also]
[link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)]
}
*/
template
<
typename CalculationType = void,
typename Strategy = pythagoras<CalculationType>
>
class projected_point
{
public :
// The three typedefs below are necessary to calculate distances
// from segments defined in integer coordinates.
// Integer coordinates can still result in FP distances.
// There is a division, which must be represented in FP.
// So promote.
template <typename Point, typename PointOfSegment>
struct calculation_type
: promote_floating_point
<
typename strategy::distance::services::return_type
<
Strategy,
Point,
PointOfSegment
>::type
>
{};
public :
template <typename Point, typename PointOfSegment>
inline typename calculation_type<Point, PointOfSegment>::type
apply(Point const& p, PointOfSegment const& p1, PointOfSegment const& p2) const
{
assert_dimension_equal<Point, PointOfSegment>();
typedef typename calculation_type<Point, PointOfSegment>::type calculation_type;
// A projected point of points in Integer coordinates must be able to be
// represented in FP.
typedef model::point
<
calculation_type,
dimension<PointOfSegment>::value,
typename coordinate_system<PointOfSegment>::type
> fp_point_type;
// For convenience
typedef fp_point_type fp_vector_type;
/*
Algorithm [p: (px,py), p1: (x1,y1), p2: (x2,y2)]
VECTOR v(x2 - x1, y2 - y1)
VECTOR w(px - x1, py - y1)
c1 = w . v
c2 = v . v
b = c1 / c2
RETURN POINT(x1 + b * vx, y1 + b * vy)
*/
// v is multiplied below with a (possibly) FP-value, so should be in FP
// For consistency we define w also in FP
fp_vector_type v, w, projected;
geometry::convert(p2, v);
geometry::convert(p, w);
geometry::convert(p1, projected);
subtract_point(v, projected);
subtract_point(w, projected);
Strategy strategy;
boost::ignore_unused_variable_warning(strategy);
calculation_type const zero = calculation_type();
calculation_type const c1 = dot_product(w, v);
if (c1 <= zero)
{
return strategy.apply(p, p1);
}
calculation_type const c2 = dot_product(v, v);
if (c2 <= c1)
{
return strategy.apply(p, p2);
}
// See above, c1 > 0 AND c2 > c1 so: c2 != 0
calculation_type const b = c1 / c2;
multiply_value(v, b);
add_point(projected, v);
return strategy.apply(p, projected);
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename CalculationType, typename Strategy>
struct tag<projected_point<CalculationType, Strategy> >
{
typedef strategy_tag_distance_point_segment type;
};
template <typename CalculationType, typename Strategy, typename P, typename PS>
struct return_type<projected_point<CalculationType, Strategy>, P, PS>
: projected_point<CalculationType, Strategy>::template calculation_type<P, PS>
{};
template <typename CalculationType, typename Strategy>
struct comparable_type<projected_point<CalculationType, Strategy> >
{
// Define a projected_point strategy with its underlying point-point-strategy
// being comparable
typedef projected_point
<
CalculationType,
typename comparable_type<Strategy>::type
> type;
};
template <typename CalculationType, typename Strategy>
struct get_comparable<projected_point<CalculationType, Strategy> >
{
typedef typename comparable_type
<
projected_point<CalculationType, Strategy>
>::type comparable_type;
public :
static inline comparable_type apply(projected_point<CalculationType, Strategy> const& )
{
return comparable_type();
}
};
template <typename CalculationType, typename Strategy, typename P, typename PS>
struct result_from_distance<projected_point<CalculationType, Strategy>, P, PS>
{
private :
typedef typename return_type<projected_point<CalculationType, Strategy>, P, PS>::type return_type;
public :
template <typename T>
static inline return_type apply(projected_point<CalculationType, Strategy> const& , T const& value)
{
Strategy s;
return result_from_distance<Strategy, P, PS>::apply(s, value);
}
};
// Get default-strategy for point-segment distance calculation
// while still have the possibility to specify point-point distance strategy (PPS)
// It is used in algorithms/distance.hpp where users specify PPS for distance
// of point-to-segment or point-to-linestring.
// Convenient for geographic coordinate systems especially.
template <typename Point, typename PointOfSegment, typename Strategy>
struct default_strategy
<
point_tag, segment_tag, Point, PointOfSegment,
cartesian_tag, cartesian_tag, Strategy
>
{
typedef strategy::distance::projected_point
<
void,
typename boost::mpl::if_
<
boost::is_void<Strategy>,
typename default_strategy
<
point_tag, point_tag, Point, PointOfSegment,
cartesian_tag, cartesian_tag
>::type,
Strategy
>::type
> type;
};
template <typename PointOfSegment, typename Point, typename Strategy>
struct default_strategy
<
segment_tag, point_tag, PointOfSegment, Point,
cartesian_tag, cartesian_tag, Strategy
>
{
typedef typename default_strategy
<
point_tag, segment_tag, Point, PointOfSegment,
cartesian_tag, cartesian_tag, Strategy
>::type type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::distance
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PROJECTED_POINT_HPP
@@ -0,0 +1,314 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2008-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PROJECTED_POINT_AX_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PROJECTED_POINT_AX_HPP
#include <algorithm>
#include <boost/concept_check.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/arithmetic/dot_product.hpp>
#include <boost/geometry/strategies/tags.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/default_distance_result.hpp>
#include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp>
#include <boost/geometry/strategies/cartesian/distance_projected_point.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
// Helper geometry (projected point on line)
#include <boost/geometry/geometries/point.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace distance
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template <typename T>
struct projected_point_ax_result
{
typedef T value_type;
projected_point_ax_result(T const& c = T(0))
: atd(c), xtd(c)
{}
projected_point_ax_result(T const& a, T const& x)
: atd(a), xtd(x)
{}
friend inline bool operator<(projected_point_ax_result const& left,
projected_point_ax_result const& right)
{
return left.xtd < right.xtd || left.atd < right.atd;
}
T atd, xtd;
};
// This less-comparator may be used as a parameter of detail::douglas_peucker.
// In this simplify strategy distances are compared in 2 places
// 1. to choose the furthest candidate (md < dist)
// 2. to check if the candidate is further than max_distance (max_distance < md)
template <typename Distance>
class projected_point_ax_less
{
public:
projected_point_ax_less(Distance const& max_distance)
: m_max_distance(max_distance)
{}
inline bool operator()(Distance const& left, Distance const& right) const
{
//return left.xtd < right.xtd && right.atd < m_max_distance.atd;
typedef typename Distance::value_type value_type;
value_type const lx = left.xtd > m_max_distance.xtd ? left.xtd - m_max_distance.xtd : 0;
value_type const rx = right.xtd > m_max_distance.xtd ? right.xtd - m_max_distance.xtd : 0;
value_type const la = left.atd > m_max_distance.atd ? left.atd - m_max_distance.atd : 0;
value_type const ra = right.atd > m_max_distance.atd ? right.atd - m_max_distance.atd : 0;
value_type const l = (std::max)(lx, la);
value_type const r = (std::max)(rx, ra);
return l < r;
}
private:
Distance const& m_max_distance;
};
// This strategy returns 2-component Point/Segment distance.
// The ATD (along track distance) is parallel to the Segment
// and is a distance between Point projected into a line defined by a Segment and the nearest Segment's endpoint.
// If the projected Point intersects the Segment the ATD is equal to 0.
// The XTD (cross track distance) is perpendicular to the Segment
// and is a distance between input Point and its projection.
// If the Segment has length equal to 0, ATD and XTD has value equal
// to the distance between the input Point and one of the Segment's endpoints.
//
// p3 p4
// ^ 7
// | /
// p1<-----e========e----->p2
//
// p1: atd=D, xtd=0
// p2: atd=D, xtd=0
// p3: atd=0, xtd=D
// p4: atd=D/2, xtd=D
template
<
typename CalculationType = void,
typename Strategy = pythagoras<CalculationType>
>
class projected_point_ax
{
public :
template <typename Point, typename PointOfSegment>
struct calculation_type
: public projected_point<CalculationType, Strategy>
::template calculation_type<Point, PointOfSegment>
{};
template <typename Point, typename PointOfSegment>
struct result_type
{
typedef projected_point_ax_result
<
typename calculation_type<Point, PointOfSegment>::type
> type;
};
public :
template <typename Point, typename PointOfSegment>
inline typename result_type<Point, PointOfSegment>::type
apply(Point const& p, PointOfSegment const& p1, PointOfSegment const& p2) const
{
assert_dimension_equal<Point, PointOfSegment>();
typedef typename calculation_type<Point, PointOfSegment>::type calculation_type;
// A projected point of points in Integer coordinates must be able to be
// represented in FP.
typedef model::point
<
calculation_type,
dimension<PointOfSegment>::value,
typename coordinate_system<PointOfSegment>::type
> fp_point_type;
// For convenience
typedef fp_point_type fp_vector_type;
/*
Algorithm [p: (px,py), p1: (x1,y1), p2: (x2,y2)]
VECTOR v(x2 - x1, y2 - y1)
VECTOR w(px - x1, py - y1)
c1 = w . v
c2 = v . v
b = c1 / c2
RETURN POINT(x1 + b * vx, y1 + b * vy)
*/
// v is multiplied below with a (possibly) FP-value, so should be in FP
// For consistency we define w also in FP
fp_vector_type v, w, projected;
geometry::convert(p2, v);
geometry::convert(p, w);
geometry::convert(p1, projected);
subtract_point(v, projected);
subtract_point(w, projected);
Strategy strategy;
boost::ignore_unused_variable_warning(strategy);
typename result_type<Point, PointOfSegment>::type result;
calculation_type const zero = calculation_type();
calculation_type const c2 = dot_product(v, v);
if ( math::equals(c2, zero) )
{
result.xtd = strategy.apply(p, projected);
// assume that the 0-length segment is perpendicular to the Pt->ProjPt vector
result.atd = 0;
return result;
}
calculation_type const c1 = dot_product(w, v);
calculation_type const b = c1 / c2;
multiply_value(v, b);
add_point(projected, v);
result.xtd = strategy.apply(p, projected);
if (c1 <= zero)
{
result.atd = strategy.apply(p1, projected);
}
else if (c2 <= c1)
{
result.atd = strategy.apply(p2, projected);
}
else
{
result.atd = 0;
}
return result;
}
};
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename CalculationType, typename Strategy>
struct tag<detail::projected_point_ax<CalculationType, Strategy> >
{
typedef strategy_tag_distance_point_segment type;
};
template <typename CalculationType, typename Strategy, typename P, typename PS>
struct return_type<detail::projected_point_ax<CalculationType, Strategy>, P, PS>
{
typedef typename detail::projected_point_ax<CalculationType, Strategy>
::template result_type<P, PS>::type type;
};
template <typename CalculationType, typename Strategy>
struct comparable_type<detail::projected_point_ax<CalculationType, Strategy> >
{
// Define a projected_point strategy with its underlying point-point-strategy
// being comparable
typedef detail::projected_point_ax
<
CalculationType,
typename comparable_type<Strategy>::type
> type;
};
template <typename CalculationType, typename Strategy>
struct get_comparable<detail::projected_point_ax<CalculationType, Strategy> >
{
typedef typename comparable_type
<
detail::projected_point_ax<CalculationType, Strategy>
>::type comparable_type;
public :
static inline comparable_type apply(detail::projected_point_ax<CalculationType, Strategy> const& )
{
return comparable_type();
}
};
template <typename CalculationType, typename Strategy, typename P, typename PS>
struct result_from_distance<detail::projected_point_ax<CalculationType, Strategy>, P, PS>
{
private :
typedef typename return_type<detail::projected_point_ax<CalculationType, Strategy>, P, PS>::type return_type;
public :
template <typename T>
static inline return_type apply(detail::projected_point_ax<CalculationType, Strategy> const& , T const& value)
{
Strategy s;
return_type ret;
ret.atd = result_from_distance<Strategy, P, PS>::apply(s, value.atd);
ret.xtd = result_from_distance<Strategy, P, PS>::apply(s, value.xtd);
return ret;
}
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::distance
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PROJECTED_POINT_AX_HPP
@@ -0,0 +1,288 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_HPP
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/calculation_type.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace distance
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template <size_t I, typename T>
struct compute_pythagoras
{
template <typename Point1, typename Point2>
static inline T apply(Point1 const& p1, Point2 const& p2)
{
T const c1 = boost::numeric_cast<T>(get<I-1>(p1));
T const c2 = boost::numeric_cast<T>(get<I-1>(p2));
T const d = c1 - c2;
return d * d + compute_pythagoras<I-1, T>::apply(p1, p2);
}
};
template <typename T>
struct compute_pythagoras<0, T>
{
template <typename Point1, typename Point2>
static inline T apply(Point1 const&, Point2 const&)
{
return boost::numeric_cast<T>(0);
}
};
}
#endif // DOXYGEN_NO_DETAIL
namespace comparable
{
/*!
\brief Strategy to calculate comparable distance between two points
\ingroup strategies
\tparam Point1 \tparam_first_point
\tparam Point2 \tparam_second_point
\tparam CalculationType \tparam_calculation
*/
template <typename CalculationType = void>
class pythagoras
{
public :
template <typename Point1, typename Point2>
struct calculation_type
: util::calculation_type::geometric::binary
<
Point1,
Point2,
CalculationType,
double,
double
>
{};
template <typename Point1, typename Point2>
static inline typename calculation_type<Point1, Point2>::type
apply(Point1 const& p1, Point2 const& p2)
{
BOOST_CONCEPT_ASSERT( (concepts::ConstPoint<Point1>) );
BOOST_CONCEPT_ASSERT( (concepts::ConstPoint<Point2>) );
// Calculate distance using Pythagoras
// (Leave comment above for Doxygen)
assert_dimension_equal<Point1, Point2>();
return detail::compute_pythagoras
<
dimension<Point1>::value,
typename calculation_type<Point1, Point2>::type
>::apply(p1, p2);
}
};
} // namespace comparable
/*!
\brief Strategy to calculate the distance between two points
\ingroup strategies
\tparam CalculationType \tparam_calculation
\qbk{
[heading Notes]
[note Can be used for points with two\, three or more dimensions]
[heading See also]
[link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)]
}
*/
template
<
typename CalculationType = void
>
class pythagoras
{
public :
template <typename P1, typename P2>
struct calculation_type
: util::calculation_type::geometric::binary
<
P1,
P2,
CalculationType,
double,
double // promote integer to double
>
{};
/*!
\brief applies the distance calculation using pythagoras
\return the calculated distance (including taking the square root)
\param p1 first point
\param p2 second point
*/
template <typename P1, typename P2>
static inline typename calculation_type<P1, P2>::type
apply(P1 const& p1, P2 const& p2)
{
// The cast is necessary for MSVC which considers sqrt __int64 as an ambiguous call
return math::sqrt
(
boost::numeric_cast<typename calculation_type<P1, P2>::type>
(
comparable::pythagoras<CalculationType>::apply(p1, p2)
)
);
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename CalculationType>
struct tag<pythagoras<CalculationType> >
{
typedef strategy_tag_distance_point_point type;
};
template <typename CalculationType, typename P1, typename P2>
struct return_type<distance::pythagoras<CalculationType>, P1, P2>
: pythagoras<CalculationType>::template calculation_type<P1, P2>
{};
template <typename CalculationType>
struct comparable_type<pythagoras<CalculationType> >
{
typedef comparable::pythagoras<CalculationType> type;
};
template <typename CalculationType>
struct get_comparable<pythagoras<CalculationType> >
{
typedef comparable::pythagoras<CalculationType> comparable_type;
public :
static inline comparable_type apply(pythagoras<CalculationType> const& )
{
return comparable_type();
}
};
template <typename CalculationType, typename Point1, typename Point2>
struct result_from_distance<pythagoras<CalculationType>, Point1, Point2>
{
private :
typedef typename return_type<pythagoras<CalculationType>, Point1, Point2>::type return_type;
public :
template <typename T>
static inline return_type apply(pythagoras<CalculationType> const& , T const& value)
{
return return_type(value);
}
};
// Specializations for comparable::pythagoras
template <typename CalculationType>
struct tag<comparable::pythagoras<CalculationType> >
{
typedef strategy_tag_distance_point_point type;
};
template <typename CalculationType, typename P1, typename P2>
struct return_type<comparable::pythagoras<CalculationType>, P1, P2>
: comparable::pythagoras<CalculationType>::template calculation_type<P1, P2>
{};
template <typename CalculationType>
struct comparable_type<comparable::pythagoras<CalculationType> >
{
typedef comparable::pythagoras<CalculationType> type;
};
template <typename CalculationType>
struct get_comparable<comparable::pythagoras<CalculationType> >
{
typedef comparable::pythagoras<CalculationType> comparable_type;
public :
static inline comparable_type apply(comparable::pythagoras<CalculationType> const& )
{
return comparable_type();
}
};
template <typename CalculationType, typename Point1, typename Point2>
struct result_from_distance<comparable::pythagoras<CalculationType>, Point1, Point2>
{
private :
typedef typename return_type<comparable::pythagoras<CalculationType>, Point1, Point2>::type return_type;
public :
template <typename T>
static inline return_type apply(comparable::pythagoras<CalculationType> const& , T const& value)
{
return_type const v = value;
return v * v;
}
};
template <typename Point1, typename Point2>
struct default_strategy
<
point_tag, point_tag, Point1, Point2, cartesian_tag, cartesian_tag
>
{
typedef pythagoras<> type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::distance
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_HPP
@@ -0,0 +1,338 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2008-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_BOX_BOX_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_BOX_BOX_HPP
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/calculation_type.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace distance
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template <std::size_t I>
struct compute_pythagoras_box_box
{
template <typename Box1, typename Box2, typename T>
static inline void apply(Box1 const& box1, Box2 const& box2, T& result)
{
T const b1_min_coord =
boost::numeric_cast<T>(geometry::get<min_corner, I-1>(box1));
T const b1_max_coord =
boost::numeric_cast<T>(geometry::get<max_corner, I-1>(box1));
T const b2_min_coord =
boost::numeric_cast<T>(geometry::get<min_corner, I-1>(box2));
T const b2_max_coord =
boost::numeric_cast<T>(geometry::get<max_corner, I-1>(box2));
if ( b1_max_coord < b2_min_coord )
{
T diff = b2_min_coord - b1_max_coord;
result += diff * diff;
}
if ( b1_min_coord > b2_max_coord )
{
T diff = b1_min_coord - b2_max_coord;
result += diff * diff;
}
compute_pythagoras_box_box<I-1>::apply(box1, box2, result);
}
};
template <>
struct compute_pythagoras_box_box<0>
{
template <typename Box1, typename Box2, typename T>
static inline void apply(Box1 const&, Box2 const&, T&)
{
}
};
}
#endif // DOXYGEN_NO_DETAIL
namespace comparable
{
/*!
\brief Strategy to calculate comparable distance between two boxes
\ingroup strategies
\tparam Box1 \tparam_first_box
\tparam Box2 \tparam_second_box
\tparam CalculationType \tparam_calculation
*/
template <typename CalculationType = void>
class pythagoras_box_box
{
public :
template <typename Box1, typename Box2>
struct calculation_type
{
typedef typename util::calculation_type::geometric::binary
<
Box1,
Box2,
CalculationType
>::type type;
};
template <typename Box1, typename Box2>
static inline typename calculation_type<Box1, Box2>::type
apply(Box1 const& box1, Box2 const& box2)
{
BOOST_CONCEPT_ASSERT
( (concepts::ConstPoint<typename point_type<Box1>::type>) );
BOOST_CONCEPT_ASSERT
( (concepts::ConstPoint<typename point_type<Box2>::type>) );
// Calculate distance using Pythagoras
// (Leave comment above for Doxygen)
assert_dimension_equal<Box1, Box2>();
typename calculation_type<Box1, Box2>::type result(0);
detail::compute_pythagoras_box_box
<
dimension<Box1>::value
>::apply(box1, box2, result);
return result;
}
};
} // namespace comparable
/*!
\brief Strategy to calculate the distance between two boxes
\ingroup strategies
\tparam CalculationType \tparam_calculation
\qbk{
[heading Notes]
[note Can be used for boxes with two\, three or more dimensions]
[heading See also]
[link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)]
}
*/
template
<
typename CalculationType = void
>
class pythagoras_box_box
{
public :
template <typename Box1, typename Box2>
struct calculation_type
: util::calculation_type::geometric::binary
<
Box1,
Box2,
CalculationType,
double,
double // promote integer to double
>
{};
/*!
\brief applies the distance calculation using pythagoras_box_box
\return the calculated distance (including taking the square root)
\param box1 first box
\param box2 second box
*/
template <typename Box1, typename Box2>
static inline typename calculation_type<Box1, Box2>::type
apply(Box1 const& box1, Box2 const& box2)
{
// The cast is necessary for MSVC which considers sqrt __int64 as an ambiguous call
return math::sqrt
(
boost::numeric_cast<typename calculation_type
<
Box1, Box2
>::type>
(
comparable::pythagoras_box_box
<
CalculationType
>::apply(box1, box2)
)
);
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename CalculationType>
struct tag<pythagoras_box_box<CalculationType> >
{
typedef strategy_tag_distance_box_box type;
};
template <typename CalculationType, typename Box1, typename Box2>
struct return_type<distance::pythagoras_box_box<CalculationType>, Box1, Box2>
: pythagoras_box_box<CalculationType>::template calculation_type<Box1, Box2>
{};
template <typename CalculationType>
struct comparable_type<pythagoras_box_box<CalculationType> >
{
typedef comparable::pythagoras_box_box<CalculationType> type;
};
template <typename CalculationType>
struct get_comparable<pythagoras_box_box<CalculationType> >
{
typedef comparable::pythagoras_box_box<CalculationType> comparable_type;
public :
static inline comparable_type
apply(pythagoras_box_box<CalculationType> const& )
{
return comparable_type();
}
};
template <typename CalculationType, typename Box1, typename Box2>
struct result_from_distance<pythagoras_box_box<CalculationType>, Box1, Box2>
{
private:
typedef typename return_type
<
pythagoras_box_box<CalculationType>, Box1, Box2
>::type return_type;
public:
template <typename T>
static inline return_type
apply(pythagoras_box_box<CalculationType> const& , T const& value)
{
return return_type(value);
}
};
// Specializations for comparable::pythagoras_box_box
template <typename CalculationType>
struct tag<comparable::pythagoras_box_box<CalculationType> >
{
typedef strategy_tag_distance_box_box type;
};
template <typename CalculationType, typename Box1, typename Box2>
struct return_type<comparable::pythagoras_box_box<CalculationType>, Box1, Box2>
: comparable::pythagoras_box_box
<
CalculationType
>::template calculation_type<Box1, Box2>
{};
template <typename CalculationType>
struct comparable_type<comparable::pythagoras_box_box<CalculationType> >
{
typedef comparable::pythagoras_box_box<CalculationType> type;
};
template <typename CalculationType>
struct get_comparable<comparable::pythagoras_box_box<CalculationType> >
{
typedef comparable::pythagoras_box_box<CalculationType> comparable_type;
public :
static inline comparable_type apply(comparable_type const& )
{
return comparable_type();
}
};
template <typename CalculationType, typename Box1, typename Box2>
struct result_from_distance
<
comparable::pythagoras_box_box<CalculationType>, Box1, Box2
>
{
private :
typedef typename return_type
<
comparable::pythagoras_box_box<CalculationType>, Box1, Box2
>::type return_type;
public :
template <typename T>
static inline return_type
apply(comparable::pythagoras_box_box<CalculationType> const&,
T const& value)
{
return_type const v = value;
return v * v;
}
};
template <typename BoxPoint1, typename BoxPoint2>
struct default_strategy
<
box_tag, box_tag, BoxPoint1, BoxPoint2, cartesian_tag, cartesian_tag
>
{
typedef pythagoras_box_box<> type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::distance
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_BOX_BOX_HPP
@@ -0,0 +1,349 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2008-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_POINT_BOX_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_POINT_BOX_HPP
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/calculation_type.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace distance
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template <size_t I>
struct compute_pythagoras_point_box
{
template <typename Point, typename Box, typename T>
static inline void apply(Point const& point, Box const& box, T& result)
{
T const p_coord = boost::numeric_cast<T>(geometry::get<I-1>(point));
T const b_min_coord =
boost::numeric_cast<T>(geometry::get<min_corner, I-1>(box));
T const b_max_coord =
boost::numeric_cast<T>(geometry::get<max_corner, I-1>(box));
if ( p_coord < b_min_coord )
{
T diff = b_min_coord - p_coord;
result += diff * diff;
}
if ( p_coord > b_max_coord )
{
T diff = p_coord - b_max_coord;
result += diff * diff;
}
compute_pythagoras_point_box<I-1>::apply(point, box, result);
}
};
template <>
struct compute_pythagoras_point_box<0>
{
template <typename Point, typename Box, typename T>
static inline void apply(Point const&, Box const&, T&)
{
}
};
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
namespace comparable
{
/*!
\brief Strategy to calculate comparable distance between a point
and a box
\ingroup strategies
\tparam Point \tparam_first_point
\tparam Box \tparam_second_box
\tparam CalculationType \tparam_calculation
*/
template <typename CalculationType = void>
class pythagoras_point_box
{
public :
template <typename Point, typename Box>
struct calculation_type
{
typedef typename util::calculation_type::geometric::binary
<
Point, Box, CalculationType
>::type type;
};
template <typename Point, typename Box>
static inline typename calculation_type<Point, Box>::type
apply(Point const& point, Box const& box)
{
BOOST_CONCEPT_ASSERT( (concepts::ConstPoint<Point>) );
BOOST_CONCEPT_ASSERT
( (concepts::ConstPoint<typename point_type<Box>::type>) );
// Calculate distance using Pythagoras
// (Leave comment above for Doxygen)
assert_dimension_equal<Point, Box>();
typename calculation_type<Point, Box>::type result(0);
detail::compute_pythagoras_point_box
<
dimension<Point>::value
>::apply(point, box, result);
return result;
}
};
} // namespace comparable
/*!
\brief Strategy to calculate the distance between a point and a box
\ingroup strategies
\tparam CalculationType \tparam_calculation
\qbk{
[heading Notes]
[note Can be used for points and boxes with two\, three or more dimensions]
[heading See also]
[link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)]
}
*/
template
<
typename CalculationType = void
>
class pythagoras_point_box
{
public :
template <typename Point, typename Box>
struct calculation_type
: util::calculation_type::geometric::binary
<
Point,
Box,
CalculationType,
double,
double // promote integer to double
>
{};
/*!
\brief applies the distance calculation using pythagoras
\return the calculated distance (including taking the square root)
\param point point
\param box box
*/
template <typename Point, typename Box>
static inline typename calculation_type<Point, Box>::type
apply(Point const& point, Box const& box)
{
// The cast is necessary for MSVC which considers sqrt __int64 as an ambiguous call
return math::sqrt
(
boost::numeric_cast<typename calculation_type
<
Point, Box
>::type>
(
comparable::pythagoras_point_box
<
CalculationType
>::apply(point, box)
)
);
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename CalculationType>
struct tag<pythagoras_point_box<CalculationType> >
{
typedef strategy_tag_distance_point_box type;
};
template <typename CalculationType, typename Point, typename Box>
struct return_type<distance::pythagoras_point_box<CalculationType>, Point, Box>
: pythagoras_point_box
<
CalculationType
>::template calculation_type<Point, Box>
{};
template <typename CalculationType>
struct comparable_type<pythagoras_point_box<CalculationType> >
{
typedef comparable::pythagoras_point_box<CalculationType> type;
};
template <typename CalculationType>
struct get_comparable<pythagoras_point_box<CalculationType> >
{
typedef comparable::pythagoras_point_box<CalculationType> comparable_type;
public :
static inline comparable_type
apply(pythagoras_point_box<CalculationType> const& )
{
return comparable_type();
}
};
template <typename CalculationType, typename Point, typename Box>
struct result_from_distance<pythagoras_point_box<CalculationType>, Point, Box>
{
private :
typedef typename return_type
<
pythagoras_point_box<CalculationType>, Point, Box
>::type return_type;
public :
template <typename T>
static inline return_type
apply(pythagoras_point_box<CalculationType> const& , T const& value)
{
return return_type(value);
}
};
// Specializations for comparable::pythagoras_point_box
template <typename CalculationType>
struct tag<comparable::pythagoras_point_box<CalculationType> >
{
typedef strategy_tag_distance_point_box type;
};
template <typename CalculationType, typename Point, typename Box>
struct return_type
<
comparable::pythagoras_point_box<CalculationType>, Point, Box
> : comparable::pythagoras_point_box
<
CalculationType
>::template calculation_type<Point, Box>
{};
template <typename CalculationType>
struct comparable_type<comparable::pythagoras_point_box<CalculationType> >
{
typedef comparable::pythagoras_point_box<CalculationType> type;
};
template <typename CalculationType>
struct get_comparable<comparable::pythagoras_point_box<CalculationType> >
{
typedef comparable::pythagoras_point_box<CalculationType> comparable_type;
public :
static inline comparable_type apply(comparable_type const& )
{
return comparable_type();
}
};
template <typename CalculationType, typename Point, typename Box>
struct result_from_distance
<
comparable::pythagoras_point_box<CalculationType>, Point, Box
>
{
private :
typedef typename return_type
<
comparable::pythagoras_point_box<CalculationType>, Point, Box
>::type return_type;
public :
template <typename T>
static inline return_type
apply(comparable::pythagoras_point_box<CalculationType> const& ,
T const& value)
{
return_type const v = value;
return v * v;
}
};
template <typename Point, typename BoxPoint>
struct default_strategy
<
point_tag, box_tag, Point, BoxPoint, cartesian_tag, cartesian_tag
>
{
typedef pythagoras_point_box<> type;
};
template <typename BoxPoint, typename Point>
struct default_strategy
<
box_tag, point_tag, BoxPoint, Point, cartesian_tag, cartesian_tag
>
{
typedef typename default_strategy
<
point_tag, box_tag, Point, BoxPoint, cartesian_tag, cartesian_tag
>::type type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::distance
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_POINT_BOX_HPP
@@ -0,0 +1,71 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2017 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fisikopoulos, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_ENVELOPE_SEGMENT_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_ENVELOPE_SEGMENT_HPP
#include <boost/geometry/algorithms/detail/envelope/segment.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace envelope
{
template
<
typename CalculationType = void
>
class cartesian_segment
{
public :
template <typename Point1, typename Point2, typename Box>
inline void
apply(Point1 const& point1, Point2 const& point2, Box& box) const
{
geometry::detail::envelope::envelope_one_segment
<
0,
dimension<Point1>::value
>
::apply(point1,
point2,
box,
strategy::envelope::cartesian_segment<CalculationType>());
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename CalculationType>
struct default_strategy<cartesian_tag, CalculationType>
{
typedef strategy::envelope::cartesian_segment<CalculationType> type;
};
}
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::envelope
}} //namepsace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_ENVELOPE_SEGMENT_HPP
@@ -0,0 +1,704 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2014, 2016, 2017.
// Modifications copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_INTERSECTION_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_INTERSECTION_HPP
#include <algorithm>
#include <boost/geometry/core/exception.hpp>
#include <boost/geometry/geometries/concepts/point_concept.hpp>
#include <boost/geometry/geometries/concepts/segment_concept.hpp>
#include <boost/geometry/arithmetic/determinant.hpp>
#include <boost/geometry/algorithms/detail/assign_values.hpp>
#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/promote_integral.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp>
#include <boost/geometry/strategies/cartesian/area_surveyor.hpp>
#include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp>
#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>
#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/intersection.hpp>
#include <boost/geometry/strategies/intersection_result.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/strategies/side_info.hpp>
#include <boost/geometry/strategies/within.hpp>
#include <boost/geometry/policies/robustness/robust_point_type.hpp>
#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
# include <boost/geometry/io/wkt/write.hpp>
#endif
namespace boost { namespace geometry
{
namespace strategy { namespace intersection
{
/*!
\see http://mathworld.wolfram.com/Line-LineIntersection.html
*/
template
<
typename CalculationType = void
>
struct cartesian_segments
{
typedef side::side_by_triangle<CalculationType> side_strategy_type;
static inline side_strategy_type get_side_strategy()
{
return side_strategy_type();
}
template <typename Geometry1, typename Geometry2>
struct point_in_geometry_strategy
{
typedef strategy::within::winding
<
typename point_type<Geometry1>::type,
typename point_type<Geometry2>::type,
side_strategy_type,
CalculationType
> type;
};
template <typename Geometry1, typename Geometry2>
static inline typename point_in_geometry_strategy<Geometry1, Geometry2>::type
get_point_in_geometry_strategy()
{
typedef typename point_in_geometry_strategy
<
Geometry1, Geometry2
>::type strategy_type;
return strategy_type();
}
template <typename Geometry>
struct area_strategy
{
typedef area::surveyor
<
typename point_type<Geometry>::type,
CalculationType
> type;
};
template <typename Geometry>
static inline typename area_strategy<Geometry>::type get_area_strategy()
{
typedef typename area_strategy<Geometry>::type strategy_type;
return strategy_type();
}
template <typename Geometry>
struct distance_strategy
{
typedef distance::pythagoras
<
CalculationType
> type;
};
template <typename Geometry>
static inline typename distance_strategy<Geometry>::type get_distance_strategy()
{
typedef typename distance_strategy<Geometry>::type strategy_type;
return strategy_type();
}
template <typename CoordinateType, typename SegmentRatio>
struct segment_intersection_info
{
typedef typename select_most_precise
<
CoordinateType, double
>::type promoted_type;
promoted_type comparable_length_a() const
{
return dx_a * dx_a + dy_a * dy_a;
}
promoted_type comparable_length_b() const
{
return dx_b * dx_b + dy_b * dy_b;
}
template <typename Point, typename Segment1, typename Segment2>
void assign_a(Point& point, Segment1 const& a, Segment2 const& ) const
{
assign(point, a, dx_a, dy_a, robust_ra);
}
template <typename Point, typename Segment1, typename Segment2>
void assign_b(Point& point, Segment1 const& , Segment2 const& b) const
{
assign(point, b, dx_b, dy_b, robust_rb);
}
template <typename Point, typename Segment>
void assign(Point& point, Segment const& segment, CoordinateType const& dx, CoordinateType const& dy, SegmentRatio const& ratio) const
{
// Calculate the intersection point based on segment_ratio
// Up to now, division was postponed. Here we divide using numerator/
// denominator. In case of integer this results in an integer
// division.
BOOST_GEOMETRY_ASSERT(ratio.denominator() != 0);
typedef typename promote_integral<CoordinateType>::type promoted_type;
promoted_type const numerator
= boost::numeric_cast<promoted_type>(ratio.numerator());
promoted_type const denominator
= boost::numeric_cast<promoted_type>(ratio.denominator());
promoted_type const dx_promoted = boost::numeric_cast<promoted_type>(dx);
promoted_type const dy_promoted = boost::numeric_cast<promoted_type>(dy);
set<0>(point, get<0, 0>(segment) + boost::numeric_cast
<
CoordinateType
>(numerator * dx_promoted / denominator));
set<1>(point, get<0, 1>(segment) + boost::numeric_cast
<
CoordinateType
>(numerator * dy_promoted / denominator));
}
CoordinateType dx_a, dy_a;
CoordinateType dx_b, dy_b;
SegmentRatio robust_ra;
SegmentRatio robust_rb;
};
template <typename D, typename W, typename ResultType>
static inline void cramers_rule(D const& dx_a, D const& dy_a,
D const& dx_b, D const& dy_b, W const& wx, W const& wy,
// out:
ResultType& d, ResultType& da)
{
// Cramers rule
d = geometry::detail::determinant<ResultType>(dx_a, dy_a, dx_b, dy_b);
da = geometry::detail::determinant<ResultType>(dx_b, dy_b, wx, wy);
// Ratio is da/d , collinear if d == 0, intersecting if 0 <= r <= 1
// IntersectionPoint = (x1 + r * dx_a, y1 + r * dy_a)
}
// Relate segments a and b
template
<
typename Segment1,
typename Segment2,
typename Policy,
typename RobustPolicy
>
static inline typename Policy::return_type
apply(Segment1 const& a, Segment2 const& b,
Policy const& policy, RobustPolicy const& robust_policy)
{
// type them all as in Segment1 - TODO reconsider this, most precise?
typedef typename geometry::point_type<Segment1>::type point_type;
typedef typename geometry::robust_point_type
<
point_type, RobustPolicy
>::type robust_point_type;
point_type a0, a1, b0, b1;
robust_point_type a0_rob, a1_rob, b0_rob, b1_rob;
detail::assign_point_from_index<0>(a, a0);
detail::assign_point_from_index<1>(a, a1);
detail::assign_point_from_index<0>(b, b0);
detail::assign_point_from_index<1>(b, b1);
geometry::recalculate(a0_rob, a0, robust_policy);
geometry::recalculate(a1_rob, a1, robust_policy);
geometry::recalculate(b0_rob, b0, robust_policy);
geometry::recalculate(b1_rob, b1, robust_policy);
return apply(a, b, policy, robust_policy, a0_rob, a1_rob, b0_rob, b1_rob);
}
// The main entry-routine, calculating intersections of segments a / b
// NOTE: Robust* types may be the same as Segments' point types
template
<
typename Segment1,
typename Segment2,
typename Policy,
typename RobustPolicy,
typename RobustPoint1,
typename RobustPoint2
>
static inline typename Policy::return_type
apply(Segment1 const& a, Segment2 const& b,
Policy const&, RobustPolicy const& /*robust_policy*/,
RobustPoint1 const& robust_a1, RobustPoint1 const& robust_a2,
RobustPoint2 const& robust_b1, RobustPoint2 const& robust_b2)
{
BOOST_CONCEPT_ASSERT( (concepts::ConstSegment<Segment1>) );
BOOST_CONCEPT_ASSERT( (concepts::ConstSegment<Segment2>) );
using geometry::detail::equals::equals_point_point;
bool const a_is_point = equals_point_point(robust_a1, robust_a2);
bool const b_is_point = equals_point_point(robust_b1, robust_b2);
if(a_is_point && b_is_point)
{
return equals_point_point(robust_a1, robust_b2)
? Policy::degenerate(a, true)
: Policy::disjoint()
;
}
side_info sides;
sides.set<0>(side_strategy_type::apply(robust_b1, robust_b2, robust_a1),
side_strategy_type::apply(robust_b1, robust_b2, robust_a2));
if (sides.same<0>())
{
// Both points are at same side of other segment, we can leave
return Policy::disjoint();
}
sides.set<1>(side_strategy_type::apply(robust_a1, robust_a2, robust_b1),
side_strategy_type::apply(robust_a1, robust_a2, robust_b2));
if (sides.same<1>())
{
// Both points are at same side of other segment, we can leave
return Policy::disjoint();
}
bool collinear = sides.collinear();
typedef typename select_most_precise
<
typename geometry::coordinate_type<RobustPoint1>::type,
typename geometry::coordinate_type<RobustPoint2>::type
>::type robust_coordinate_type;
typedef typename segment_ratio_type
<
typename geometry::point_type<Segment1>::type, // TODO: most precise point?
RobustPolicy
>::type ratio_type;
segment_intersection_info
<
typename select_calculation_type<Segment1, Segment2, CalculationType>::type,
ratio_type
> sinfo;
sinfo.dx_a = get<1, 0>(a) - get<0, 0>(a); // distance in x-dir
sinfo.dx_b = get<1, 0>(b) - get<0, 0>(b);
sinfo.dy_a = get<1, 1>(a) - get<0, 1>(a); // distance in y-dir
sinfo.dy_b = get<1, 1>(b) - get<0, 1>(b);
robust_coordinate_type const robust_dx_a = get<0>(robust_a2) - get<0>(robust_a1);
robust_coordinate_type const robust_dx_b = get<0>(robust_b2) - get<0>(robust_b1);
robust_coordinate_type const robust_dy_a = get<1>(robust_a2) - get<1>(robust_a1);
robust_coordinate_type const robust_dy_b = get<1>(robust_b2) - get<1>(robust_b1);
// r: ratio 0-1 where intersection divides A/B
// (only calculated for non-collinear segments)
if (! collinear)
{
robust_coordinate_type robust_da0, robust_da;
robust_coordinate_type robust_db0, robust_db;
cramers_rule(robust_dx_a, robust_dy_a, robust_dx_b, robust_dy_b,
get<0>(robust_a1) - get<0>(robust_b1),
get<1>(robust_a1) - get<1>(robust_b1),
robust_da0, robust_da);
cramers_rule(robust_dx_b, robust_dy_b, robust_dx_a, robust_dy_a,
get<0>(robust_b1) - get<0>(robust_a1),
get<1>(robust_b1) - get<1>(robust_a1),
robust_db0, robust_db);
math::detail::equals_factor_policy<robust_coordinate_type>
policy(robust_dx_a, robust_dy_a, robust_dx_b, robust_dy_b);
robust_coordinate_type const zero = 0;
if (math::detail::equals_by_policy(robust_da0, zero, policy)
|| math::detail::equals_by_policy(robust_db0, zero, policy))
{
// If this is the case, no rescaling is done for FP precision.
// We set it to collinear, but it indicates a robustness issue.
sides.set<0>(0,0);
sides.set<1>(0,0);
collinear = true;
}
else
{
sinfo.robust_ra.assign(robust_da, robust_da0);
sinfo.robust_rb.assign(robust_db, robust_db0);
}
}
if (collinear)
{
std::pair<bool, bool> const collinear_use_first
= is_x_more_significant(geometry::math::abs(robust_dx_a),
geometry::math::abs(robust_dy_a),
geometry::math::abs(robust_dx_b),
geometry::math::abs(robust_dy_b),
a_is_point, b_is_point);
if (collinear_use_first.second)
{
// Degenerate cases: segments of single point, lying on other segment, are not disjoint
// This situation is collinear too
if (collinear_use_first.first)
{
return relate_collinear<0, Policy, ratio_type>(a, b,
robust_a1, robust_a2, robust_b1, robust_b2,
a_is_point, b_is_point);
}
else
{
// Y direction contains larger segments (maybe dx is zero)
return relate_collinear<1, Policy, ratio_type>(a, b,
robust_a1, robust_a2, robust_b1, robust_b2,
a_is_point, b_is_point);
}
}
}
return Policy::segments_crosses(sides, sinfo, a, b);
}
private:
// first is true if x is more significant
// second is true if the more significant difference is not 0
template <typename RobustCoordinateType>
static inline std::pair<bool, bool>
is_x_more_significant(RobustCoordinateType const& abs_robust_dx_a,
RobustCoordinateType const& abs_robust_dy_a,
RobustCoordinateType const& abs_robust_dx_b,
RobustCoordinateType const& abs_robust_dy_b,
bool const a_is_point,
bool const b_is_point)
{
//BOOST_GEOMETRY_ASSERT_MSG(!(a_is_point && b_is_point), "both segments shouldn't be degenerated");
// for degenerated segments the second is always true because this function
// shouldn't be called if both segments were degenerated
if (a_is_point)
{
return std::make_pair(abs_robust_dx_b >= abs_robust_dy_b, true);
}
else if (b_is_point)
{
return std::make_pair(abs_robust_dx_a >= abs_robust_dy_a, true);
}
else
{
RobustCoordinateType const min_dx = (std::min)(abs_robust_dx_a, abs_robust_dx_b);
RobustCoordinateType const min_dy = (std::min)(abs_robust_dy_a, abs_robust_dy_b);
return min_dx == min_dy ?
std::make_pair(true, min_dx > RobustCoordinateType(0)) :
std::make_pair(min_dx > min_dy, true);
}
}
template
<
std::size_t Dimension,
typename Policy,
typename RatioType,
typename Segment1,
typename Segment2,
typename RobustPoint1,
typename RobustPoint2
>
static inline typename Policy::return_type
relate_collinear(Segment1 const& a,
Segment2 const& b,
RobustPoint1 const& robust_a1, RobustPoint1 const& robust_a2,
RobustPoint2 const& robust_b1, RobustPoint2 const& robust_b2,
bool a_is_point, bool b_is_point)
{
if (a_is_point)
{
return relate_one_degenerate<Policy, RatioType>(a,
get<Dimension>(robust_a1),
get<Dimension>(robust_b1), get<Dimension>(robust_b2),
true);
}
if (b_is_point)
{
return relate_one_degenerate<Policy, RatioType>(b,
get<Dimension>(robust_b1),
get<Dimension>(robust_a1), get<Dimension>(robust_a2),
false);
}
return relate_collinear<Policy, RatioType>(a, b,
get<Dimension>(robust_a1),
get<Dimension>(robust_a2),
get<Dimension>(robust_b1),
get<Dimension>(robust_b2));
}
/// Relate segments known collinear
template
<
typename Policy,
typename RatioType,
typename Segment1,
typename Segment2,
typename RobustType1,
typename RobustType2
>
static inline typename Policy::return_type
relate_collinear(Segment1 const& a, Segment2 const& b,
RobustType1 oa_1, RobustType1 oa_2,
RobustType2 ob_1, RobustType2 ob_2)
{
// Calculate the ratios where a starts in b, b starts in a
// a1--------->a2 (2..7)
// b1----->b2 (5..8)
// length_a: 7-2=5
// length_b: 8-5=3
// b1 is located w.r.t. a at ratio: (5-2)/5=3/5 (on a)
// b2 is located w.r.t. a at ratio: (8-2)/5=6/5 (right of a)
// a1 is located w.r.t. b at ratio: (2-5)/3=-3/3 (left of b)
// a2 is located w.r.t. b at ratio: (7-5)/3=2/3 (on b)
// A arrives (a2 on b), B departs (b1 on a)
// If both are reversed:
// a2<---------a1 (7..2)
// b2<-----b1 (8..5)
// length_a: 2-7=-5
// length_b: 5-8=-3
// b1 is located w.r.t. a at ratio: (8-7)/-5=-1/5 (before a starts)
// b2 is located w.r.t. a at ratio: (5-7)/-5=2/5 (on a)
// a1 is located w.r.t. b at ratio: (7-8)/-3=1/3 (on b)
// a2 is located w.r.t. b at ratio: (2-8)/-3=6/3 (after b ends)
// If both one is reversed:
// a1--------->a2 (2..7)
// b2<-----b1 (8..5)
// length_a: 7-2=+5
// length_b: 5-8=-3
// b1 is located w.r.t. a at ratio: (8-2)/5=6/5 (after a ends)
// b2 is located w.r.t. a at ratio: (5-2)/5=3/5 (on a)
// a1 is located w.r.t. b at ratio: (2-8)/-3=6/3 (after b ends)
// a2 is located w.r.t. b at ratio: (7-8)/-3=1/3 (on b)
RobustType1 const length_a = oa_2 - oa_1; // no abs, see above
RobustType2 const length_b = ob_2 - ob_1;
RatioType ra_from(oa_1 - ob_1, length_b);
RatioType ra_to(oa_2 - ob_1, length_b);
RatioType rb_from(ob_1 - oa_1, length_a);
RatioType rb_to(ob_2 - oa_1, length_a);
// use absolute measure to detect endpoints intersection
// NOTE: it'd be possible to calculate bx_wrt_a using ax_wrt_b values
int const a1_wrt_b = position_value(oa_1, ob_1, ob_2);
int const a2_wrt_b = position_value(oa_2, ob_1, ob_2);
int const b1_wrt_a = position_value(ob_1, oa_1, oa_2);
int const b2_wrt_a = position_value(ob_2, oa_1, oa_2);
// fix the ratios if necessary
// CONSIDER: fixing ratios also in other cases, if they're inconsistent
// e.g. if ratio == 1 or 0 (so IP at the endpoint)
// but position value indicates that the IP is in the middle of the segment
// because one of the segments is very long
// In such case the ratios could be moved into the middle direction
// by some small value (e.g. EPS+1ULP)
if (a1_wrt_b == 1)
{
ra_from.assign(0, 1);
rb_from.assign(0, 1);
}
else if (a1_wrt_b == 3)
{
ra_from.assign(1, 1);
rb_to.assign(0, 1);
}
if (a2_wrt_b == 1)
{
ra_to.assign(0, 1);
rb_from.assign(1, 1);
}
else if (a2_wrt_b == 3)
{
ra_to.assign(1, 1);
rb_to.assign(1, 1);
}
if ((a1_wrt_b < 1 && a2_wrt_b < 1) || (a1_wrt_b > 3 && a2_wrt_b > 3))
//if ((ra_from.left() && ra_to.left()) || (ra_from.right() && ra_to.right()))
{
return Policy::disjoint();
}
bool const opposite = math::sign(length_a) != math::sign(length_b);
return Policy::segments_collinear(a, b, opposite,
a1_wrt_b, a2_wrt_b, b1_wrt_a, b2_wrt_a,
ra_from, ra_to, rb_from, rb_to);
}
/// Relate segments where one is degenerate
template
<
typename Policy,
typename RatioType,
typename DegenerateSegment,
typename RobustType1,
typename RobustType2
>
static inline typename Policy::return_type
relate_one_degenerate(DegenerateSegment const& degenerate_segment,
RobustType1 d, RobustType2 s1, RobustType2 s2,
bool a_degenerate)
{
// Calculate the ratios where ds starts in s
// a1--------->a2 (2..6)
// b1/b2 (4..4)
// Ratio: (4-2)/(6-2)
RatioType const ratio(d - s1, s2 - s1);
if (!ratio.on_segment())
{
return Policy::disjoint();
}
return Policy::one_degenerate(degenerate_segment, ratio, a_degenerate);
}
template <typename ProjCoord1, typename ProjCoord2>
static inline int position_value(ProjCoord1 const& ca1,
ProjCoord2 const& cb1,
ProjCoord2 const& cb2)
{
// S1x 0 1 2 3 4
// S2 |---------->
return math::equals(ca1, cb1) ? 1
: math::equals(ca1, cb2) ? 3
: cb1 < cb2 ?
( ca1 < cb1 ? 0
: ca1 > cb2 ? 4
: 2 )
: ( ca1 > cb1 ? 0
: ca1 < cb2 ? 4
: 2 );
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename CalculationType>
struct default_strategy<cartesian_tag, CalculationType>
{
typedef cartesian_segments<CalculationType> type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::intersection
namespace strategy
{
namespace within { namespace services
{
template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2>
struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, linear_tag, linear_tag, cartesian_tag, cartesian_tag>
{
typedef strategy::intersection::cartesian_segments<> type;
};
template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2>
struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, linear_tag, polygonal_tag, cartesian_tag, cartesian_tag>
{
typedef strategy::intersection::cartesian_segments<> type;
};
template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2>
struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, polygonal_tag, linear_tag, cartesian_tag, cartesian_tag>
{
typedef strategy::intersection::cartesian_segments<> type;
};
template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2>
struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, polygonal_tag, polygonal_tag, cartesian_tag, cartesian_tag>
{
typedef strategy::intersection::cartesian_segments<> type;
};
}} // within::services
namespace covered_by { namespace services
{
template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2>
struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, linear_tag, linear_tag, cartesian_tag, cartesian_tag>
{
typedef strategy::intersection::cartesian_segments<> type;
};
template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2>
struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, linear_tag, polygonal_tag, cartesian_tag, cartesian_tag>
{
typedef strategy::intersection::cartesian_segments<> type;
};
template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2>
struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, polygonal_tag, linear_tag, cartesian_tag, cartesian_tag>
{
typedef strategy::intersection::cartesian_segments<> type;
};
template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2>
struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, polygonal_tag, polygonal_tag, cartesian_tag, cartesian_tag>
{
typedef strategy::intersection::cartesian_segments<> type;
};
}} // within::services
} // strategy
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_INTERSECTION_HPP
@@ -0,0 +1,295 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2015-2017.
// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_IN_BOX_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_IN_BOX_HPP
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/within.hpp>
#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
namespace boost { namespace geometry { namespace strategy
{
namespace within
{
struct within_coord
{
template <typename Value1, typename Value2>
static inline bool apply(Value1 const& value, Value2 const& min_value, Value2 const& max_value)
{
return value > min_value && value < max_value;
}
};
struct covered_by_coord
{
template <typename Value1, typename Value2>
static inline bool apply(Value1 const& value, Value2 const& min_value, Value2 const& max_value)
{
return value >= min_value && value <= max_value;
}
};
template <typename Geometry, std::size_t Dimension, typename CSTag>
struct within_range
: within_coord
{};
template <typename Geometry, std::size_t Dimension, typename CSTag>
struct covered_by_range
: covered_by_coord
{};
// NOTE: the result would be the same if instead of structs defined below
// the above xxx_range were used with the following arguments:
// (min_value + diff_min, min_value, max_value)
struct within_longitude_diff
{
template <typename CalcT>
static inline bool apply(CalcT const& diff_min, CalcT const& min_value, CalcT const& max_value)
{
CalcT const c0 = 0;
return diff_min > c0
&& (min_value + diff_min < max_value
/*|| max_value - diff_min > min_value*/);
}
};
struct covered_by_longitude_diff
{
template <typename CalcT>
static inline bool apply(CalcT const& diff_min, CalcT const& min_value, CalcT const& max_value)
{
return min_value + diff_min <= max_value
/*|| max_value - diff_min >= min_value*/;
}
};
template <typename Geometry,
typename CoordCheck,
typename DiffCheck>
struct longitude_range
{
template <typename Value1, typename Value2>
static inline bool apply(Value1 const& value, Value2 const& min_value, Value2 const& max_value)
{
typedef typename select_most_precise
<
Value1, Value2
>::type calc_t;
typedef typename coordinate_system<Geometry>::type::units units_t;
typedef math::detail::constants_on_spheroid<calc_t, units_t> constants;
if (CoordCheck::apply(value, min_value, max_value))
{
return true;
}
// min <= max <=> diff >= 0
calc_t const diff_ing = max_value - min_value;
// if containing covers the whole globe it contains all
if (diff_ing >= constants::period())
{
return true;
}
// calculate positive longitude translation with min_value as origin
calc_t const diff_min = math::longitude_distance_unsigned<units_t, calc_t>(min_value, value);
return DiffCheck::template apply<calc_t>(diff_min, min_value, max_value);
}
};
// spherical_equatorial_tag, spherical_polar_tag and geographic_cat are casted to spherical_tag
template <typename Geometry>
struct within_range<Geometry, 0, spherical_tag>
: longitude_range<Geometry, within_coord, within_longitude_diff>
{};
template <typename Geometry>
struct covered_by_range<Geometry, 0, spherical_tag>
: longitude_range<Geometry, covered_by_coord, covered_by_longitude_diff>
{};
template
<
template <typename, std::size_t, typename> class SubStrategy,
typename Point,
typename Box,
std::size_t Dimension,
std::size_t DimensionCount
>
struct relate_point_box_loop
{
static inline bool apply(Point const& point, Box const& box)
{
typedef typename tag_cast<typename cs_tag<Point>::type, spherical_tag>::type cs_tag_t;
if (! SubStrategy<Point, Dimension, cs_tag_t>::apply(get<Dimension>(point),
get<min_corner, Dimension>(box),
get<max_corner, Dimension>(box))
)
{
return false;
}
return relate_point_box_loop
<
SubStrategy,
Point, Box,
Dimension + 1, DimensionCount
>::apply(point, box);
}
};
template
<
template <typename, std::size_t, typename> class SubStrategy,
typename Point,
typename Box,
std::size_t DimensionCount
>
struct relate_point_box_loop<SubStrategy, Point, Box, DimensionCount, DimensionCount>
{
static inline bool apply(Point const& , Box const& )
{
return true;
}
};
template
<
typename Point,
typename Box,
template <typename, std::size_t, typename> class SubStrategy = within_range
>
struct point_in_box
{
static inline bool apply(Point const& point, Box const& box)
{
return relate_point_box_loop
<
SubStrategy,
Point, Box,
0, dimension<Point>::type::value
>::apply(point, box);
}
};
} // namespace within
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace within { namespace services
{
template <typename Point, typename Box>
struct default_strategy
<
Point, Box,
point_tag, box_tag,
pointlike_tag, areal_tag,
cartesian_tag, cartesian_tag
>
{
typedef within::point_in_box<Point, Box> type;
};
// spherical_equatorial_tag, spherical_polar_tag and geographic_cat are casted to spherical_tag
template <typename Point, typename Box>
struct default_strategy
<
Point, Box,
point_tag, box_tag,
pointlike_tag, areal_tag,
spherical_tag, spherical_tag
>
{
typedef within::point_in_box<Point, Box> type;
};
}} // namespace within::services
namespace covered_by { namespace services
{
template <typename Point, typename Box>
struct default_strategy
<
Point, Box,
point_tag, box_tag,
pointlike_tag, areal_tag,
cartesian_tag, cartesian_tag
>
{
typedef within::point_in_box
<
Point, Box,
within::covered_by_range
> type;
};
// spherical_equatorial_tag, spherical_polar_tag and geographic_cat are casted to spherical_tag
template <typename Point, typename Box>
struct default_strategy
<
Point, Box,
point_tag, box_tag,
pointlike_tag, areal_tag,
spherical_tag, spherical_tag
>
{
typedef within::point_in_box
<
Point, Box,
within::covered_by_range
> type;
};
}} // namespace covered_by::services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}}} // namespace boost::geometry::strategy
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_IN_BOX_HPP
@@ -0,0 +1,124 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_IN_POLY_CROSSINGS_MULTIPLY_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_IN_POLY_CROSSINGS_MULTIPLY_HPP
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace within
{
/*!
\brief Within detection using cross counting,
\ingroup strategies
\tparam Point \tparam_point
\tparam PointOfSegment \tparam_segment_point
\tparam CalculationType \tparam_calculation
\see http://tog.acm.org/resources/GraphicsGems/gemsiv/ptpoly_haines/ptinpoly.c
\note Does NOT work correctly for point ON border
\qbk{
[heading See also]
[link geometry.reference.algorithms.within.within_3_with_strategy within (with strategy)]
}
*/
template
<
typename Point,
typename PointOfSegment = Point,
typename CalculationType = void
>
class crossings_multiply
{
typedef typename select_calculation_type
<
Point,
PointOfSegment,
CalculationType
>::type calculation_type;
class flags
{
bool inside_flag;
bool first;
bool yflag0;
public :
friend class crossings_multiply;
inline flags()
: inside_flag(false)
, first(true)
, yflag0(false)
{}
};
public :
typedef Point point_type;
typedef PointOfSegment segment_point_type;
typedef flags state_type;
static inline bool apply(Point const& point,
PointOfSegment const& seg1, PointOfSegment const& seg2,
flags& state)
{
calculation_type const tx = get<0>(point);
calculation_type const ty = get<1>(point);
calculation_type const x0 = get<0>(seg1);
calculation_type const y0 = get<1>(seg1);
calculation_type const x1 = get<0>(seg2);
calculation_type const y1 = get<1>(seg2);
if (state.first)
{
state.first = false;
state.yflag0 = y0 >= ty;
}
bool yflag1 = y1 >= ty;
if (state.yflag0 != yflag1)
{
if ( ((y1-ty) * (x0-x1) >= (x1-tx) * (y0-y1)) == yflag1 )
{
state.inside_flag = ! state.inside_flag;
}
}
state.yflag0 = yflag1;
return true;
}
static inline int result(flags const& state)
{
return state.inside_flag ? 1 : -1;
}
};
}} // namespace strategy::within
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_IN_POLY_CROSSINGS_MULTIPLY_HPP
@@ -0,0 +1,118 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_IN_POLY_FRANKLIN_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_IN_POLY_FRANKLIN_HPP
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace within
{
/*!
\brief Within detection using cross counting
\ingroup strategies
\tparam Point \tparam_point
\tparam PointOfSegment \tparam_segment_point
\tparam CalculationType \tparam_calculation
\author adapted from Randolph Franklin algorithm
\author Barend and Maarten, 1995
\author Revised for templatized library, Barend Gehrels, 2007
\return true if point is in ring, works for closed rings in both directions
\note Does NOT work correctly for point ON border
\qbk{
[heading See also]
[link geometry.reference.algorithms.within.within_3_with_strategy within (with strategy)]
}
*/
template
<
typename Point,
typename PointOfSegment = Point,
typename CalculationType = void
>
class franklin
{
typedef typename select_calculation_type
<
Point,
PointOfSegment,
CalculationType
>::type calculation_type;
/*! subclass to keep state */
class crossings
{
bool crosses;
public :
friend class franklin;
inline crossings()
: crosses(false)
{}
};
public :
typedef Point point_type;
typedef PointOfSegment segment_point_type;
typedef crossings state_type;
static inline bool apply(Point const& point,
PointOfSegment const& seg1, PointOfSegment const& seg2,
crossings& state)
{
calculation_type const& px = get<0>(point);
calculation_type const& py = get<1>(point);
calculation_type const& x1 = get<0>(seg1);
calculation_type const& y1 = get<1>(seg1);
calculation_type const& x2 = get<0>(seg2);
calculation_type const& y2 = get<1>(seg2);
if (
( (y2 <= py && py < y1) || (y1 <= py && py < y2) )
&& (px < (x1 - x2) * (py - y2) / (y1 - y2) + x2)
)
{
state.crosses = ! state.crosses;
}
return true;
}
static inline int result(crossings const& state)
{
return state.crosses ? 1 : -1;
}
};
}} // namespace strategy::within
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_IN_POLY_FRANKLIN_HPP
@@ -0,0 +1,264 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2015.
// Modifications copyright (c) 2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_SIDE_BY_TRIANGLE_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_SIDE_BY_TRIANGLE_HPP
#include <boost/mpl/if.hpp>
#include <boost/type_traits/is_integral.hpp>
#include <boost/type_traits/is_void.hpp>
#include <boost/geometry/arithmetic/determinant.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/algorithms/detail/relate/less.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace side
{
/*!
\brief Check at which side of a segment a point lies:
left of segment (> 0), right of segment (< 0), on segment (0)
\ingroup strategies
\tparam CalculationType \tparam_calculation
*/
template <typename CalculationType = void>
class side_by_triangle
{
template <typename Policy>
struct eps_policy
{
eps_policy() {}
template <typename Type>
eps_policy(Type const& a, Type const& b, Type const& c, Type const& d)
: policy(a, b, c, d)
{}
Policy policy;
};
struct eps_empty
{
eps_empty() {}
template <typename Type>
eps_empty(Type const&, Type const&, Type const&, Type const&) {}
};
public :
// Template member function, because it is not always trivial
// or convenient to explicitly mention the typenames in the
// strategy-struct itself.
// Types can be all three different. Therefore it is
// not implemented (anymore) as "segment"
template
<
typename CoordinateType,
typename PromotedType,
typename P1,
typename P2,
typename P,
typename EpsPolicy
>
static inline
PromotedType side_value(P1 const& p1, P2 const& p2, P const& p, EpsPolicy & eps_policy)
{
CoordinateType const x = get<0>(p);
CoordinateType const y = get<1>(p);
CoordinateType const sx1 = get<0>(p1);
CoordinateType const sy1 = get<1>(p1);
CoordinateType const sx2 = get<0>(p2);
CoordinateType const sy2 = get<1>(p2);
PromotedType const dx = sx2 - sx1;
PromotedType const dy = sy2 - sy1;
PromotedType const dpx = x - sx1;
PromotedType const dpy = y - sy1;
eps_policy = EpsPolicy(dx, dy, dpx, dpy);
return geometry::detail::determinant<PromotedType>
(
dx, dy,
dpx, dpy
);
}
template
<
typename CoordinateType,
typename PromotedType,
typename P1,
typename P2,
typename P
>
static inline
PromotedType side_value(P1 const& p1, P2 const& p2, P const& p)
{
eps_empty dummy;
return side_value<CoordinateType, PromotedType>(p1, p2, p, dummy);
}
template
<
typename CoordinateType,
typename PromotedType,
bool AreAllIntegralCoordinates
>
struct compute_side_value
{
template <typename P1, typename P2, typename P, typename EpsPolicy>
static inline PromotedType apply(P1 const& p1, P2 const& p2, P const& p, EpsPolicy & epsp)
{
return side_value<CoordinateType, PromotedType>(p1, p2, p, epsp);
}
};
template <typename CoordinateType, typename PromotedType>
struct compute_side_value<CoordinateType, PromotedType, false>
{
template <typename P1, typename P2, typename P, typename EpsPolicy>
static inline PromotedType apply(P1 const& p1, P2 const& p2, P const& p, EpsPolicy & epsp)
{
// For robustness purposes, first check if any two points are
// the same; in this case simply return that the points are
// collinear
if (geometry::detail::equals::equals_point_point(p1, p2)
|| geometry::detail::equals::equals_point_point(p1, p)
|| geometry::detail::equals::equals_point_point(p2, p))
{
return PromotedType(0);
}
// The side_by_triangle strategy computes the signed area of
// the point triplet (p1, p2, p); as such it is (in theory)
// invariant under cyclic permutations of its three arguments.
//
// In the context of numerical errors that arise in
// floating-point computations, and in order to make the strategy
// consistent with respect to cyclic permutations of its three
// arguments, we cyclically permute them so that the first
// argument is always the lexicographically smallest point.
geometry::detail::relate::less less;
if (less(p, p1))
{
if (less(p, p2))
{
// p is the lexicographically smallest
return side_value<CoordinateType, PromotedType>(p, p1, p2, epsp);
}
else
{
// p2 is the lexicographically smallest
return side_value<CoordinateType, PromotedType>(p2, p, p1, epsp);
}
}
if (less(p1, p2))
{
// p1 is the lexicographically smallest
return side_value<CoordinateType, PromotedType>(p1, p2, p, epsp);
}
else
{
// p2 is the lexicographically smallest
return side_value<CoordinateType, PromotedType>(p2, p, p1, epsp);
}
}
};
template <typename P1, typename P2, typename P>
static inline int apply(P1 const& p1, P2 const& p2, P const& p)
{
typedef typename coordinate_type<P1>::type coordinate_type1;
typedef typename coordinate_type<P2>::type coordinate_type2;
typedef typename coordinate_type<P>::type coordinate_type3;
typedef typename boost::mpl::if_c
<
boost::is_void<CalculationType>::type::value,
typename select_most_precise
<
typename select_most_precise
<
coordinate_type1, coordinate_type2
>::type,
coordinate_type3
>::type,
CalculationType
>::type coordinate_type;
// Promote float->double, small int->int
typedef typename select_most_precise
<
coordinate_type,
double
>::type promoted_type;
bool const are_all_integral_coordinates =
boost::is_integral<coordinate_type1>::value
&& boost::is_integral<coordinate_type2>::value
&& boost::is_integral<coordinate_type3>::value;
eps_policy< math::detail::equals_factor_policy<promoted_type> > epsp;
promoted_type s = compute_side_value
<
coordinate_type, promoted_type, are_all_integral_coordinates
>::apply(p1, p2, p, epsp);
promoted_type const zero = promoted_type();
return math::detail::equals_by_policy(s, zero, epsp.policy) ? 0
: s > zero ? 1
: -1;
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename CalculationType>
struct default_strategy<cartesian_tag, CalculationType>
{
typedef side_by_triangle<CalculationType> type;
};
}
#endif
}} // namespace strategy::side
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_SIDE_BY_TRIANGLE_HPP
@@ -0,0 +1,349 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2015.
// Modifications copyright (c) 2015, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_SIDE_OF_INTERSECTION_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_SIDE_OF_INTERSECTION_HPP
#include <limits>
#include <boost/core/ignore_unused.hpp>
#include <boost/type_traits/is_integral.hpp>
#include <boost/type_traits/make_unsigned.hpp>
#include <boost/geometry/arithmetic/determinant.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>
#include <boost/geometry/util/math.hpp>
#ifdef BOOST_GEOMETRY_SIDE_OF_INTERSECTION_DEBUG
#include <boost/math/common_factor_ct.hpp>
#include <boost/math/common_factor_rt.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#endif
namespace boost { namespace geometry
{
namespace strategy { namespace side
{
namespace detail
{
// A tool for multiplication of integers avoiding overflow
// It's a temporary workaround until we can use Multiprecision
// The algorithm is based on Karatsuba algorithm
// see: http://en.wikipedia.org/wiki/Karatsuba_algorithm
template <typename T>
struct multiplicable_integral
{
// Currently this tool can't be used with non-integral coordinate types.
// Also side_of_intersection strategy sign_of_product() and sign_of_compare()
// functions would have to be modified to properly support floating-point
// types (comparisons and multiplication).
BOOST_STATIC_ASSERT(boost::is_integral<T>::value);
static const std::size_t bits = CHAR_BIT * sizeof(T);
static const std::size_t half_bits = bits / 2;
typedef typename boost::make_unsigned<T>::type unsigned_type;
static const unsigned_type base = unsigned_type(1) << half_bits; // 2^half_bits
int m_sign;
unsigned_type m_ms;
unsigned_type m_ls;
multiplicable_integral(int sign, unsigned_type ms, unsigned_type ls)
: m_sign(sign), m_ms(ms), m_ls(ls)
{}
explicit multiplicable_integral(T const& val)
{
unsigned_type val_u = val > 0 ?
unsigned_type(val)
: val == (std::numeric_limits<T>::min)() ?
unsigned_type((std::numeric_limits<T>::max)()) + 1
: unsigned_type(-val);
// MMLL -> S 00MM 00LL
m_sign = math::sign(val);
m_ms = val_u >> half_bits; // val_u / base
m_ls = val_u - m_ms * base;
}
friend multiplicable_integral operator*(multiplicable_integral const& a,
multiplicable_integral const& b)
{
// (S 00MM 00LL) * (S 00MM 00LL) -> (S Z2MM 00LL)
unsigned_type z2 = a.m_ms * b.m_ms;
unsigned_type z0 = a.m_ls * b.m_ls;
unsigned_type z1 = (a.m_ms + a.m_ls) * (b.m_ms + b.m_ls) - z2 - z0;
// z0 may be >= base so it must be normalized to allow comparison
unsigned_type z0_ms = z0 >> half_bits; // z0 / base
return multiplicable_integral(a.m_sign * b.m_sign,
z2 * base + z1 + z0_ms,
z0 - base * z0_ms);
}
friend bool operator<(multiplicable_integral const& a,
multiplicable_integral const& b)
{
if ( a.m_sign == b.m_sign )
{
bool u_less = a.m_ms < b.m_ms
|| (a.m_ms == b.m_ms && a.m_ls < b.m_ls);
return a.m_sign > 0 ? u_less : (! u_less);
}
else
{
return a.m_sign < b.m_sign;
}
}
friend bool operator>(multiplicable_integral const& a,
multiplicable_integral const& b)
{
return b < a;
}
template <typename CmpVal>
void check_value(CmpVal const& cmp_val) const
{
unsigned_type b = base; // a workaround for MinGW - undefined reference base
CmpVal val = CmpVal(m_sign) * (CmpVal(m_ms) * CmpVal(b) + CmpVal(m_ls));
BOOST_GEOMETRY_ASSERT(cmp_val == val);
}
};
} // namespace detail
// Calculates the side of the intersection-point (if any) of
// of segment a//b w.r.t. segment c
// This is calculated without (re)calculating the IP itself again and fully
// based on integer mathematics; there are no divisions
// It can be used for either integer (rescaled) points, and also for FP
class side_of_intersection
{
private :
template <typename T, typename U>
static inline
int sign_of_product(T const& a, U const& b)
{
return a == 0 || b == 0 ? 0
: a > 0 && b > 0 ? 1
: a < 0 && b < 0 ? 1
: -1;
}
template <typename T>
static inline
int sign_of_compare(T const& a, T const& b, T const& c, T const& d)
{
// Both a*b and c*d are positive
// We have to judge if a*b > c*d
using side::detail::multiplicable_integral;
multiplicable_integral<T> ab = multiplicable_integral<T>(a)
* multiplicable_integral<T>(b);
multiplicable_integral<T> cd = multiplicable_integral<T>(c)
* multiplicable_integral<T>(d);
int result = ab > cd ? 1
: ab < cd ? -1
: 0
;
#ifdef BOOST_GEOMETRY_SIDE_OF_INTERSECTION_DEBUG
using namespace boost::multiprecision;
cpp_int const lab = cpp_int(a) * cpp_int(b);
cpp_int const lcd = cpp_int(c) * cpp_int(d);
ab.check_value(lab);
cd.check_value(lcd);
int result2 = lab > lcd ? 1
: lab < lcd ? -1
: 0
;
BOOST_GEOMETRY_ASSERT(result == result2);
#endif
return result;
}
template <typename T>
static inline
int sign_of_addition_of_two_products(T const& a, T const& b, T const& c, T const& d)
{
// sign of a*b+c*d, 1 if positive, -1 if negative, else 0
int const ab = sign_of_product(a, b);
int const cd = sign_of_product(c, d);
if (ab == 0)
{
return cd;
}
if (cd == 0)
{
return ab;
}
if (ab == cd)
{
// Both positive or both negative
return ab;
}
// One is positive, one is negative, both are non zero
// If ab is positive, we have to judge if a*b > -c*d (then 1 because sum is positive)
// If ab is negative, we have to judge if c*d > -a*b (idem)
return ab == 1
? sign_of_compare(a, b, -c, d)
: sign_of_compare(c, d, -a, b);
}
public :
// Calculates the side of the intersection-point (if any) of
// of segment a//b w.r.t. segment c
// This is calculated without (re)calculating the IP itself again and fully
// based on integer mathematics
template <typename T, typename Segment, typename Point>
static inline T side_value(Segment const& a, Segment const& b,
Segment const& c, Point const& fallback_point)
{
// The first point of the three segments is reused several times
T const ax = get<0, 0>(a);
T const ay = get<0, 1>(a);
T const bx = get<0, 0>(b);
T const by = get<0, 1>(b);
T const cx = get<0, 0>(c);
T const cy = get<0, 1>(c);
T const dx_a = get<1, 0>(a) - ax;
T const dy_a = get<1, 1>(a) - ay;
T const dx_b = get<1, 0>(b) - bx;
T const dy_b = get<1, 1>(b) - by;
T const dx_c = get<1, 0>(c) - cx;
T const dy_c = get<1, 1>(c) - cy;
// Cramer's rule: d (see cart_intersect.hpp)
T const d = geometry::detail::determinant<T>
(
dx_a, dy_a,
dx_b, dy_b
);
T const zero = T();
if (d == zero)
{
// There is no IP of a//b, they are collinear or parallel
// Assuming they intersect (this method should be called for
// segments known to intersect), they are collinear and overlap.
// They have one or two intersection points - we don't know and
// have to rely on the fallback intersection point
Point c1, c2;
geometry::detail::assign_point_from_index<0>(c, c1);
geometry::detail::assign_point_from_index<1>(c, c2);
return side_by_triangle<>::apply(c1, c2, fallback_point);
}
// Cramer's rule: da (see cart_intersect.hpp)
T const da = geometry::detail::determinant<T>
(
dx_b, dy_b,
ax - bx, ay - by
);
// IP is at (ax + (da/d) * dx_a, ay + (da/d) * dy_a)
// Side of IP is w.r.t. c is: determinant(dx_c, dy_c, ipx-cx, ipy-cy)
// We replace ipx by expression above and multiply each term by d
#ifdef BOOST_GEOMETRY_SIDE_OF_INTERSECTION_DEBUG
T const result1 = geometry::detail::determinant<T>
(
dx_c * d, dy_c * d,
d * (ax - cx) + dx_a * da, d * (ay - cy) + dy_a * da
);
// Note: result / (d * d)
// is identical to the side_value of side_by_triangle
// Therefore, the sign is always the same as that result, and the
// resulting side (left,right,collinear) is the same
// The first row we divide again by d because of determinant multiply rule
T const result2 = d * geometry::detail::determinant<T>
(
dx_c, dy_c,
d * (ax - cx) + dx_a * da, d * (ay - cy) + dy_a * da
);
// Write out:
T const result3 = d * (dx_c * (d * (ay - cy) + dy_a * da)
- dy_c * (d * (ax - cx) + dx_a * da));
// Write out in braces:
T const result4 = d * (dx_c * d * (ay - cy) + dx_c * dy_a * da
- dy_c * d * (ax - cx) - dy_c * dx_a * da);
// Write in terms of d * XX + da * YY
T const result5 = d * (d * (dx_c * (ay - cy) - dy_c * (ax - cx))
+ da * (dx_c * dy_a - dy_c * dx_a));
boost::ignore_unused(result1, result2, result3, result4, result5);
//return result;
#endif
// We consider the results separately
// (in the end we only have to return the side-value 1,0 or -1)
// To avoid multiplications we judge the product (easy, avoids *d)
// and the sign of p*q+r*s (more elaborate)
T const result = sign_of_product
(
d,
sign_of_addition_of_two_products
(
d, dx_c * (ay - cy) - dy_c * (ax - cx),
da, dx_c * dy_a - dy_c * dx_a
)
);
return result;
}
template <typename Segment, typename Point>
static inline int apply(Segment const& a, Segment const& b,
Segment const& c,
Point const& fallback_point)
{
typedef typename geometry::coordinate_type<Segment>::type coordinate_type;
coordinate_type const s = side_value<coordinate_type>(a, b, c, fallback_point);
coordinate_type const zero = coordinate_type();
return math::equals(s, zero) ? 0
: s > zero ? 1
: -1;
}
};
}} // namespace strategy::side
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_SIDE_OF_INTERSECTION_HPP
@@ -0,0 +1,72 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CENTROID_HPP
#define BOOST_GEOMETRY_STRATEGIES_CENTROID_HPP
#include <cstddef>
#include <boost/mpl/assert.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/strategies/tags.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace centroid
{
struct not_applicable_strategy
{
};
namespace services
{
/*!
\brief Traits class binding a centroid calculation strategy to a coordinate system
\ingroup centroid
\tparam CsTag tag of coordinate system, for specialization
\tparam GeometryTag tag of geometry, for specialization
\tparam Dimension dimension of geometry, for specialization
\tparam Point point-type
\tparam Geometry
*/
template
<
typename CsTag,
typename GeometryTag,
std::size_t Dimension,
typename Point,
typename Geometry
>
struct default_strategy
{
typedef not_applicable_strategy type;
};
} // namespace services
}} // namespace strategy::centroid
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CENTROID_HPP
@@ -0,0 +1,196 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_STRATEGIES_COMPARABLE_DISTANCE_RESULT_HPP
#define BOOST_GEOMETRY_STRATEGIES_COMPARABLE_DISTANCE_RESULT_HPP
#include <boost/mpl/always.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/util/compress_variant.hpp>
#include <boost/geometry/util/transform_variant.hpp>
#include <boost/geometry/util/combine_if.hpp>
#include <boost/geometry/algorithms/detail/distance/default_strategies.hpp>
namespace boost { namespace geometry
{
namespace resolve_strategy
{
template <typename Geometry1, typename Geometry2, typename Strategy>
struct comparable_distance_result
: strategy::distance::services::return_type
<
typename strategy::distance::services::comparable_type
<
Strategy
>::type,
typename point_type<Geometry1>::type,
typename point_type<Geometry2>::type
>
{};
template <typename Geometry1, typename Geometry2>
struct comparable_distance_result<Geometry1, Geometry2, default_strategy>
: comparable_distance_result
<
Geometry1,
Geometry2,
typename detail::distance::default_strategy
<
Geometry1, Geometry2
>::type
>
{};
} // namespace resolve_strategy
namespace resolve_variant
{
template <typename Geometry1, typename Geometry2, typename Strategy>
struct comparable_distance_result
: resolve_strategy::comparable_distance_result
<
Geometry1,
Geometry2,
Strategy
>
{};
template
<
typename Geometry1,
BOOST_VARIANT_ENUM_PARAMS(typename T),
typename Strategy
>
struct comparable_distance_result
<
Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Strategy
>
{
// A set of all variant type combinations that are compatible and
// implemented
typedef typename util::combine_if<
typename boost::mpl::vector1<Geometry1>,
typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types,
boost::mpl::always<boost::mpl::true_>
>::type possible_input_types;
// The (possibly variant) result type resulting from these combinations
typedef typename compress_variant<
typename transform_variant<
possible_input_types,
resolve_strategy::comparable_distance_result<
boost::mpl::first<boost::mpl::_>,
boost::mpl::second<boost::mpl::_>,
Strategy
>,
boost::mpl::back_inserter<boost::mpl::vector0<> >
>::type
>::type type;
};
// Distance arguments are commutative
template
<
BOOST_VARIANT_ENUM_PARAMS(typename T),
typename Geometry2,
typename Strategy
>
struct comparable_distance_result
<
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
Geometry2,
Strategy
> : public comparable_distance_result
<
Geometry2, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Strategy
>
{};
template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Strategy>
struct comparable_distance_result
<
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
Strategy
>
{
// A set of all variant type combinations that are compatible and
// implemented
typedef typename util::combine_if
<
typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types,
typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types,
boost::mpl::always<boost::mpl::true_>
>::type possible_input_types;
// The (possibly variant) result type resulting from these combinations
typedef typename compress_variant<
typename transform_variant<
possible_input_types,
resolve_strategy::comparable_distance_result<
boost::mpl::first<boost::mpl::_>,
boost::mpl::second<boost::mpl::_>,
Strategy
>,
boost::mpl::back_inserter<boost::mpl::vector0<> >
>::type
>::type type;
};
} // namespace resolve_variant
/*!
\brief Meta-function defining return type of comparable_distance function
\ingroup distance
*/
template
<
typename Geometry1,
typename Geometry2 = Geometry1,
typename Strategy = void
>
struct comparable_distance_result
: resolve_variant::comparable_distance_result
<
Geometry1, Geometry2, Strategy
>
{};
template <typename Geometry1, typename Geometry2>
struct comparable_distance_result<Geometry1, Geometry2, void>
: comparable_distance_result<Geometry1, Geometry2, default_strategy>
{};
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_COMPARABLE_DISTANCE_RESULT_HPP
@@ -0,0 +1,172 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_COMPARE_HPP
#define BOOST_GEOMETRY_STRATEGIES_COMPARE_HPP
#include <cstddef>
#include <functional>
#include <boost/mpl/if.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/strategies/tags.hpp>
namespace boost { namespace geometry
{
/*!
\brief Traits class binding a comparing strategy to a coordinate system
\ingroup util
\tparam Tag tag of coordinate system of point-type
\tparam Direction direction to compare on: 1 for less (-> ascending order)
and -1 for greater (-> descending order)
\tparam Point point-type
\tparam CoordinateSystem coordinate sytem of point
\tparam Dimension: the dimension to compare on
*/
template
<
typename Tag,
int Direction,
typename Point,
typename CoordinateSystem,
std::size_t Dimension
>
struct strategy_compare
{
typedef strategy::not_implemented type;
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
// For compare we add defaults specializations,
// because they defaultly redirect to std::less / greater / equal_to
template
<
typename Tag,
typename Point,
typename CoordinateSystem,
std::size_t Dimension
>
struct strategy_compare<Tag, 1, Point, CoordinateSystem, Dimension>
{
typedef std::less<typename coordinate_type<Point>::type> type;
};
template
<
typename Tag,
typename Point,
typename CoordinateSystem,
std::size_t Dimension
>
struct strategy_compare<Tag, -1, Point, CoordinateSystem, Dimension>
{
typedef std::greater<typename coordinate_type<Point>::type> type;
};
template
<
typename Tag,
typename Point,
typename CoordinateSystem,
std::size_t Dimension
>
struct strategy_compare<Tag, 0, Point, CoordinateSystem, Dimension>
{
typedef std::equal_to<typename coordinate_type<Point>::type> type;
};
#endif
namespace strategy { namespace compare
{
/*!
\brief Default strategy, indicates the default strategy for comparisons
\details The default strategy for comparisons defer in most cases
to std::less (for ascending) and std::greater (for descending).
However, if a spherical coordinate system is used, and comparison
is done on longitude, it will take another strategy handling circular
*/
struct default_strategy {};
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template <typename Type>
struct is_default : boost::false_type
{};
template <>
struct is_default<default_strategy> : boost::true_type
{};
/*!
\brief Meta-function to select strategy
\details If "default_strategy" is specified, it will take the
traits-registered class for the specified coordinate system.
If another strategy is explicitly specified, it takes that one.
*/
template
<
typename Strategy,
int Direction,
typename Point,
std::size_t Dimension
>
struct select_strategy
{
typedef typename
boost::mpl::if_
<
is_default<Strategy>,
typename strategy_compare
<
typename cs_tag<Point>::type,
Direction,
Point,
typename coordinate_system<Point>::type,
Dimension
>::type,
Strategy
>::type type;
};
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
}} // namespace strategy::compare
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_COMPARE_HPP
@@ -0,0 +1,75 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CONCEPTS_AREA_CONCEPT_HPP
#define BOOST_GEOMETRY_STRATEGIES_CONCEPTS_AREA_CONCEPT_HPP
#include <boost/concept_check.hpp>
namespace boost { namespace geometry { namespace concepts
{
/*!
\brief Checks strategy for area
\ingroup area
*/
template <typename Strategy>
class AreaStrategy
{
#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
// 1) must define state_type,
typedef typename Strategy::state_type state_type;
// 2) must define return_type,
typedef typename Strategy::return_type return_type;
// 3) must define point_type, of polygon (segments)
typedef typename Strategy::segment_point_type spoint_type;
struct check_methods
{
static void apply()
{
Strategy const* str = 0;
state_type *st = 0;
// 4) must implement a method apply with the following signature
spoint_type const* sp = 0;
str->apply(*sp, *sp, *st);
// 5) must implement a static method result with the following signature
return_type r = str->result(*st);
boost::ignore_unused_variable_warning(r);
boost::ignore_unused_variable_warning(str);
}
};
public :
BOOST_CONCEPT_USAGE(AreaStrategy)
{
check_methods::apply();
}
#endif
};
}}} // namespace boost::geometry::concepts
#endif // BOOST_GEOMETRY_STRATEGIES_CONCEPTS_AREA_CONCEPT_HPP
@@ -0,0 +1,78 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CONCEPTS_CENTROID_CONCEPT_HPP
#define BOOST_GEOMETRY_STRATEGIES_CONCEPTS_CENTROID_CONCEPT_HPP
#include <boost/concept_check.hpp>
namespace boost { namespace geometry { namespace concepts
{
/*!
\brief Checks strategy for centroid
\ingroup centroid
*/
template <typename Strategy>
class CentroidStrategy
{
#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
// 1) must define state_type,
typedef typename Strategy::state_type state_type;
// 2) must define point_type,
typedef typename Strategy::point_type point_type;
// 3) must define point_type, of polygon (segments)
typedef typename Strategy::segment_point_type spoint_type;
struct check_methods
{
static void apply()
{
Strategy *str = 0;
state_type *st = 0;
// 4) must implement a static method apply,
// getting two segment-points
spoint_type const* sp = 0;
str->apply(*sp, *sp, *st);
// 5) must implement a static method result
// getting the centroid
point_type *c = 0;
bool r = str->result(*st, *c);
boost::ignore_unused_variable_warning(str);
boost::ignore_unused_variable_warning(r);
}
};
public :
BOOST_CONCEPT_USAGE(CentroidStrategy)
{
check_methods::apply();
}
#endif
};
}}} // namespace boost::geometry::concepts
#endif // BOOST_GEOMETRY_STRATEGIES_CONCEPTS_CENTROID_CONCEPT_HPP
@@ -0,0 +1,80 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CONCEPTS_CONVEX_HULL_CONCEPT_HPP
#define BOOST_GEOMETRY_STRATEGIES_CONCEPTS_CONVEX_HULL_CONCEPT_HPP
#include <vector>
#include <boost/concept_check.hpp>
namespace boost { namespace geometry { namespace concepts
{
/*!
\brief Checks strategy for convex_hull
\ingroup convex_hull
*/
template <typename Strategy>
class ConvexHullStrategy
{
#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
// 1) must define state_type
typedef typename Strategy::state_type state_type;
// 2) must define point_type
typedef typename Strategy::point_type point_type;
// 3) must define geometry_type
typedef typename Strategy::geometry_type geometry_type;
struct check_methods
{
static void apply()
{
Strategy const* str = 0;
state_type* st = 0;
geometry_type* sp = 0;
std::vector<point_type> *v = 0;
// 4) must implement a method apply, iterating over a range
str->apply(*sp, *st);
// 5) must implement a method result, with an output iterator
str->result(*st, std::back_inserter(*v), true, true);
}
};
public :
BOOST_CONCEPT_USAGE(ConvexHullStrategy)
{
check_methods::apply();
}
#endif
};
}}} // namespace boost::geometry::concepts
#endif // BOOST_GEOMETRY_STRATEGIES_CONCEPTS_CONVEX_HULL_CONCEPT_HPP
@@ -0,0 +1,212 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CONCEPTS_DISTANCE_CONCEPT_HPP
#define BOOST_GEOMETRY_STRATEGIES_CONCEPTS_DISTANCE_CONCEPT_HPP
#include <vector>
#include <iterator>
#include <boost/concept_check.hpp>
#include <boost/core/ignore_unused.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/geometry/util/parameter_type_of.hpp>
#include <boost/geometry/geometries/concepts/point_concept.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/strategies/tags.hpp>
namespace boost { namespace geometry { namespace concepts
{
/*!
\brief Checks strategy for point-point or point-box or box-box distance
\ingroup distance
*/
template <typename Strategy, typename Point1, typename Point2>
struct PointDistanceStrategy
{
#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
private :
struct checker
{
template <typename ApplyMethod>
static void apply(ApplyMethod)
{
// 1: inspect and define both arguments of apply
typedef typename parameter_type_of
<
ApplyMethod, 0
>::type ptype1;
typedef typename parameter_type_of
<
ApplyMethod, 1
>::type ptype2;
// 2) must define meta-function "return_type"
typedef typename strategy::distance::services::return_type
<
Strategy, ptype1, ptype2
>::type rtype;
// 3) must define meta-function "comparable_type"
typedef typename strategy::distance::services::comparable_type
<
Strategy
>::type ctype;
// 4) must define meta-function "tag"
typedef typename strategy::distance::services::tag
<
Strategy
>::type tag;
static const bool is_correct_strategy_tag =
boost::is_same<tag, strategy_tag_distance_point_point>::value
|| boost::is_same<tag, strategy_tag_distance_point_box>::value
|| boost::is_same<tag, strategy_tag_distance_box_box>::value;
BOOST_MPL_ASSERT_MSG
((is_correct_strategy_tag),
INCORRECT_STRATEGY_TAG,
(types<tag>));
// 5) must implement apply with arguments
Strategy* str = 0;
ptype1 *p1 = 0;
ptype2 *p2 = 0;
rtype r = str->apply(*p1, *p2);
// 6) must define (meta)struct "get_comparable" with apply
ctype c = strategy::distance::services::get_comparable
<
Strategy
>::apply(*str);
// 7) must define (meta)struct "result_from_distance" with apply
r = strategy::distance::services::result_from_distance
<
Strategy,
ptype1, ptype2
>::apply(*str, 1.0);
boost::ignore_unused<tag>();
boost::ignore_unused(str, c, r);
}
};
public :
BOOST_CONCEPT_USAGE(PointDistanceStrategy)
{
checker::apply(&Strategy::template apply<Point1, Point2>);
}
#endif
};
/*!
\brief Checks strategy for point-segment distance
\ingroup strategy_concepts
*/
template <typename Strategy, typename Point, typename PointOfSegment>
struct PointSegmentDistanceStrategy
{
#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
private :
struct checker
{
template <typename ApplyMethod>
static void apply(ApplyMethod)
{
// 1) inspect and define both arguments of apply
typedef typename parameter_type_of
<
ApplyMethod, 0
>::type ptype;
typedef typename parameter_type_of
<
ApplyMethod, 1
>::type sptype;
namespace services = strategy::distance::services;
// 2) must define meta-function "tag"
typedef typename services::tag<Strategy>::type tag;
BOOST_MPL_ASSERT_MSG
((boost::is_same
<
tag, strategy_tag_distance_point_segment
>::value),
INCORRECT_STRATEGY_TAG,
(types<tag>));
// 3) must define meta-function "return_type"
typedef typename services::return_type
<
Strategy, ptype, sptype
>::type rtype;
// 4) must define meta-function "comparable_type"
typedef typename services::comparable_type<Strategy>::type ctype;
// 5) must implement apply with arguments
Strategy *str = 0;
ptype *p = 0;
sptype *sp1 = 0;
sptype *sp2 = 0;
rtype r = str->apply(*p, *sp1, *sp2);
// 6) must define (meta-)struct "get_comparable" with apply
ctype cstrategy = services::get_comparable<Strategy>::apply(*str);
// 7) must define (meta-)struct "result_from_distance" with apply
r = services::result_from_distance
<
Strategy, ptype, sptype
>::apply(*str, rtype(1.0));
boost::ignore_unused(str, r, cstrategy);
}
};
public :
BOOST_CONCEPT_USAGE(PointSegmentDistanceStrategy)
{
checker::apply(&Strategy::template apply<Point, PointOfSegment>);
}
#endif
};
}}} // namespace boost::geometry::concepts
#endif // BOOST_GEOMETRY_STRATEGIES_CONCEPTS_DISTANCE_CONCEPT_HPP
@@ -0,0 +1,78 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CONCEPTS_SEGMENT_INTERSECT_CONCEPT_HPP
#define BOOST_GEOMETRY_STRATEGIES_CONCEPTS_SEGMENT_INTERSECT_CONCEPT_HPP
//NOT FINISHED!
#include <boost/concept_check.hpp>
namespace boost { namespace geometry { namespace concepts
{
/*!
\brief Checks strategy for segment intersection
\ingroup segment_intersection
*/
template <typename Strategy>
class SegmentIntersectStrategy
{
#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
// 1) must define return_type
typedef typename Strategy::return_type return_type;
// 2) must define point_type (of segment points)
//typedef typename Strategy::point_type point_type;
// 3) must define segment_type 1 and 2 (of segment points)
typedef typename Strategy::segment_type1 segment_type1;
typedef typename Strategy::segment_type2 segment_type2;
struct check_methods
{
static void apply()
{
Strategy const* str;
return_type* rt;
//point_type const* p;
segment_type1 const* s1;
segment_type2 const* s2;
// 4) must implement a method apply
// having two segments
*rt = str->apply(*s1, *s2);
}
};
public :
BOOST_CONCEPT_USAGE(SegmentIntersectStrategy)
{
check_methods::apply();
}
#endif
};
}}} // namespace boost::geometry::concepts
#endif // BOOST_GEOMETRY_STRATEGIES_CONCEPTS_SEGMENT_INTERSECT_CONCEPT_HPP
@@ -0,0 +1,96 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CONCEPTS_SIMPLIFY_CONCEPT_HPP
#define BOOST_GEOMETRY_STRATEGIES_CONCEPTS_SIMPLIFY_CONCEPT_HPP
#include <vector>
#include <iterator>
#include <boost/concept_check.hpp>
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/strategies/concepts/distance_concept.hpp>
namespace boost { namespace geometry { namespace concepts
{
/*!
\brief Checks strategy for simplify
\ingroup simplify
*/
template <typename Strategy, typename Point>
struct SimplifyStrategy
{
#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
private :
// 1) must define distance_strategy_type,
// defining point-segment distance strategy (to be checked)
typedef typename Strategy::distance_strategy_type ds_type;
struct checker
{
template <typename ApplyMethod>
static void apply(ApplyMethod)
{
namespace ft = boost::function_types;
typedef typename ft::parameter_types
<
ApplyMethod
>::type parameter_types;
typedef typename boost::mpl::if_
<
ft::is_member_function_pointer<ApplyMethod>,
boost::mpl::int_<1>,
boost::mpl::int_<0>
>::type base_index;
BOOST_CONCEPT_ASSERT
(
(concepts::PointSegmentDistanceStrategy<ds_type, Point, Point>)
);
Strategy *str = 0;
std::vector<Point> const* v1 = 0;
std::vector<Point> * v2 = 0;
// 2) must implement method apply with arguments
// - Range
// - OutputIterator
// - floating point value
str->apply(*v1, std::back_inserter(*v2), 1.0);
boost::ignore_unused<parameter_types, base_index>();
boost::ignore_unused(str);
}
};
public :
BOOST_CONCEPT_USAGE(SimplifyStrategy)
{
checker::apply(&ds_type::template apply<Point, Point>);
}
#endif
};
}}} // namespace boost::geometry::concepts
#endif // BOOST_GEOMETRY_STRATEGIES_CONCEPTS_SIMPLIFY_CONCEPT_HPP
@@ -0,0 +1,291 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CONCEPTS_WITHIN_CONCEPT_HPP
#define BOOST_GEOMETRY_STRATEGIES_CONCEPTS_WITHIN_CONCEPT_HPP
#include <boost/concept_check.hpp>
#include <boost/function_types/result_type.hpp>
#include <boost/geometry/util/parameter_type_of.hpp>
namespace boost { namespace geometry { namespace concepts
{
/*!
\brief Checks strategy for within (point-in-polygon)
\ingroup within
*/
template <typename Strategy>
class WithinStrategyPolygonal
{
#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
// 1) must define state_type
typedef typename Strategy::state_type state_type;
struct checker
{
template <typename ApplyMethod, typename ResultMethod>
static void apply(ApplyMethod const&, ResultMethod const& )
{
typedef typename parameter_type_of
<
ApplyMethod, 0
>::type point_type;
typedef typename parameter_type_of
<
ApplyMethod, 1
>::type segment_point_type;
// CHECK: apply-arguments should both fulfill point concept
BOOST_CONCEPT_ASSERT
(
(concepts::ConstPoint<point_type>)
);
BOOST_CONCEPT_ASSERT
(
(concepts::ConstPoint<segment_point_type>)
);
// CHECK: return types (result: int, apply: bool)
BOOST_MPL_ASSERT_MSG
(
(boost::is_same
<
bool, typename boost::function_types::result_type<ApplyMethod>::type
>::type::value),
WRONG_RETURN_TYPE_OF_APPLY
, (bool)
);
BOOST_MPL_ASSERT_MSG
(
(boost::is_same
<
int, typename boost::function_types::result_type<ResultMethod>::type
>::type::value),
WRONG_RETURN_TYPE_OF_RESULT
, (int)
);
// CHECK: calling method apply and result
Strategy const* str = 0;
state_type* st = 0;
point_type const* p = 0;
segment_point_type const* sp = 0;
bool b = str->apply(*p, *sp, *sp, *st);
int r = str->result(*st);
boost::ignore_unused_variable_warning(r);
boost::ignore_unused_variable_warning(b);
boost::ignore_unused_variable_warning(str);
}
};
public :
BOOST_CONCEPT_USAGE(WithinStrategyPolygonal)
{
checker::apply(&Strategy::apply, &Strategy::result);
}
#endif
};
template <typename Strategy>
class WithinStrategyPointBox
{
#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
struct checker
{
template <typename ApplyMethod>
static void apply(ApplyMethod const&)
{
typedef typename parameter_type_of
<
ApplyMethod, 0
>::type point_type;
typedef typename parameter_type_of
<
ApplyMethod, 1
>::type box_type;
// CHECK: apply-arguments should fulfill point/box concept
BOOST_CONCEPT_ASSERT
(
(concepts::ConstPoint<point_type>)
);
BOOST_CONCEPT_ASSERT
(
(concepts::ConstBox<box_type>)
);
// CHECK: return types (apply: bool)
BOOST_MPL_ASSERT_MSG
(
(boost::is_same
<
bool,
typename boost::function_types::result_type<ApplyMethod>::type
>::type::value),
WRONG_RETURN_TYPE
, (bool)
);
// CHECK: calling method apply
Strategy const* str = 0;
point_type const* p = 0;
box_type const* bx = 0;
bool b = str->apply(*p, *bx);
boost::ignore_unused_variable_warning(b);
boost::ignore_unused_variable_warning(str);
}
};
public :
BOOST_CONCEPT_USAGE(WithinStrategyPointBox)
{
checker::apply(&Strategy::apply);
}
#endif
};
template <typename Strategy>
class WithinStrategyBoxBox
{
#ifndef DOXYGEN_NO_CONCEPT_MEMBERS
struct checker
{
template <typename ApplyMethod>
static void apply(ApplyMethod const&)
{
typedef typename parameter_type_of
<
ApplyMethod, 0
>::type box_type1;
typedef typename parameter_type_of
<
ApplyMethod, 1
>::type box_type2;
// CHECK: apply-arguments should both fulfill box concept
BOOST_CONCEPT_ASSERT
(
(concepts::ConstBox<box_type1>)
);
BOOST_CONCEPT_ASSERT
(
(concepts::ConstBox<box_type2>)
);
// CHECK: return types (apply: bool)
BOOST_MPL_ASSERT_MSG
(
(boost::is_same
<
bool,
typename boost::function_types::result_type<ApplyMethod>::type
>::type::value),
WRONG_RETURN_TYPE
, (bool)
);
// CHECK: calling method apply
Strategy const* str = 0;
box_type1 const* b1 = 0;
box_type2 const* b2 = 0;
bool b = str->apply(*b1, *b2);
boost::ignore_unused_variable_warning(b);
boost::ignore_unused_variable_warning(str);
}
};
public :
BOOST_CONCEPT_USAGE(WithinStrategyBoxBox)
{
checker::apply(&Strategy::apply);
}
#endif
};
// So now: boost::geometry::concepts::within
namespace within
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename FirstTag, typename SecondTag, typename CastedTag, typename Strategy>
struct check_within
{};
template <typename AnyTag, typename Strategy>
struct check_within<point_tag, AnyTag, areal_tag, Strategy>
{
BOOST_CONCEPT_ASSERT( (WithinStrategyPolygonal<Strategy>) );
};
template <typename Strategy>
struct check_within<point_tag, box_tag, areal_tag, Strategy>
{
BOOST_CONCEPT_ASSERT( (WithinStrategyPointBox<Strategy>) );
};
template <typename Strategy>
struct check_within<box_tag, box_tag, areal_tag, Strategy>
{
BOOST_CONCEPT_ASSERT( (WithinStrategyBoxBox<Strategy>) );
};
} // namespace dispatch
#endif
/*!
\brief Checks, in compile-time, the concept of any within-strategy
\ingroup concepts
*/
template <typename FirstTag, typename SecondTag, typename CastedTag, typename Strategy>
inline void check()
{
dispatch::check_within<FirstTag, SecondTag, CastedTag, Strategy> c;
boost::ignore_unused_variable_warning(c);
}
}}}} // namespace boost::geometry::concepts::within
#endif // BOOST_GEOMETRY_STRATEGIES_CONCEPTS_WITHIN_CONCEPT_HPP
@@ -0,0 +1,47 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_CONVEX_HULL_HPP
#define BOOST_GEOMETRY_STRATEGIES_CONVEX_HULL_HPP
#include <boost/geometry/strategies/tags.hpp>
namespace boost { namespace geometry
{
/*!
\brief Traits class binding a convex hull calculation strategy to a coordinate system
\ingroup convex_hull
\tparam Tag tag of coordinate system
\tparam Geometry the geometry type (hull operates internally per hull over geometry)
\tparam Point point-type of output points
*/
template
<
typename Geometry1,
typename Point,
typename CsTag = typename cs_tag<Point>::type
>
struct strategy_convex_hull
{
typedef strategy::not_implemented type;
};
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CONVEX_HULL_HPP
@@ -0,0 +1,99 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_COVERED_BY_HPP
#define BOOST_GEOMETRY_STRATEGIES_COVERED_BY_HPP
#include <boost/mpl/assert.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/tag_cast.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace covered_by
{
namespace services
{
/*!
\brief Traits class binding a covered_by determination strategy to a coordinate system
\ingroup covered_by
\tparam GeometryContained geometry-type of input (possibly) contained type
\tparam GeometryContaining geometry-type of input (possibly) containing type
\tparam TagContained casted tag of (possibly) contained type
\tparam TagContaining casted tag of (possibly) containing type
\tparam CsTagContained tag of coordinate system of (possibly) contained type
\tparam CsTagContaining tag of coordinate system of (possibly) containing type
*/
template
<
typename GeometryContained,
typename GeometryContaining,
typename TagContained = typename tag<GeometryContained>::type,
typename TagContaining = typename tag<GeometryContaining>::type,
typename CastedTagContained = typename tag_cast
<
typename tag<GeometryContained>::type,
pointlike_tag, linear_tag, polygonal_tag, areal_tag
>::type,
typename CastedTagContaining = typename tag_cast
<
typename tag<GeometryContaining>::type,
pointlike_tag, linear_tag, polygonal_tag, areal_tag
>::type,
typename CsTagContained = typename tag_cast
<
typename cs_tag<typename point_type<GeometryContained>::type>::type,
spherical_tag
>::type,
typename CsTagContaining = typename tag_cast
<
typename cs_tag<typename point_type<GeometryContaining>::type>::type,
spherical_tag
>::type
>
struct default_strategy
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_IMPLEMENTED_FOR_THESE_TYPES
, (types<GeometryContained, GeometryContaining>)
);
};
} // namespace services
}} // namespace strategy::covered_by
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_COVERED_BY_HPP
@@ -0,0 +1,51 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_DEFAULT_AREA_RESULT_HPP
#define BOOST_GEOMETRY_STRATEGIES_DEFAULT_AREA_RESULT_HPP
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/strategies/area.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
namespace boost { namespace geometry
{
/*!
\brief Meta-function defining return type of area function, using the default strategy
\ingroup area
\note The strategy defines the return-type (so this situation is different
from length, where distance is sqr/sqrt, but length always squared)
*/
template <typename Geometry>
struct default_area_result
{
typedef typename point_type<Geometry>::type point_type;
typedef typename strategy::area::services::default_strategy
<
typename cs_tag<point_type>::type,
point_type
>::type strategy_type;
typedef typename strategy_type::return_type type;
};
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_DEFAULT_AREA_RESULT_HPP
@@ -0,0 +1,43 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_DEFAULT_COMPARABLE_DISTANCE_RESULT_HPP
#define BOOST_GEOMETRY_STRATEGIES_DEFAULT_COMPARABLE_DISTANCE_RESULT_HPP
#include <boost/geometry/strategies/comparable_distance_result.hpp>
namespace boost { namespace geometry
{
/*!
\brief Meta-function defining return type of comparable_distance function
\ingroup distance
\note The strategy defines the return-type (so this situation is different
from length, where distance is sqr/sqrt, but length always squared)
*/
template <typename Geometry1, typename Geometry2 = Geometry1>
struct default_comparable_distance_result
: comparable_distance_result<Geometry1, Geometry2, void>
{};
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_DEFAULT_COMPARABLE_DISTANCE_RESULT_HPP
@@ -0,0 +1,43 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_DEFAULT_DISTANCE_RESULT_HPP
#define BOOST_GEOMETRY_STRATEGIES_DEFAULT_DISTANCE_RESULT_HPP
#include <boost/geometry/strategies/distance_result.hpp>
namespace boost { namespace geometry
{
/*!
\brief Meta-function defining return type of distance function
\ingroup distance
\note The strategy defines the return-type (so this situation is different
from length, where distance is sqr/sqrt, but length always squared)
*/
template <typename Geometry1, typename Geometry2 = Geometry1>
struct default_distance_result
: distance_result<Geometry1, Geometry2, void>
{};
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_DEFAULT_DISTANCE_RESULT_HPP
@@ -0,0 +1,89 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_DEFAULT_LENGTH_RESULT_HPP
#define BOOST_GEOMETRY_STRATEGIES_DEFAULT_LENGTH_RESULT_HPP
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/util/compress_variant.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
#include <boost/geometry/util/transform_variant.hpp>
namespace boost { namespace geometry
{
namespace resolve_strategy
{
template <typename Geometry>
struct default_length_result
{
typedef typename select_most_precise
<
typename coordinate_type<Geometry>::type,
long double
>::type type;
};
} // namespace resolve_strategy
namespace resolve_variant
{
template <typename Geometry>
struct default_length_result
: resolve_strategy::default_length_result<Geometry>
{};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct default_length_result<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
typedef typename compress_variant<
typename transform_variant<
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
resolve_strategy::default_length_result<boost::mpl::placeholders::_>
>::type
>::type type;
};
} // namespace resolve_variant
/*!
\brief Meta-function defining return type of length function
\ingroup length
\note Length of a line of integer coordinates can be double.
So we take at least a double. If Big Number types are used,
we take that type.
*/
template <typename Geometry>
struct default_length_result
: resolve_variant::default_length_result<Geometry>
{};
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_DEFAULT_LENGTH_RESULT_HPP
@@ -0,0 +1,34 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2008-2013 Bruno Lalande, Paris, France.
// Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2009-2013 Mateusz Loskot, London, UK.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_DEFAULT_STRATEGY_HPP
#define BOOST_GEOMETRY_STRATEGIES_DEFAULT_STRATEGY_HPP
namespace boost { namespace geometry
{
// This is a strategy placeholder type, which is passed by the algorithm free
// functions to the multi-stage resolving process. It's resolved into an actual
// strategy type during the resolve_strategy stage, possibly depending on the
// input geometry type(s). This typically happens after the resolve_variant
// stage, as it needs to be based on concrete geometry types - as opposed to
// variant geometry types.
struct default_strategy {};
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_DEFAULT_STRATEGY_HPP
@@ -0,0 +1,90 @@
// Boost.Geometry
// Copyright (c) 2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_DISJOINT_HPP
#define BOOST_GEOMETRY_STRATEGIES_DISJOINT_HPP
#include <boost/mpl/assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/topological_dimension.hpp>
#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/relate.hpp>
namespace boost { namespace geometry { namespace strategy { namespace disjoint
{
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template
<
typename Geometry1,
typename Geometry2,
typename Tag1 = typename geometry::tag<Geometry1>::type,
typename Tag2 = typename geometry::tag<Geometry2>::type,
int TopDim1 = geometry::topological_dimension<Geometry1>::value,
int TopDim2 = geometry::topological_dimension<Geometry2>::value
>
struct default_strategy
: relate::services::default_strategy
<
Geometry1, Geometry2
>
{};
template <typename Point, typename Box>
struct default_strategy<Point, Box, point_tag, box_tag, 0, 2>
: strategy::covered_by::services::default_strategy<Point, Box>
{};
template <typename Box, typename Point>
struct default_strategy<Box, Point, box_tag, point_tag, 2, 0>
: strategy::covered_by::services::default_strategy<Point, Box>
{};
template <typename MultiPoint, typename Box>
struct default_strategy<MultiPoint, Box, multi_point_tag, box_tag, 0, 2>
: strategy::covered_by::services::default_strategy
<
typename point_type<MultiPoint>::type,
Box
>
{};
template <typename Box, typename MultiPoint>
struct default_strategy<Box, MultiPoint, box_tag, multi_point_tag, 2, 0>
: strategy::covered_by::services::default_strategy
<
typename point_type<MultiPoint>::type,
Box
>
{};
template <typename Box1, typename Box2>
struct default_strategy<Box1, Box2, box_tag, box_tag, 2, 2>
{
// dummy strategy which will be ignored
typedef geometry::default_strategy type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}}}} // namespace boost::geometry::strategy::disjoint
#endif // BOOST_GEOMETRY_STRATEGIES_DISJOINT_HPP
@@ -0,0 +1,110 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_DISTANCE_HPP
#define BOOST_GEOMETRY_STRATEGIES_DISTANCE_HPP
#include <boost/mpl/assert.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/strategies/tags.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace distance { namespace services
{
template <typename Strategy> struct tag {};
template <typename Strategy, typename P1, typename P2>
struct return_type
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_IMPLEMENTED_FOR_THIS_STRATEGY, (types<Strategy, P1, P2>)
);
};
template <typename Strategy> struct comparable_type
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_IMPLEMENTED_FOR_THIS_STRATEGY, (types<Strategy>)
);
};
template <typename Strategy> struct get_comparable
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_IMPLEMENTED_FOR_THIS_STRATEGY, (types<Strategy>)
);
};
template <typename Strategy, typename P1, typename P2>
struct result_from_distance {};
// Default strategy
/*!
\brief Traits class binding a default strategy for distance
to one (or possibly two) coordinate system(s)
\ingroup distance
\tparam GeometryTag1 tag (point/segment/box) for which this strategy is the default
\tparam GeometryTag2 tag (point/segment/box) for which this strategy is the default
\tparam Point1 first point-type
\tparam Point2 second point-type
\tparam CsTag1 tag of coordinate system of first point type
\tparam CsTag2 tag of coordinate system of second point type
*/
template
<
typename GeometryTag1,
typename GeometryTag2,
typename Point1,
typename Point2 = Point1,
typename CsTag1 = typename cs_tag<Point1>::type,
typename CsTag2 = typename cs_tag<Point2>::type,
typename UnderlyingStrategy = void
>
struct default_strategy
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_IMPLEMENTED_FOR_THIS_POINT_TYPE_COMBINATION
, (types<Point1, Point2, CsTag1, CsTag2>)
);
};
}}} // namespace strategy::distance::services
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_DISTANCE_HPP
@@ -0,0 +1,213 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France.
// This file was modified by Oracle on 2014, 2015.
// Modifications copyright (c) 2014-2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_DISTANCE_RESULT_HPP
#define BOOST_GEOMETRY_STRATEGIES_DISTANCE_RESULT_HPP
#include <boost/mpl/always.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/util/compress_variant.hpp>
#include <boost/geometry/util/transform_variant.hpp>
#include <boost/geometry/util/combine_if.hpp>
#include <boost/geometry/algorithms/detail/distance/default_strategies.hpp>
namespace boost { namespace geometry
{
namespace resolve_strategy
{
template <typename Geometry1, typename Geometry2, typename Strategy>
struct distance_result
: strategy::distance::services::return_type
<
Strategy,
typename point_type<Geometry1>::type,
typename point_type<Geometry2>::type
>
{};
template <typename Geometry1, typename Geometry2>
struct distance_result<Geometry1, Geometry2, default_strategy>
: distance_result
<
Geometry1,
Geometry2,
typename detail::distance::default_strategy
<
Geometry1, Geometry2
>::type
>
{};
} // namespace resolve_strategy
namespace resolve_variant
{
template <typename Geometry1, typename Geometry2, typename Strategy>
struct distance_result
: resolve_strategy::distance_result
<
Geometry1,
Geometry2,
Strategy
>
{};
template
<
typename Geometry1,
BOOST_VARIANT_ENUM_PARAMS(typename T),
typename Strategy
>
struct distance_result
<
Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Strategy
>
{
// A set of all variant type combinations that are compatible and
// implemented
typedef typename util::combine_if<
typename boost::mpl::vector1<Geometry1>,
typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types,
// Here we want should remove most of the combinations that
// are not valid, mostly to limit the size of the resulting MPL set.
// But is_implementedn is not ready for prime time
//
// util::is_implemented2<boost::mpl::_1, boost::mpl::_2, dispatch::distance<boost::mpl::_1, boost::mpl::_2> >
boost::mpl::always<boost::mpl::true_>
>::type possible_input_types;
// The (possibly variant) result type resulting from these combinations
typedef typename compress_variant<
typename transform_variant<
possible_input_types,
resolve_strategy::distance_result<
boost::mpl::first<boost::mpl::_>,
boost::mpl::second<boost::mpl::_>,
Strategy
>,
boost::mpl::back_inserter<boost::mpl::vector0<> >
>::type
>::type type;
};
// Distance arguments are commutative
template
<
BOOST_VARIANT_ENUM_PARAMS(typename T),
typename Geometry2,
typename Strategy
>
struct distance_result
<
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
Geometry2,
Strategy
> : public distance_result
<
Geometry2, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Strategy
>
{};
template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Strategy>
struct distance_result
<
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
Strategy
>
{
// A set of all variant type combinations that are compatible and
// implemented
typedef typename util::combine_if
<
typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types,
typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types,
// Here we want to try to remove most of the combinations
// that are not valid, mostly to limit the size of the
// resulting MPL vector.
// But is_implemented is not ready for prime time
//
// util::is_implemented2<boost::mpl::_1, boost::mpl::_2, dispatch::distance<boost::mpl::_1, boost::mpl::_2> >
boost::mpl::always<boost::mpl::true_>
>::type possible_input_types;
// The (possibly variant) result type resulting from these combinations
typedef typename compress_variant<
typename transform_variant<
possible_input_types,
resolve_strategy::distance_result<
boost::mpl::first<boost::mpl::_>,
boost::mpl::second<boost::mpl::_>,
Strategy
>,
boost::mpl::back_inserter<boost::mpl::vector0<> >
>::type
>::type type;
};
} // namespace resolve_variant
/*!
\brief Meta-function defining return type of distance function
\ingroup distance
\note The strategy defines the return-type (so this situation is different
from length, where distance is sqr/sqrt, but length always squared)
*/
template
<
typename Geometry1,
typename Geometry2 = Geometry1,
typename Strategy = void
>
struct distance_result
: resolve_variant::distance_result<Geometry1, Geometry2, Strategy>
{};
template <typename Geometry1, typename Geometry2>
struct distance_result<Geometry1, Geometry2, void>
: distance_result<Geometry1, Geometry2, default_strategy>
{};
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_DISTANCE_RESULT_HPP
@@ -0,0 +1,45 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2016-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fisikopoulos, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_ENVELOPE_HPP
#define BOOST_GEOMETRY_STRATEGIES_ENVELOPE_HPP
#include <boost/mpl/assert.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace envelope { namespace services
{
/*!
\brief Traits class binding a default envelope strategy to a coordinate system
\ingroup util
\tparam CSTag tag of coordinate system
\tparam CalculationType \tparam_calculation
*/
template <typename CSTag, typename CalculationType = void>
struct default_strategy
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_IMPLEMENTED_FOR_THIS_TYPE
, (types<CSTag>)
);
};
}}} // namespace strategy::envelope::services
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_ENVELOPE_HPP
@@ -0,0 +1,216 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2016-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fisikopoulos, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_HPP
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_HPP
#include <boost/geometry/core/srs.hpp>
#include <boost/geometry/formulas/area_formulas.hpp>
#include <boost/geometry/formulas/flattening.hpp>
#include <boost/geometry/strategies/geographic/parameters.hpp>
#include <boost/math/special_functions/atanh.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace area
{
/*!
\brief Geographic area calculation
\ingroup strategies
\details Geographic area calculation by trapezoidal rule plus integral
approximation that gives the ellipsoidal correction
\tparam PointOfSegment \tparam_segment_point
\tparam FormulaPolicy Formula used to calculate azimuths
\tparam SeriesOrder The order of approximation of the geodesic integral
\tparam Spheroid The spheroid model
\tparam CalculationType \tparam_calculation
\author See
- Danielsen JS, The area under the geodesic. Surv Rev 30(232): 6166, 1989
- Charles F.F Karney, Algorithms for geodesics, 2011 https://arxiv.org/pdf/1109.4448.pdf
\qbk{
[heading See also]
[link geometry.reference.algorithms.area.area_2_with_strategy area (with strategy)]
}
*/
template
<
typename PointOfSegment,
typename FormulaPolicy = strategy::andoyer,
std::size_t SeriesOrder = strategy::default_order<FormulaPolicy>::value,
typename Spheroid = srs::spheroid<double>,
typename CalculationType = void
>
class geographic
{
// Switch between two kinds of approximation(series in eps and n v.s.series in k ^ 2 and e'^2)
static const bool ExpandEpsN = true;
// LongSegment Enables special handling of long segments
static const bool LongSegment = false;
//Select default types in case they are not set
typedef typename boost::mpl::if_c
<
boost::is_void<CalculationType>::type::value,
typename select_most_precise
<
typename coordinate_type<PointOfSegment>::type,
double
>::type,
CalculationType
>::type CT;
protected :
struct spheroid_constants
{
Spheroid m_spheroid;
CT const m_a2; // squared equatorial radius
CT const m_e2; // squared eccentricity
CT const m_ep2; // squared second eccentricity
CT const m_ep; // second eccentricity
CT const m_c2; // authalic radius
inline spheroid_constants(Spheroid const& spheroid)
: m_spheroid(spheroid)
, m_a2(math::sqr(get_radius<0>(spheroid)))
, m_e2(formula::flattening<CT>(spheroid)
* (CT(2.0) - CT(formula::flattening<CT>(spheroid))))
, m_ep2(m_e2 / (CT(1.0) - m_e2))
, m_ep(math::sqrt(m_ep2))
, m_c2((m_a2 / CT(2.0)) +
((math::sqr(get_radius<2>(spheroid)) * boost::math::atanh(math::sqrt(m_e2)))
/ (CT(2.0) * math::sqrt(m_e2))))
{}
};
struct area_sums
{
CT m_excess_sum;
CT m_correction_sum;
// Keep track if encircles some pole
std::size_t m_crosses_prime_meridian;
inline area_sums()
: m_excess_sum(0)
, m_correction_sum(0)
, m_crosses_prime_meridian(0)
{}
inline CT area(spheroid_constants spheroid_const) const
{
CT result;
CT sum = spheroid_const.m_c2 * m_excess_sum
+ spheroid_const.m_e2 * spheroid_const.m_a2 * m_correction_sum;
// If encircles some pole
if (m_crosses_prime_meridian % 2 == 1)
{
std::size_t times_crosses_prime_meridian
= 1 + (m_crosses_prime_meridian / 2);
result = CT(2.0)
* geometry::math::pi<CT>()
* spheroid_const.m_c2
* CT(times_crosses_prime_meridian)
- geometry::math::abs(sum);
if (geometry::math::sign<CT>(sum) == 1)
{
result = - result;
}
}
else
{
result = sum;
}
return result;
}
};
public :
typedef CT return_type;
typedef PointOfSegment segment_point_type;
typedef area_sums state_type;
explicit inline geographic(Spheroid const& spheroid = Spheroid())
: m_spheroid_constants(spheroid)
{}
inline void apply(PointOfSegment const& p1,
PointOfSegment const& p2,
area_sums& state) const
{
if (! geometry::math::equals(get<0>(p1), get<0>(p2)))
{
typedef geometry::formula::area_formulas
<
CT, SeriesOrder, ExpandEpsN
> area_formulas;
typename area_formulas::return_type_ellipsoidal result =
area_formulas::template ellipsoidal<FormulaPolicy::template inverse>
(p1, p2, m_spheroid_constants);
state.m_excess_sum += result.spherical_term;
state.m_correction_sum += result.ellipsoidal_term;
// Keep track whenever a segment crosses the prime meridian
geometry::formula::area_formulas<CT>
::crosses_prime_meridian(p1, p2, state);
}
}
inline return_type result(area_sums const& state) const
{
return state.area(m_spheroid_constants);
}
private:
spheroid_constants m_spheroid_constants;
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename Point>
struct default_strategy<geographic_tag, Point>
{
typedef strategy::area::geographic<Point> type;
};
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}
}} // namespace strategy::area
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_HPP
@@ -0,0 +1,103 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2016-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fisikopoulos, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AZIMUTH_HPP
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AZIMUTH_HPP
#include <boost/geometry/core/srs.hpp>
#include <boost/geometry/strategies/azimuth.hpp>
#include <boost/geometry/strategies/geographic/parameters.hpp>
#include <boost/mpl/if.hpp>
#include <boost/type_traits/is_void.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace azimuth
{
template
<
typename FormulaPolicy = strategy::andoyer,
typename Spheroid = srs::spheroid<double>,
typename CalculationType = void
>
class geographic
{
public :
typedef Spheroid model_type;
inline geographic()
: m_spheroid()
{}
explicit inline geographic(Spheroid const& spheroid)
: m_spheroid(spheroid)
{}
inline model_type const& model() const
{
return m_spheroid;
}
template <typename T>
inline void apply(T const& lon1_rad, T const& lat1_rad,
T const& lon2_rad, T const& lat2_rad,
T& a1, T& a2) const
{
typedef typename boost::mpl::if_
<
boost::is_void<CalculationType>, T, CalculationType
>::type calc_t;
typedef typename FormulaPolicy::template inverse<calc_t, false, true, true, false, false> inverse_type;
typedef typename inverse_type::result_type inverse_result;
inverse_result i_res = inverse_type::apply(calc_t(lon1_rad), calc_t(lat1_rad),
calc_t(lon2_rad), calc_t(lat2_rad),
m_spheroid);
a1 = i_res.azimuth;
a2 = i_res.reverse_azimuth;
}
private :
Spheroid m_spheroid;
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename CalculationType>
struct default_strategy<geographic_tag, CalculationType>
{
typedef strategy::azimuth::geographic
<
strategy::andoyer,
srs::spheroid<double>,
CalculationType
> type;
};
}
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::azimuth
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AZIMUTH_HPP
@@ -0,0 +1,195 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2016 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014-2017.
// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_HPP
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_HPP
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/core/radius.hpp>
#include <boost/geometry/core/srs.hpp>
#include <boost/geometry/formulas/andoyer_inverse.hpp>
#include <boost/geometry/formulas/flattening.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/geographic/parameters.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace distance
{
template
<
typename FormulaPolicy = strategy::andoyer,
typename Spheroid = srs::spheroid<double>,
typename CalculationType = void
>
class geographic
{
public :
template <typename Point1, typename Point2>
struct calculation_type
: promote_floating_point
<
typename select_calculation_type
<
Point1,
Point2,
CalculationType
>::type
>
{};
typedef Spheroid model_type;
inline geographic()
: m_spheroid()
{}
explicit inline geographic(Spheroid const& spheroid)
: m_spheroid(spheroid)
{}
template <typename Point1, typename Point2>
inline typename calculation_type<Point1, Point2>::type
apply(Point1 const& point1, Point2 const& point2) const
{
return FormulaPolicy::template inverse
<
typename calculation_type<Point1, Point2>::type,
true, false, false, false, false
>::apply(get_as_radian<0>(point1), get_as_radian<1>(point1),
get_as_radian<0>(point2), get_as_radian<1>(point2),
m_spheroid).distance;
}
inline Spheroid const& model() const
{
return m_spheroid;
}
private :
Spheroid m_spheroid;
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template
<
typename FormulaPolicy,
typename Spheroid,
typename CalculationType
>
struct tag<geographic<FormulaPolicy, Spheroid, CalculationType> >
{
typedef strategy_tag_distance_point_point type;
};
template
<
typename FormulaPolicy,
typename Spheroid,
typename CalculationType,
typename P1,
typename P2
>
struct return_type<geographic<FormulaPolicy, Spheroid, CalculationType>, P1, P2>
: geographic<FormulaPolicy, Spheroid, CalculationType>::template calculation_type<P1, P2>
{};
template
<
typename FormulaPolicy,
typename Spheroid,
typename CalculationType
>
struct comparable_type<geographic<FormulaPolicy, Spheroid, CalculationType> >
{
typedef geographic<FormulaPolicy, Spheroid, CalculationType> type;
};
template
<
typename FormulaPolicy,
typename Spheroid,
typename CalculationType
>
struct get_comparable<geographic<FormulaPolicy, Spheroid, CalculationType> >
{
static inline geographic<FormulaPolicy, Spheroid, CalculationType>
apply(geographic<FormulaPolicy, Spheroid, CalculationType> const& input)
{
return input;
}
};
template
<
typename FormulaPolicy,
typename Spheroid,
typename CalculationType,
typename P1,
typename P2
>
struct result_from_distance<geographic<FormulaPolicy, Spheroid, CalculationType>, P1, P2>
{
template <typename T>
static inline typename return_type<geographic<FormulaPolicy, Spheroid, CalculationType>, P1, P2>::type
apply(geographic<FormulaPolicy, Spheroid, CalculationType> const& , T const& value)
{
return value;
}
};
template <typename Point1, typename Point2>
struct default_strategy<point_tag, point_tag, Point1, Point2, geographic_tag, geographic_tag>
{
typedef strategy::distance::geographic
<
strategy::andoyer,
srs::spheroid
<
typename select_coordinate_type<Point1, Point2>::type
>
> type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::distance
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_HPP
@@ -0,0 +1,128 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2016 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014, 2017.
// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_DETAIL_HPP
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_DETAIL_HPP
#include <boost/geometry/strategies/geographic/distance.hpp>
#include <boost/geometry/strategies/geographic/parameters.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace distance
{
/*!
\brief Point-point distance approximation taking flattening into account
\ingroup distance
\tparam Spheroid The reference spheroid model
\tparam CalculationType \tparam_calculation
\author After Andoyer, 19xx, republished 1950, republished by Meeus, 1999
\note Although not so well-known, the approximation is very good: in all cases the results
are about the same as Vincenty. In my (Barend's) testcases the results didn't differ more than 6 m
\see http://nacc.upc.es/tierra/node16.html
\see http://sci.tech-archive.net/Archive/sci.geo.satellite-nav/2004-12/2724.html
\see http://home.att.net/~srschmitt/great_circle_route.html (implementation)
\see http://www.codeguru.com/Cpp/Cpp/algorithms/article.php/c5115 (implementation)
\see http://futureboy.homeip.net/frinksamp/navigation.frink (implementation)
\see http://www.voidware.com/earthdist.htm (implementation)
\see http://www.dtic.mil/docs/citations/AD0627893
\see http://www.dtic.mil/docs/citations/AD703541
*/
template
<
typename Spheroid = srs::spheroid<double>,
typename CalculationType = void
>
class andoyer
: public strategy::distance::geographic
<
strategy::andoyer, Spheroid, CalculationType
>
{
typedef strategy::distance::geographic
<
strategy::andoyer, Spheroid, CalculationType
> base_type;
public :
inline andoyer()
: base_type()
{}
explicit inline andoyer(Spheroid const& spheroid)
: base_type(spheroid)
{}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename Spheroid, typename CalculationType>
struct tag<andoyer<Spheroid, CalculationType> >
{
typedef strategy_tag_distance_point_point type;
};
template <typename Spheroid, typename CalculationType, typename P1, typename P2>
struct return_type<andoyer<Spheroid, CalculationType>, P1, P2>
: andoyer<Spheroid, CalculationType>::template calculation_type<P1, P2>
{};
template <typename Spheroid, typename CalculationType>
struct comparable_type<andoyer<Spheroid, CalculationType> >
{
typedef andoyer<Spheroid, CalculationType> type;
};
template <typename Spheroid, typename CalculationType>
struct get_comparable<andoyer<Spheroid, CalculationType> >
{
static inline andoyer<Spheroid, CalculationType> apply(andoyer<Spheroid, CalculationType> const& input)
{
return input;
}
};
template <typename Spheroid, typename CalculationType, typename P1, typename P2>
struct result_from_distance<andoyer<Spheroid, CalculationType>, P1, P2>
{
template <typename T>
static inline typename return_type<andoyer<Spheroid, CalculationType>, P1, P2>::type
apply(andoyer<Spheroid, CalculationType> const& , T const& value)
{
return value;
}
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::distance
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_DETAIL_HPP
@@ -0,0 +1,121 @@
// Boost.Geometry
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2015-2017.
// Modifications copyright (c) 2015-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_THOMAS_HPP
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_THOMAS_HPP
#include <boost/geometry/strategies/geographic/distance.hpp>
#include <boost/geometry/strategies/geographic/parameters.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace distance
{
/*!
\brief The solution of the inverse problem of geodesics on latlong coordinates,
Forsyth-Andoyer-Lambert type approximation with second order terms.
\ingroup distance
\tparam Spheroid The reference spheroid model
\tparam CalculationType \tparam_calculation
\author See
- Technical Report: PAUL D. THOMAS, MATHEMATICAL MODELS FOR NAVIGATION SYSTEMS, 1965
http://www.dtic.mil/docs/citations/AD0627893
- Technical Report: PAUL D. THOMAS, SPHEROIDAL GEODESICS, REFERENCE SYSTEMS, AND LOCAL GEOMETRY, 1970
http://www.dtic.mil/docs/citations/AD703541
*/
template
<
typename Spheroid = srs::spheroid<double>,
typename CalculationType = void
>
class thomas
: public strategy::distance::geographic
<
strategy::thomas, Spheroid, CalculationType
>
{
typedef strategy::distance::geographic
<
strategy::thomas, Spheroid, CalculationType
> base_type;
public :
inline thomas()
: base_type()
{}
explicit inline thomas(Spheroid const& spheroid)
: base_type(spheroid)
{}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename Spheroid, typename CalculationType>
struct tag<thomas<Spheroid, CalculationType> >
{
typedef strategy_tag_distance_point_point type;
};
template <typename Spheroid, typename CalculationType, typename P1, typename P2>
struct return_type<thomas<Spheroid, CalculationType>, P1, P2>
: thomas<Spheroid, CalculationType>::template calculation_type<P1, P2>
{};
template <typename Spheroid, typename CalculationType>
struct comparable_type<thomas<Spheroid, CalculationType> >
{
typedef thomas<Spheroid, CalculationType> type;
};
template <typename Spheroid, typename CalculationType>
struct get_comparable<thomas<Spheroid, CalculationType> >
{
static inline thomas<Spheroid, CalculationType> apply(thomas<Spheroid, CalculationType> const& input)
{
return input;
}
};
template <typename Spheroid, typename CalculationType, typename P1, typename P2>
struct result_from_distance<thomas<Spheroid, CalculationType>, P1, P2 >
{
template <typename T>
static inline typename return_type<thomas<Spheroid, CalculationType>, P1, P2>::type
apply(thomas<Spheroid, CalculationType> const& , T const& value)
{
return value;
}
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::distance
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_THOMAS_HPP
@@ -0,0 +1,127 @@
// Boost.Geometry
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014-2017.
// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_VINCENTY_HPP
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_VINCENTY_HPP
#include <boost/geometry/strategies/geographic/distance.hpp>
#include <boost/geometry/strategies/geographic/parameters.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace distance
{
/*!
\brief Distance calculation formulae on latlong coordinates, after Vincenty, 1975
\ingroup distance
\tparam Spheroid The reference spheroid model
\tparam CalculationType \tparam_calculation
\author See
- http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
- http://www.icsm.gov.au/gda/gdav2.3.pdf
\author Adapted from various implementations to get it close to the original document
- http://www.movable-type.co.uk/scripts/LatLongVincenty.html
- http://exogen.case.edu/projects/geopy/source/geopy.distance.html
- http://futureboy.homeip.net/fsp/colorize.fsp?fileName=navigation.frink
*/
template
<
typename Spheroid = srs::spheroid<double>,
typename CalculationType = void
>
class vincenty
: public strategy::distance::geographic
<
strategy::vincenty, Spheroid, CalculationType
>
{
typedef strategy::distance::geographic
<
strategy::vincenty, Spheroid, CalculationType
> base_type;
public:
inline vincenty()
: base_type()
{}
explicit inline vincenty(Spheroid const& spheroid)
: base_type(spheroid)
{}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename Spheroid, typename CalculationType>
struct tag<vincenty<Spheroid, CalculationType> >
{
typedef strategy_tag_distance_point_point type;
};
template <typename Spheroid, typename CalculationType, typename P1, typename P2>
struct return_type<vincenty<Spheroid, CalculationType>, P1, P2>
: vincenty<Spheroid, CalculationType>::template calculation_type<P1, P2>
{};
template <typename Spheroid, typename CalculationType>
struct comparable_type<vincenty<Spheroid, CalculationType> >
{
typedef vincenty<Spheroid, CalculationType> type;
};
template <typename Spheroid, typename CalculationType>
struct get_comparable<vincenty<Spheroid, CalculationType> >
{
static inline vincenty<Spheroid, CalculationType> apply(vincenty<Spheroid, CalculationType> const& input)
{
return input;
}
};
template <typename Spheroid, typename CalculationType, typename P1, typename P2>
struct result_from_distance<vincenty<Spheroid, CalculationType>, P1, P2 >
{
template <typename T>
static inline typename return_type<vincenty<Spheroid, CalculationType>, P1, P2>::type
apply(vincenty<Spheroid, CalculationType> const& , T const& value)
{
return value;
}
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
// We might add a vincenty-like strategy also for point-segment distance, but to calculate the projected point is not trivial
}} // namespace strategy::distance
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_VINCENTY_HPP
@@ -0,0 +1,104 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2017 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fisikopoulos, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_ENVELOPE_SEGMENT_HPP
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_ENVELOPE_SEGMENT_HPP
#include <boost/geometry/algorithms/detail/envelope/segment.hpp>
#include <boost/geometry/algorithms/detail/normalize.hpp>
#include <boost/geometry/core/srs.hpp>
#include <boost/geometry/strategies/envelope.hpp>
#include <boost/geometry/strategies/geographic/azimuth.hpp>
#include <boost/geometry/strategies/geographic/parameters.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace envelope
{
template
<
typename FormulaPolicy = strategy::andoyer,
typename Spheroid = geometry::srs::spheroid<double>,
typename CalculationType = void
>
class geographic_segment
{
public:
typedef Spheroid model_type;
inline geographic_segment()
: m_spheroid()
{}
explicit inline geographic_segment(Spheroid const& spheroid)
: m_spheroid(spheroid)
{}
template <typename Point1, typename Point2, typename Box>
inline void apply(Point1 const& point1, Point2 const& point2, Box& box) const
{
Point1 p1_normalized = detail::return_normalized<Point1>(point1);
Point2 p2_normalized = detail::return_normalized<Point2>(point2);
geometry::strategy::azimuth::geographic
<
FormulaPolicy,
Spheroid,
CalculationType
> azimuth_geographic(m_spheroid);
typedef typename coordinate_system<Point1>::type::units units_type;
detail::envelope::envelope_segment_impl
<
geographic_tag
>::template apply<units_type>(geometry::get<0>(p1_normalized),
geometry::get<1>(p1_normalized),
geometry::get<0>(p2_normalized),
geometry::get<1>(p2_normalized),
box,
azimuth_geographic);
}
private:
Spheroid m_spheroid;
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename CalculationType>
struct default_strategy<geographic_tag, CalculationType>
{
typedef strategy::envelope::geographic_segment
<
strategy::andoyer,
srs::spheroid<double>,
CalculationType
> type;
};
}
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::envelope
}} //namepsace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_ENVELOPE_SEGMENT_HPP
@@ -0,0 +1,897 @@
// Boost.Geometry
// Copyright (c) 2016-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_INTERSECTION_HPP
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_INTERSECTION_HPP
#include <algorithm>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/core/srs.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/detail/assign_values.hpp>
#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/formulas/andoyer_inverse.hpp>
#include <boost/geometry/formulas/sjoberg_intersection.hpp>
#include <boost/geometry/formulas/spherical.hpp>
#include <boost/geometry/geometries/concepts/point_concept.hpp>
#include <boost/geometry/geometries/concepts/segment_concept.hpp>
#include <boost/geometry/policies/robustness/segment_ratio.hpp>
#include <boost/geometry/strategies/geographic/area.hpp>
#include <boost/geometry/strategies/geographic/distance.hpp>
#include <boost/geometry/strategies/geographic/parameters.hpp>
#include <boost/geometry/strategies/geographic/side.hpp>
#include <boost/geometry/strategies/intersection.hpp>
#include <boost/geometry/strategies/intersection_result.hpp>
#include <boost/geometry/strategies/side_info.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace intersection
{
// CONSIDER: Improvement of the robustness/accuracy/repeatability by
// moving all segments to 0 longitude
// picking latitudes closer to 0
// etc.
template
<
typename FormulaPolicy = strategy::andoyer,
unsigned int Order = strategy::default_order<FormulaPolicy>::value,
typename Spheroid = srs::spheroid<double>,
typename CalculationType = void
>
struct geographic_segments
{
typedef side::geographic
<
FormulaPolicy, Spheroid, CalculationType
> side_strategy_type;
inline side_strategy_type get_side_strategy() const
{
return side_strategy_type(m_spheroid);
}
template <typename Geometry1, typename Geometry2>
struct point_in_geometry_strategy
{
typedef strategy::within::winding
<
typename point_type<Geometry1>::type,
typename point_type<Geometry2>::type,
side_strategy_type,
CalculationType
> type;
};
template <typename Geometry1, typename Geometry2>
inline typename point_in_geometry_strategy<Geometry1, Geometry2>::type
get_point_in_geometry_strategy() const
{
typedef typename point_in_geometry_strategy
<
Geometry1, Geometry2
>::type strategy_type;
return strategy_type(get_side_strategy());
}
template <typename Geometry>
struct area_strategy
{
typedef area::geographic
<
typename point_type<Geometry>::type,
FormulaPolicy,
Order,
Spheroid,
CalculationType
> type;
};
template <typename Geometry>
inline typename area_strategy<Geometry>::type get_area_strategy() const
{
typedef typename area_strategy<Geometry>::type strategy_type;
return strategy_type(m_spheroid);
}
template <typename Geometry>
struct distance_strategy
{
typedef distance::geographic
<
FormulaPolicy,
Spheroid,
CalculationType
> type;
};
template <typename Geometry>
inline typename distance_strategy<Geometry>::type get_distance_strategy() const
{
typedef typename distance_strategy<Geometry>::type strategy_type;
return strategy_type(m_spheroid);
}
enum intersection_point_flag { ipi_inters = 0, ipi_at_a1, ipi_at_a2, ipi_at_b1, ipi_at_b2 };
template <typename CoordinateType, typename SegmentRatio>
struct segment_intersection_info
{
typedef typename select_most_precise
<
CoordinateType, double
>::type promoted_type;
promoted_type comparable_length_a() const
{
return robust_ra.denominator();
}
promoted_type comparable_length_b() const
{
return robust_rb.denominator();
}
template <typename Point, typename Segment1, typename Segment2>
void assign_a(Point& point, Segment1 const& a, Segment2 const& b) const
{
assign(point, a, b);
}
template <typename Point, typename Segment1, typename Segment2>
void assign_b(Point& point, Segment1 const& a, Segment2 const& b) const
{
assign(point, a, b);
}
template <typename Point, typename Segment1, typename Segment2>
void assign(Point& point, Segment1 const& a, Segment2 const& b) const
{
if (ip_flag == ipi_inters)
{
// TODO: assign the rest of coordinates
set_from_radian<0>(point, lon);
set_from_radian<1>(point, lat);
}
else if (ip_flag == ipi_at_a1)
{
detail::assign_point_from_index<0>(a, point);
}
else if (ip_flag == ipi_at_a2)
{
detail::assign_point_from_index<1>(a, point);
}
else if (ip_flag == ipi_at_b1)
{
detail::assign_point_from_index<0>(b, point);
}
else // ip_flag == ipi_at_b2
{
detail::assign_point_from_index<1>(b, point);
}
}
CoordinateType lon;
CoordinateType lat;
SegmentRatio robust_ra;
SegmentRatio robust_rb;
intersection_point_flag ip_flag;
};
explicit geographic_segments(Spheroid const& spheroid = Spheroid())
: m_spheroid(spheroid)
{}
// Relate segments a and b
template
<
typename Segment1,
typename Segment2,
typename Policy,
typename RobustPolicy
>
inline typename Policy::return_type apply(Segment1 const& a, Segment2 const& b,
Policy const& policy,
RobustPolicy const& robust_policy) const
{
typedef typename point_type<Segment1>::type point1_t;
typedef typename point_type<Segment2>::type point2_t;
point1_t a1, a2;
point2_t b1, b2;
detail::assign_point_from_index<0>(a, a1);
detail::assign_point_from_index<1>(a, a2);
detail::assign_point_from_index<0>(b, b1);
detail::assign_point_from_index<1>(b, b2);
return apply(a, b, policy, robust_policy, a1, a2, b1, b2);
}
// Relate segments a and b
template
<
typename Segment1,
typename Segment2,
typename Policy,
typename RobustPolicy,
typename Point1,
typename Point2
>
inline typename Policy::return_type apply(Segment1 const& a, Segment2 const& b,
Policy const&, RobustPolicy const&,
Point1 a1, Point1 a2, Point2 b1, Point2 b2) const
{
bool is_a_reversed = get<1>(a1) > get<1>(a2);
bool is_b_reversed = get<1>(b1) > get<1>(b2);
if (is_a_reversed)
{
std::swap(a1, a2);
}
if (is_b_reversed)
{
std::swap(b1, b2);
}
return apply<Policy>(a, b, a1, a2, b1, b2, is_a_reversed, is_b_reversed);
}
private:
// Relate segments a and b
template
<
typename Policy,
typename Segment1,
typename Segment2,
typename Point1,
typename Point2
>
inline typename Policy::return_type apply(Segment1 const& a, Segment2 const& b,
Point1 const& a1, Point1 const& a2,
Point2 const& b1, Point2 const& b2,
bool is_a_reversed, bool is_b_reversed) const
{
BOOST_CONCEPT_ASSERT( (concepts::ConstSegment<Segment1>) );
BOOST_CONCEPT_ASSERT( (concepts::ConstSegment<Segment2>) );
typedef typename select_calculation_type
<Segment1, Segment2, CalculationType>::type calc_t;
// normalized spheroid
srs::spheroid<calc_t> spheroid = normalized_spheroid<calc_t>(m_spheroid);
// TODO: check only 2 first coordinates here?
using geometry::detail::equals::equals_point_point;
bool a_is_point = equals_point_point(a1, a2);
bool b_is_point = equals_point_point(b1, b2);
if(a_is_point && b_is_point)
{
return equals_point_point(a1, b2)
? Policy::degenerate(a, true)
: Policy::disjoint()
;
}
calc_t const a1_lon = get_as_radian<0>(a1);
calc_t const a1_lat = get_as_radian<1>(a1);
calc_t const a2_lon = get_as_radian<0>(a2);
calc_t const a2_lat = get_as_radian<1>(a2);
calc_t const b1_lon = get_as_radian<0>(b1);
calc_t const b1_lat = get_as_radian<1>(b1);
calc_t const b2_lon = get_as_radian<0>(b2);
calc_t const b2_lat = get_as_radian<1>(b2);
side_info sides;
// NOTE: potential optimization, don't calculate distance at this point
// this would require to reimplement inverse strategy to allow
// calculation of distance if needed, probably also storing intermediate
// results somehow inside an object.
typedef typename FormulaPolicy::template inverse<calc_t, true, true, false, false, false> inverse_dist_azi;
typedef typename inverse_dist_azi::result_type inverse_result;
// TODO: no need to call inverse formula if we know that the points are equal
// distance can be set to 0 in this case and azimuth may be not calculated
bool const is_equal_a1_b1 = equals_point_point(a1, b1);
bool const is_equal_a2_b1 = equals_point_point(a2, b1);
inverse_result res_b1_b2 = inverse_dist_azi::apply(b1_lon, b1_lat, b2_lon, b2_lat, spheroid);
inverse_result res_b1_a1 = inverse_dist_azi::apply(b1_lon, b1_lat, a1_lon, a1_lat, spheroid);
inverse_result res_b1_a2 = inverse_dist_azi::apply(b1_lon, b1_lat, a2_lon, a2_lat, spheroid);
sides.set<0>(is_equal_a1_b1 ? 0 : formula::azimuth_side_value(res_b1_a1.azimuth, res_b1_b2.azimuth),
is_equal_a2_b1 ? 0 : formula::azimuth_side_value(res_b1_a2.azimuth, res_b1_b2.azimuth));
if (sides.same<0>())
{
// Both points are at the same side of other segment, we can leave
return Policy::disjoint();
}
bool const is_equal_a1_b2 = equals_point_point(a1, b2);
inverse_result res_a1_a2 = inverse_dist_azi::apply(a1_lon, a1_lat, a2_lon, a2_lat, spheroid);
inverse_result res_a1_b1 = inverse_dist_azi::apply(a1_lon, a1_lat, b1_lon, b1_lat, spheroid);
inverse_result res_a1_b2 = inverse_dist_azi::apply(a1_lon, a1_lat, b2_lon, b2_lat, spheroid);
sides.set<1>(is_equal_a1_b1 ? 0 : formula::azimuth_side_value(res_a1_b1.azimuth, res_a1_a2.azimuth),
is_equal_a1_b2 ? 0 : formula::azimuth_side_value(res_a1_b2.azimuth, res_a1_a2.azimuth));
if (sides.same<1>())
{
// Both points are at the same side of other segment, we can leave
return Policy::disjoint();
}
// NOTE: at this point the segments may still be disjoint
// NOTE: at this point one of the segments may be degenerated
bool collinear = sides.collinear();
if (! collinear)
{
// WARNING: the side strategy doesn't have the info about the other
// segment so it may return results inconsistent with this intersection
// strategy, as it checks both segments for consistency
if (sides.get<0, 0>() == 0 && sides.get<0, 1>() == 0)
{
collinear = true;
sides.set<1>(0, 0);
}
else if (sides.get<1, 0>() == 0 && sides.get<1, 1>() == 0)
{
collinear = true;
sides.set<0>(0, 0);
}
}
if (collinear)
{
if (a_is_point)
{
return collinear_one_degenerated<Policy, calc_t>(a, true, b1, b2, a1, a2, res_b1_b2, res_b1_a1, is_b_reversed);
}
else if (b_is_point)
{
return collinear_one_degenerated<Policy, calc_t>(b, false, a1, a2, b1, b2, res_a1_a2, res_a1_b1, is_a_reversed);
}
else
{
calc_t dist_a1_a2, dist_a1_b1, dist_a1_b2;
calc_t dist_b1_b2, dist_b1_a1, dist_b1_a2;
// use shorter segment
if (res_a1_a2.distance <= res_b1_b2.distance)
{
calculate_collinear_data(a1, a2, b1, b2, res_a1_a2, res_a1_b1, dist_a1_a2, dist_a1_b1);
calculate_collinear_data(a1, a2, b1, b2, res_a1_a2, res_a1_b2, dist_a1_a2, dist_a1_b2);
dist_b1_b2 = dist_a1_b2 - dist_a1_b1;
dist_b1_a1 = -dist_a1_b1;
dist_b1_a2 = dist_a1_a2 - dist_a1_b1;
}
else
{
calculate_collinear_data(b1, b2, a1, a2, res_b1_b2, res_b1_a1, dist_b1_b2, dist_b1_a1);
calculate_collinear_data(b1, b2, a1, a2, res_b1_b2, res_b1_a2, dist_b1_b2, dist_b1_a2);
dist_a1_a2 = dist_b1_a2 - dist_b1_a1;
dist_a1_b1 = -dist_b1_a1;
dist_a1_b2 = dist_b1_b2 - dist_b1_a1;
}
// NOTE: this is probably not needed
calc_t const c0 = 0;
int a1_on_b = position_value(c0, dist_a1_b1, dist_a1_b2);
int a2_on_b = position_value(dist_a1_a2, dist_a1_b1, dist_a1_b2);
int b1_on_a = position_value(c0, dist_b1_a1, dist_b1_a2);
int b2_on_a = position_value(dist_b1_b2, dist_b1_a1, dist_b1_a2);
if ((a1_on_b < 1 && a2_on_b < 1) || (a1_on_b > 3 && a2_on_b > 3))
{
return Policy::disjoint();
}
if (a1_on_b == 1)
{
dist_b1_a1 = 0;
dist_a1_b1 = 0;
}
else if (a1_on_b == 3)
{
dist_b1_a1 = dist_b1_b2;
dist_a1_b2 = 0;
}
if (a2_on_b == 1)
{
dist_b1_a2 = 0;
dist_a1_b1 = dist_a1_a2;
}
else if (a2_on_b == 3)
{
dist_b1_a2 = dist_b1_b2;
dist_a1_b2 = dist_a1_a2;
}
bool opposite = ! same_direction(res_a1_a2.azimuth, res_b1_b2.azimuth);
// NOTE: If segment was reversed opposite, positions and segment ratios has to be altered
if (is_a_reversed)
{
// opposite
opposite = ! opposite;
// positions
std::swap(a1_on_b, a2_on_b);
b1_on_a = 4 - b1_on_a;
b2_on_a = 4 - b2_on_a;
// distances for ratios
std::swap(dist_b1_a1, dist_b1_a2);
dist_a1_b1 = dist_a1_a2 - dist_a1_b1;
dist_a1_b2 = dist_a1_a2 - dist_a1_b2;
}
if (is_b_reversed)
{
// opposite
opposite = ! opposite;
// positions
a1_on_b = 4 - a1_on_b;
a2_on_b = 4 - a2_on_b;
std::swap(b1_on_a, b2_on_a);
// distances for ratios
dist_b1_a1 = dist_b1_b2 - dist_b1_a1;
dist_b1_a2 = dist_b1_b2 - dist_b1_a2;
std::swap(dist_a1_b1, dist_a1_b2);
}
segment_ratio<calc_t> ra_from(dist_b1_a1, dist_b1_b2);
segment_ratio<calc_t> ra_to(dist_b1_a2, dist_b1_b2);
segment_ratio<calc_t> rb_from(dist_a1_b1, dist_a1_a2);
segment_ratio<calc_t> rb_to(dist_a1_b2, dist_a1_a2);
return Policy::segments_collinear(a, b, opposite,
a1_on_b, a2_on_b, b1_on_a, b2_on_a,
ra_from, ra_to, rb_from, rb_to);
}
}
else // crossing or touching
{
if (a_is_point || b_is_point)
{
return Policy::disjoint();
}
calc_t lon = 0, lat = 0;
intersection_point_flag ip_flag;
calc_t dist_a1_a2, dist_a1_i1, dist_b1_b2, dist_b1_i1;
if (calculate_ip_data(a1, a2, b1, b2,
a1_lon, a1_lat, a2_lon, a2_lat,
b1_lon, b1_lat, b2_lon, b2_lat,
res_a1_a2, res_a1_b1, res_a1_b2,
res_b1_b2, res_b1_a1, res_b1_a2,
sides, spheroid,
lon, lat,
dist_a1_a2, dist_a1_i1, dist_b1_b2, dist_b1_i1,
ip_flag))
{
// NOTE: If segment was reversed sides and segment ratios has to be altered
if (is_a_reversed)
{
// sides
sides_reverse_segment<0>(sides);
// distance for ratio
dist_a1_i1 = dist_a1_a2 - dist_a1_i1;
// ip flag
ip_flag_reverse_segment(ip_flag, ipi_at_a1, ipi_at_a2);
}
if (is_b_reversed)
{
// sides
sides_reverse_segment<1>(sides);
// distance for ratio
dist_b1_i1 = dist_b1_b2 - dist_b1_i1;
// ip flag
ip_flag_reverse_segment(ip_flag, ipi_at_b1, ipi_at_b2);
}
// intersects
segment_intersection_info
<
calc_t,
segment_ratio<calc_t>
> sinfo;
sinfo.lon = lon;
sinfo.lat = lat;
sinfo.robust_ra.assign(dist_a1_i1, dist_a1_a2);
sinfo.robust_rb.assign(dist_b1_i1, dist_b1_b2);
sinfo.ip_flag = ip_flag;
return Policy::segments_crosses(sides, sinfo, a, b);
}
else
{
return Policy::disjoint();
}
}
}
template <typename Policy, typename CalcT, typename Segment, typename Point1, typename Point2, typename ResultInverse>
static inline typename Policy::return_type
collinear_one_degenerated(Segment const& segment, bool degenerated_a,
Point1 const& a1, Point1 const& a2,
Point2 const& b1, Point2 const& b2,
ResultInverse const& res_a1_a2,
ResultInverse const& res_a1_bi,
bool is_other_reversed)
{
CalcT dist_1_2, dist_1_o;
if (! calculate_collinear_data(a1, a2, b1, b2, res_a1_a2, res_a1_bi, dist_1_2, dist_1_o))
{
return Policy::disjoint();
}
// NOTE: If segment was reversed segment ratio has to be altered
if (is_other_reversed)
{
// distance for ratio
dist_1_o = dist_1_2 - dist_1_o;
}
return Policy::one_degenerate(segment, segment_ratio<CalcT>(dist_1_o, dist_1_2), degenerated_a);
}
// TODO: instead of checks below test bi against a1 and a2 here?
// in order to make this independent from is_near()
template <typename Point1, typename Point2, typename ResultInverse, typename CalcT>
static inline bool calculate_collinear_data(Point1 const& a1, Point1 const& a2, // in
Point2 const& b1, Point2 const& b2, // in
ResultInverse const& res_a1_a2, // in
ResultInverse const& res_a1_bi, // in
CalcT& dist_a1_a2, CalcT& dist_a1_bi) // out
{
dist_a1_a2 = res_a1_a2.distance;
dist_a1_bi = res_a1_bi.distance;
if (! same_direction(res_a1_bi.azimuth, res_a1_a2.azimuth))
{
dist_a1_bi = -dist_a1_bi;
}
// if i1 is close to a1 and b1 or b2 is equal to a1
if (is_endpoint_equal(dist_a1_bi, a1, b1, b2))
{
dist_a1_bi = 0;
return true;
}
// or i1 is close to a2 and b1 or b2 is equal to a2
else if (is_endpoint_equal(dist_a1_a2 - dist_a1_bi, a2, b1, b2))
{
dist_a1_bi = dist_a1_a2;
return true;
}
// or i1 is on b
return segment_ratio<CalcT>(dist_a1_bi, dist_a1_a2).on_segment();
}
template <typename Point1, typename Point2, typename CalcT, typename ResultInverse, typename Spheroid_>
static inline bool calculate_ip_data(Point1 const& a1, Point1 const& a2, // in
Point2 const& b1, Point2 const& b2, // in
CalcT const& a1_lon, CalcT const& a1_lat, // in
CalcT const& a2_lon, CalcT const& a2_lat, // in
CalcT const& b1_lon, CalcT const& b1_lat, // in
CalcT const& b2_lon, CalcT const& b2_lat, // in
ResultInverse const& res_a1_a2, // in
ResultInverse const& res_a1_b1, // in
ResultInverse const& res_a1_b2, // in
ResultInverse const& res_b1_b2, // in
ResultInverse const& res_b1_a1, // in
ResultInverse const& res_b1_a2, // in
side_info const& sides, // in
Spheroid_ const& spheroid, // in
CalcT & lon, CalcT & lat, // out
CalcT& dist_a1_a2, CalcT& dist_a1_ip, // out
CalcT& dist_b1_b2, CalcT& dist_b1_ip, // out
intersection_point_flag& ip_flag) // out
{
dist_a1_a2 = res_a1_a2.distance;
dist_b1_b2 = res_b1_b2.distance;
// assign the IP if some endpoints overlap
using geometry::detail::equals::equals_point_point;
if (equals_point_point(a1, b1))
{
lon = a1_lon;
lat = a1_lat;
dist_a1_ip = 0;
dist_b1_ip = 0;
ip_flag = ipi_at_a1;
return true;
}
else if (equals_point_point(a1, b2))
{
lon = a1_lon;
lat = a1_lat;
dist_a1_ip = 0;
dist_b1_ip = dist_b1_b2;
ip_flag = ipi_at_a1;
return true;
}
else if (equals_point_point(a2, b1))
{
lon = a2_lon;
lat = a2_lat;
dist_a1_ip = dist_a1_a2;
dist_b1_ip = 0;
ip_flag = ipi_at_a2;
return true;
}
else if (equals_point_point(a2, b2))
{
lon = a2_lon;
lat = a2_lat;
dist_a1_ip = dist_a1_a2;
dist_b1_ip = dist_b1_b2;
ip_flag = ipi_at_a2;
return true;
}
// at this point we know that the endpoints doesn't overlap
// check cases when an endpoint lies on the other geodesic
if (sides.template get<0, 0>() == 0) // a1 wrt b
{
if (res_b1_a1.distance <= res_b1_b2.distance
&& same_direction(res_b1_a1.azimuth, res_b1_b2.azimuth))
{
lon = a1_lon;
lat = a1_lat;
dist_a1_ip = 0;
dist_b1_ip = res_b1_a1.distance;
ip_flag = ipi_at_a1;
return true;
}
else
{
return false;
}
}
else if (sides.template get<0, 1>() == 0) // a2 wrt b
{
if (res_b1_a2.distance <= res_b1_b2.distance
&& same_direction(res_b1_a2.azimuth, res_b1_b2.azimuth))
{
lon = a2_lon;
lat = a2_lat;
dist_a1_ip = res_a1_a2.distance;
dist_b1_ip = res_b1_a2.distance;
ip_flag = ipi_at_a2;
return true;
}
else
{
return false;
}
}
else if (sides.template get<1, 0>() == 0) // b1 wrt a
{
if (res_a1_b1.distance <= res_a1_a2.distance
&& same_direction(res_a1_b1.azimuth, res_a1_a2.azimuth))
{
lon = b1_lon;
lat = b1_lat;
dist_a1_ip = res_a1_b1.distance;
dist_b1_ip = 0;
ip_flag = ipi_at_b1;
return true;
}
else
{
return false;
}
}
else if (sides.template get<1, 1>() == 0) // b2 wrt a
{
if (res_a1_b2.distance <= res_a1_a2.distance
&& same_direction(res_a1_b2.azimuth, res_a1_a2.azimuth))
{
lon = b2_lon;
lat = b2_lat;
dist_a1_ip = res_a1_b2.distance;
dist_b1_ip = res_b1_b2.distance;
ip_flag = ipi_at_b2;
return true;
}
else
{
return false;
}
}
// At this point neither the endpoints overlaps
// nor any andpoint lies on the other geodesic
// So the endpoints should lie on the opposite sides of both geodesics
bool const ok = formula::sjoberg_intersection<CalcT, FormulaPolicy::template inverse, Order>
::apply(a1_lon, a1_lat, a2_lon, a2_lat, res_a1_a2.azimuth,
b1_lon, b1_lat, b2_lon, b2_lat, res_b1_b2.azimuth,
lon, lat, spheroid);
if (! ok)
{
return false;
}
typedef typename FormulaPolicy::template inverse<CalcT, true, true, false, false, false> inverse_dist_azi;
typedef typename inverse_dist_azi::result_type inverse_result;
inverse_result const res_a1_ip = inverse_dist_azi::apply(a1_lon, a1_lat, lon, lat, spheroid);
dist_a1_ip = res_a1_ip.distance;
if (! same_direction(res_a1_ip.azimuth, res_a1_a2.azimuth))
{
dist_a1_ip = -dist_a1_ip;
}
bool is_on_a = segment_ratio<CalcT>(dist_a1_ip, dist_a1_a2).on_segment();
// NOTE: not fully consistent with equals_point_point() since radians are always used.
bool is_on_a1 = math::equals(lon, a1_lon) && math::equals(lat, a1_lat);
bool is_on_a2 = math::equals(lon, a2_lon) && math::equals(lat, a2_lat);
if (! (is_on_a || is_on_a1 || is_on_a2))
{
return false;
}
inverse_result const res_b1_ip = inverse_dist_azi::apply(b1_lon, b1_lat, lon, lat, spheroid);
dist_b1_ip = res_b1_ip.distance;
if (! same_direction(res_b1_ip.azimuth, res_b1_b2.azimuth))
{
dist_b1_ip = -dist_b1_ip;
}
bool is_on_b = segment_ratio<CalcT>(dist_b1_ip, dist_b1_b2).on_segment();
// NOTE: not fully consistent with equals_point_point() since radians are always used.
bool is_on_b1 = math::equals(lon, b1_lon) && math::equals(lat, b1_lat);
bool is_on_b2 = math::equals(lon, b2_lon) && math::equals(lat, b2_lat);
if (! (is_on_b || is_on_b1 || is_on_b2))
{
return false;
}
ip_flag = ipi_inters;
if (is_on_b1)
{
lon = b1_lon;
lat = b1_lat;
dist_b1_ip = 0;
ip_flag = ipi_at_b1;
}
else if (is_on_b2)
{
lon = b2_lon;
lat = b2_lat;
dist_b1_ip = res_b1_b2.distance;
ip_flag = ipi_at_b2;
}
if (is_on_a1)
{
lon = a1_lon;
lat = a1_lat;
dist_a1_ip = 0;
ip_flag = ipi_at_a1;
}
else if (is_on_a2)
{
lon = a2_lon;
lat = a2_lat;
dist_a1_ip = res_a1_a2.distance;
ip_flag = ipi_at_a2;
}
return true;
}
template <typename CalcT, typename P1, typename P2>
static inline bool is_endpoint_equal(CalcT const& dist,
P1 const& ai, P2 const& b1, P2 const& b2)
{
using geometry::detail::equals::equals_point_point;
return is_near(dist) && (equals_point_point(ai, b1) || equals_point_point(ai, b2));
}
template <typename CalcT>
static inline bool is_near(CalcT const& dist)
{
// NOTE: This strongly depends on the Inverse method
CalcT const small_number = CalcT(boost::is_same<CalcT, float>::value ? 0.0001 : 0.00000001);
return math::abs(dist) <= small_number;
}
template <typename ProjCoord1, typename ProjCoord2>
static inline int position_value(ProjCoord1 const& ca1,
ProjCoord2 const& cb1,
ProjCoord2 const& cb2)
{
// S1x 0 1 2 3 4
// S2 |---------->
return math::equals(ca1, cb1) ? 1
: math::equals(ca1, cb2) ? 3
: cb1 < cb2 ?
( ca1 < cb1 ? 0
: ca1 > cb2 ? 4
: 2 )
: ( ca1 > cb1 ? 0
: ca1 < cb2 ? 4
: 2 );
}
template <typename CalcT>
static inline bool same_direction(CalcT const& azimuth1, CalcT const& azimuth2)
{
// distance between two angles normalized to (-180, 180]
CalcT const angle_diff = math::longitude_distance_signed<radian>(azimuth1, azimuth2);
return math::abs(angle_diff) <= math::half_pi<CalcT>();
}
template <int Which>
static inline void sides_reverse_segment(side_info & sides)
{
// names assuming segment A is reversed (Which == 0)
int a1_wrt_b = sides.template get<Which, 0>();
int a2_wrt_b = sides.template get<Which, 1>();
std::swap(a1_wrt_b, a2_wrt_b);
sides.template set<Which>(a1_wrt_b, a2_wrt_b);
int b1_wrt_a = sides.template get<1 - Which, 0>();
int b2_wrt_a = sides.template get<1 - Which, 1>();
sides.template set<1 - Which>(-b1_wrt_a, -b2_wrt_a);
}
static inline void ip_flag_reverse_segment(intersection_point_flag & ip_flag,
intersection_point_flag const& ipi_at_p1,
intersection_point_flag const& ipi_at_p2)
{
ip_flag = ip_flag == ipi_at_p1 ? ipi_at_p2 :
ip_flag == ipi_at_p2 ? ipi_at_p1 :
ip_flag;
}
template <typename CalcT, typename SpheroidT>
static inline srs::spheroid<CalcT> normalized_spheroid(SpheroidT const& spheroid)
{
return srs::spheroid<CalcT>(CalcT(1),
CalcT(get_radius<2>(spheroid)) // b/a
/ CalcT(get_radius<0>(spheroid)));
}
private:
Spheroid m_spheroid;
};
}} // namespace strategy::intersection
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_INTERSECTION_HPP
@@ -0,0 +1,243 @@
// Boost.Geometry
// Copyright (c) 2016-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_INTERSECTION_ELLIPTIC_HPP
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_INTERSECTION_ELLIPTIC_HPP
#include <boost/geometry/core/srs.hpp>
#include <boost/geometry/formulas/geographic.hpp>
#include <boost/geometry/strategies/spherical/intersection.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace intersection
{
template <typename Spheroid>
struct great_elliptic_segments_calc_policy
: spherical_segments_calc_policy
{
explicit great_elliptic_segments_calc_policy(Spheroid const& spheroid = Spheroid())
: m_spheroid(spheroid)
{}
template <typename Point, typename Point3d>
Point from_cart3d(Point3d const& point_3d) const
{
return formula::cart3d_to_geo<Point>(point_3d, m_spheroid);
}
template <typename Point3d, typename Point>
Point3d to_cart3d(Point const& point) const
{
return formula::geo_to_cart3d<Point3d>(point, m_spheroid);
}
// relate_xxx_calc_policy must live londer than plane because it contains
// Spheroid object and plane keeps the reference to that object.
template <typename Point3d>
struct plane
{
typedef typename coordinate_type<Point3d>::type coord_t;
// not normalized
plane(Point3d const& p1, Point3d const& p2)
: normal(cross_product(p1, p2))
{}
int side_value(Point3d const& pt) const
{
return formula::sph_side_value(normal, pt);
}
coord_t cos_angle_between(Point3d const& p1, Point3d const& p2) const
{
Point3d v1 = p1;
detail::vec_normalize(v1);
Point3d v2 = p2;
detail::vec_normalize(v2);
return dot_product(v1, v2);
}
coord_t cos_angle_between(Point3d const& p1, Point3d const& p2, bool & is_forward) const
{
coord_t const c0 = 0;
Point3d v1 = p1;
detail::vec_normalize(v1);
Point3d v2 = p2;
detail::vec_normalize(v2);
is_forward = dot_product(normal, cross_product(v1, v2)) >= c0;
return dot_product(v1, v2);
}
Point3d normal;
};
template <typename Point3d>
plane<Point3d> get_plane(Point3d const& p1, Point3d const& p2) const
{
return plane<Point3d>(p1, p2);
}
template <typename Point3d>
bool intersection_points(plane<Point3d> const& plane1,
plane<Point3d> const& plane2,
Point3d & ip1, Point3d & ip2) const
{
typedef typename coordinate_type<Point3d>::type coord_t;
Point3d id = cross_product(plane1.normal, plane2.normal);
// NOTE: the length should be greater than 0 at this point
// NOTE: no need to normalize in this case
ip1 = formula::projected_to_surface(id, m_spheroid);
ip2 = ip1;
multiply_value(ip2, coord_t(-1));
return true;
}
private:
Spheroid m_spheroid;
};
template <typename Spheroid>
struct experimental_elliptic_segments_calc_policy
{
explicit experimental_elliptic_segments_calc_policy(Spheroid const& spheroid = Spheroid())
: m_spheroid(spheroid)
{}
template <typename Point, typename Point3d>
Point from_cart3d(Point3d const& point_3d) const
{
return formula::cart3d_to_geo<Point>(point_3d, m_spheroid);
}
template <typename Point3d, typename Point>
Point3d to_cart3d(Point const& point) const
{
return formula::geo_to_cart3d<Point3d>(point, m_spheroid);
}
// relate_xxx_calc_policy must live londer than plane because it contains
// Spheroid object and plane keeps the reference to that object.
template <typename Point3d>
struct plane
{
typedef typename coordinate_type<Point3d>::type coord_t;
// not normalized
plane(Point3d const& p1, Point3d const& p2, Spheroid const& spheroid)
: m_spheroid(spheroid)
{
formula::experimental_elliptic_plane(p1, p2, origin, normal, m_spheroid);
}
int side_value(Point3d const& pt) const
{
return formula::elliptic_side_value(origin, normal, pt);
}
coord_t cos_angle_between(Point3d const& p1, Point3d const& p2) const
{
Point3d const v1 = normalized_vec(p1);
Point3d const v2 = normalized_vec(p2);
return dot_product(v1, v2);
}
coord_t cos_angle_between(Point3d const& p1, Point3d const& p2, bool & is_forward) const
{
coord_t const c0 = 0;
Point3d const v1 = normalized_vec(p1);
Point3d const v2 = normalized_vec(p2);
is_forward = dot_product(normal, cross_product(v1, v2)) >= c0;
return dot_product(v1, v2);
}
Point3d origin;
Point3d normal;
private:
Point3d normalized_vec(Point3d const& p) const
{
Point3d v = p;
subtract_point(v, origin);
detail::vec_normalize(v);
return v;
}
Spheroid const& m_spheroid;
};
template <typename Point3d>
plane<Point3d> get_plane(Point3d const& p1, Point3d const& p2) const
{
return plane<Point3d>(p1, p2, m_spheroid);
}
template <typename Point3d>
bool intersection_points(plane<Point3d> const& plane1,
plane<Point3d> const& plane2,
Point3d & ip1, Point3d & ip2) const
{
return formula::planes_spheroid_intersection(plane1.origin, plane1.normal,
plane2.origin, plane2.normal,
ip1, ip2, m_spheroid);
}
private:
Spheroid m_spheroid;
};
template
<
typename Spheroid = srs::spheroid<double>,
typename CalculationType = void
>
struct great_elliptic_segments
: ecef_segments
<
great_elliptic_segments_calc_policy<Spheroid>,
CalculationType
>
{};
template
<
typename Spheroid = srs::spheroid<double>,
typename CalculationType = void
>
struct experimental_elliptic_segments
: ecef_segments
<
experimental_elliptic_segments_calc_policy<Spheroid>,
CalculationType
>
{};
}} // namespace strategy::intersection
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_INTERSECTION_ELLIPTIC_HPP
@@ -0,0 +1,185 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2011-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014, 2017.
// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_MAPPING_SSF_HPP
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_MAPPING_SSF_HPP
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/core/radius.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/strategies/spherical/ssf.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace side
{
// An enumeration type defining types of mapping of geographical
// latitude to spherical latitude.
// See: http://en.wikipedia.org/wiki/Great_ellipse
// http://en.wikipedia.org/wiki/Latitude#Auxiliary_latitudes
enum mapping_type { mapping_geodetic, mapping_reduced, mapping_geocentric };
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template <typename Spheroid, mapping_type Mapping>
struct mapper
{
explicit inline mapper(Spheroid const& /*spheroid*/) {}
template <typename CalculationType>
static inline CalculationType const& apply(CalculationType const& lat)
{
return lat;
}
};
template <typename Spheroid>
struct mapper<Spheroid, mapping_reduced>
{
typedef typename promote_floating_point
<
typename radius_type<Spheroid>::type
>::type fraction_type;
explicit inline mapper(Spheroid const& spheroid)
{
fraction_type const a = geometry::get_radius<0>(spheroid);
fraction_type const b = geometry::get_radius<2>(spheroid);
b_div_a = b / a;
}
template <typename CalculationType>
inline CalculationType apply(CalculationType const& lat) const
{
return atan(static_cast<CalculationType>(b_div_a) * tan(lat));
}
fraction_type b_div_a;
};
template <typename Spheroid>
struct mapper<Spheroid, mapping_geocentric>
{
typedef typename promote_floating_point
<
typename radius_type<Spheroid>::type
>::type fraction_type;
explicit inline mapper(Spheroid const& spheroid)
{
fraction_type const a = geometry::get_radius<0>(spheroid);
fraction_type const b = geometry::get_radius<2>(spheroid);
sqr_b_div_a = b / a;
sqr_b_div_a *= sqr_b_div_a;
}
template <typename CalculationType>
inline CalculationType apply(CalculationType const& lat) const
{
return atan(static_cast<CalculationType>(sqr_b_div_a) * tan(lat));
}
fraction_type sqr_b_div_a;
};
}
#endif // DOXYGEN_NO_DETAIL
/*!
\brief Check at which side of a geographical segment a point lies
left of segment (> 0), right of segment (< 0), on segment (0).
The check is performed by mapping the geographical coordinates
to spherical coordinates and using spherical_side_formula.
\ingroup strategies
\tparam Spheroid The reference spheroid model
\tparam Mapping The type of mapping of geographical to spherical latitude
\tparam CalculationType \tparam_calculation
*/
template <typename Spheroid,
mapping_type Mapping = mapping_geodetic,
typename CalculationType = void>
class mapping_spherical_side_formula
{
public :
inline mapping_spherical_side_formula()
: m_mapper(Spheroid())
{}
explicit inline mapping_spherical_side_formula(Spheroid const& spheroid)
: m_mapper(spheroid)
{}
template <typename P1, typename P2, typename P>
inline int apply(P1 const& p1, P2 const& p2, P const& p) const
{
typedef typename promote_floating_point
<
typename select_calculation_type_alt
<
CalculationType,
P1, P2, P
>::type
>::type calculation_type;
calculation_type lon1 = get_as_radian<0>(p1);
calculation_type lat1 = m_mapper.template apply<calculation_type>(get_as_radian<1>(p1));
calculation_type lon2 = get_as_radian<0>(p2);
calculation_type lat2 = m_mapper.template apply<calculation_type>(get_as_radian<1>(p2));
calculation_type lon = get_as_radian<0>(p);
calculation_type lat = m_mapper.template apply<calculation_type>(get_as_radian<1>(p));
return detail::spherical_side_formula(lon1, lat1, lon2, lat2, lon, lat);
}
private:
side::detail::mapper<Spheroid, Mapping> const m_mapper;
};
// The specialization for geodetic latitude which can be used directly
template <typename Spheroid,
typename CalculationType>
class mapping_spherical_side_formula<Spheroid, mapping_geodetic, CalculationType>
{
public :
inline mapping_spherical_side_formula() {}
explicit inline mapping_spherical_side_formula(Spheroid const& /*spheroid*/) {}
template <typename P1, typename P2, typename P>
static inline int apply(P1 const& p1, P2 const& p2, P const& p)
{
return spherical_side_formula<CalculationType>::apply(p1, p2, p);
}
};
}} // namespace strategy::side
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_MAPPING_SSF_HPP
@@ -0,0 +1,117 @@
// Boost.Geometry
// Copyright (c) 2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_PARAMETERS_HPP
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_PARAMETERS_HPP
#include <boost/geometry/formulas/andoyer_inverse.hpp>
#include <boost/geometry/formulas/thomas_inverse.hpp>
#include <boost/geometry/formulas/vincenty_inverse.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/mpl/integral_c.hpp>
namespace boost { namespace geometry { namespace strategy
{
struct andoyer
{
template
<
typename CT,
bool EnableDistance,
bool EnableAzimuth,
bool EnableReverseAzimuth = false,
bool EnableReducedLength = false,
bool EnableGeodesicScale = false
>
struct inverse
: formula::andoyer_inverse
<
CT, EnableDistance,
EnableAzimuth, EnableReverseAzimuth,
EnableReducedLength, EnableGeodesicScale
>
{};
};
struct thomas
{
template
<
typename CT,
bool EnableDistance,
bool EnableAzimuth,
bool EnableReverseAzimuth = false,
bool EnableReducedLength = false,
bool EnableGeodesicScale = false
>
struct inverse
: formula::thomas_inverse
<
CT, EnableDistance,
EnableAzimuth, EnableReverseAzimuth,
EnableReducedLength, EnableGeodesicScale
>
{};
};
struct vincenty
{
template
<
typename CT,
bool EnableDistance,
bool EnableAzimuth,
bool EnableReverseAzimuth = false,
bool EnableReducedLength = false,
bool EnableGeodesicScale = false
>
struct inverse
: formula::vincenty_inverse
<
CT, EnableDistance,
EnableAzimuth, EnableReverseAzimuth,
EnableReducedLength, EnableGeodesicScale
>
{};
};
template <typename FormulaPolicy>
struct default_order
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_IMPLEMENTED_FOR_THIS_TYPE
, (types<FormulaPolicy>)
);
};
template<>
struct default_order<andoyer>
: boost::mpl::integral_c<unsigned int, 1>
{};
template<>
struct default_order<thomas>
: boost::mpl::integral_c<unsigned int, 2>
{};
template<>
struct default_order<vincenty>
: boost::mpl::integral_c<unsigned int, 4>
{};
}}} // namespace boost::geometry::strategy
#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_PARAMETERS_HPP
@@ -0,0 +1,113 @@
// Boost.Geometry
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014-2017.
// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_HPP
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_HPP
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/core/radius.hpp>
#include <boost/geometry/core/srs.hpp>
#include <boost/geometry/formulas/spherical.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/strategies/geographic/parameters.hpp>
#include <boost/geometry/strategies/side.hpp>
//#include <boost/geometry/strategies/concepts/side_concept.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace side
{
/*!
\brief Check at which side of a segment a point lies
left of segment (> 0), right of segment (< 0), on segment (0)
\ingroup strategies
\tparam FormulaPolicy Geodesic solution formula policy.
\tparam Spheroid Reference model of coordinate system.
\tparam CalculationType \tparam_calculation
*/
template
<
typename FormulaPolicy = strategy::andoyer,
typename Spheroid = srs::spheroid<double>,
typename CalculationType = void
>
class geographic
{
public:
geographic()
{}
explicit geographic(Spheroid const& model)
: m_model(model)
{}
template <typename P1, typename P2, typename P>
inline int apply(P1 const& p1, P2 const& p2, P const& p) const
{
typedef typename promote_floating_point
<
typename select_calculation_type_alt
<
CalculationType,
P1, P2, P
>::type
>::type calc_t;
typedef typename FormulaPolicy::template inverse
<calc_t, false, true, false, false, false> inverse_formula;
calc_t a1p = azimuth<calc_t, inverse_formula>(p1, p, m_model);
calc_t a12 = azimuth<calc_t, inverse_formula>(p1, p2, m_model);
return formula::azimuth_side_value(a1p, a12);
}
private:
template <typename ResultType,
typename InverseFormulaType,
typename Point1,
typename Point2,
typename ModelT>
static inline ResultType azimuth(Point1 const& point1, Point2 const& point2,
ModelT const& model)
{
return InverseFormulaType::apply(get_as_radian<0>(point1),
get_as_radian<1>(point1),
get_as_radian<0>(point2),
get_as_radian<1>(point2),
model).azimuth;
}
Spheroid m_model;
};
}} // namespace strategy::side
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_HPP
@@ -0,0 +1,60 @@
// Boost.Geometry
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014-2017.
// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_ANDOYER_HPP
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_ANDOYER_HPP
#include <boost/geometry/strategies/geographic/side.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace side
{
/*!
\brief Check at which side of a segment a point lies
left of segment (> 0), right of segment (< 0), on segment (0)
\ingroup strategies
\tparam Spheroid Reference model of coordinate system.
\tparam CalculationType \tparam_calculation
*/
template
<
typename Spheroid = srs::spheroid<double>,
typename CalculationType = void
>
class andoyer
: public side::geographic<strategy::andoyer, Spheroid, CalculationType>
{
typedef side::geographic<strategy::andoyer, Spheroid, CalculationType> base_t;
public:
andoyer()
{}
explicit andoyer(Spheroid const& model)
: base_t(model)
{}
};
}} // namespace strategy::side
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_ANDOYER_HPP
@@ -0,0 +1,60 @@
// Boost.Geometry
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014-2017.
// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_THOMAS_HPP
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_THOMAS_HPP
#include <boost/geometry/strategies/geographic/side.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace side
{
/*!
\brief Check at which side of a segment a point lies
left of segment (> 0), right of segment (< 0), on segment (0)
\ingroup strategies
\tparam Spheroid Reference model of coordinate system.
\tparam CalculationType \tparam_calculation
*/
template
<
typename Spheroid = srs::spheroid<double>,
typename CalculationType = void
>
class thomas
: public side::geographic<strategy::thomas, Spheroid, CalculationType>
{
typedef side::geographic<strategy::thomas, Spheroid, CalculationType> base_t;
public:
thomas()
{}
explicit thomas(Spheroid const& model)
: base_t(model)
{}
};
}} // namespace strategy::side
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_THOMAS_HPP
@@ -0,0 +1,60 @@
// Boost.Geometry
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014-2017.
// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_VINCENTY_HPP
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_VINCENTY_HPP
#include <boost/geometry/strategies/geographic/side.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace side
{
/*!
\brief Check at which side of a segment a point lies
left of segment (> 0), right of segment (< 0), on segment (0)
\ingroup strategies
\tparam Spheroid Reference model of coordinate system.
\tparam CalculationType \tparam_calculation
*/
template
<
typename Spheroid = srs::spheroid<double>,
typename CalculationType = void
>
class vincenty
: public side::geographic<strategy::vincenty, Spheroid, CalculationType>
{
typedef side::geographic<strategy::vincenty, Spheroid, CalculationType> base_t;
public:
vincenty()
{}
explicit vincenty(Spheroid const& model)
: base_t(model)
{}
};
}} // namespace strategy::side
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_SIDE_VINCENTY_HPP
@@ -0,0 +1,51 @@
// Boost.Geometry
// Copyright (c) 2016-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_SEGMENT_INTERSECTION_HPP
#define BOOST_GEOMETRY_STRATEGIES_SEGMENT_INTERSECTION_HPP
#include <boost/geometry/strategies/tags.hpp>
#include <boost/mpl/assert.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace intersection
{
namespace services
{
/*!
\brief Traits class binding a segments intersection strategy to a coordinate system
\ingroup util
\tparam CSTag tag of coordinate system of point-type
\tparam CalculationType \tparam_calculation
*/
template <typename CSTag, typename CalculationType = void>
struct default_strategy
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_IMPLEMENTED_FOR_THIS_TYPE
, (types<CSTag>)
);
};
} // namespace services
}} // namespace strategy::intersection
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_SEGMENT_INTERSECTION_HPP
@@ -0,0 +1,78 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2015, 2016.
// Modifications copyright (c) 2015-2016 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_INTERSECTION_RESULT_HPP
#define BOOST_GEOMETRY_STRATEGIES_INTERSECTION_RESULT_HPP
#if defined(HAVE_MATRIX_AS_STRING)
#include <string>
#endif
#include <cstddef>
namespace boost { namespace geometry
{
template <typename SegmentRatio>
struct fraction_type
{
SegmentRatio robust_ra; // TODO this can be renamed now to "ra"
SegmentRatio robust_rb;
bool initialized;
inline fraction_type()
: initialized(false)
{}
template <typename Info>
inline void assign(Info const& info)
{
initialized = true;
robust_ra = info.robust_ra;
robust_rb = info.robust_rb;
}
inline void assign(SegmentRatio const& a, SegmentRatio const& b)
{
initialized = true;
robust_ra = a;
robust_rb = b;
}
};
//
/*!
\brief return-type for segment-intersection
\note Set in intersection_points.hpp, from segment_intersection_info
*/
template <typename Point, typename SegmentRatio>
struct segment_intersection_points
{
std::size_t count; // The number of intersection points
// TODO: combine intersections and fractions in one struct
Point intersections[2];
fraction_type<SegmentRatio> fractions[2];
typedef Point point_type;
segment_intersection_points()
: count(0)
{}
};
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_INTERSECTION_RESULT_HPP
@@ -0,0 +1,101 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2016, 2017.
// Modifications copyright (c) 2016-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_INTERSECTION_HPP
#define BOOST_GEOMETRY_STRATEGIES_INTERSECTION_HPP
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/policies/relate/intersection_points.hpp>
#include <boost/geometry/policies/relate/direction.hpp>
#include <boost/geometry/policies/relate/tupled.hpp>
#include <boost/geometry/strategies/intersection.hpp>
#include <boost/geometry/strategies/intersection_result.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/strategies/cartesian/intersection.hpp>
#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>
#include <boost/geometry/strategies/spherical/intersection.hpp>
#include <boost/geometry/strategies/spherical/ssf.hpp>
#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
namespace boost { namespace geometry
{
/*!
\brief "compound strategy", containing a segment-intersection-strategy
and a side-strategy
*/
template
<
typename Tag,
typename Geometry1,
typename Geometry2,
typename IntersectionPoint,
typename RobustPolicy,
typename CalculationType = void
>
struct intersection_strategies
{
private :
// for development BOOST_STATIC_ASSERT((! boost::is_same<RobustPolicy, void>::type::value));
typedef typename geometry::point_type<Geometry1>::type point1_type;
typedef typename geometry::point_type<Geometry2>::type point2_type;
typedef typename model::referring_segment<point1_type const> segment1_type;
typedef typename model::referring_segment<point2_type const> segment2_type;
typedef segment_intersection_points
<
IntersectionPoint,
typename geometry::segment_ratio_type
<
IntersectionPoint, RobustPolicy
>::type
> ip_type;
public:
typedef policies::relate::segments_tupled
<
policies::relate::segments_intersection_points
<
ip_type
> ,
policies::relate::segments_direction
> intersection_policy_type;
typedef typename strategy::intersection::services::default_strategy
<
Tag,
CalculationType
>::type segment_intersection_strategy_type;
typedef typename strategy::side::services::default_strategy
<
Tag,
CalculationType
>::type side_strategy_type;
typedef RobustPolicy rescale_policy_type;
};
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_INTERSECTION_HPP
@@ -0,0 +1,177 @@
// Boost.Geometry
// Copyright (c) 2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_RELATE_HPP
#define BOOST_GEOMETRY_STRATEGIES_RELATE_HPP
#include <boost/mpl/assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/topological_dimension.hpp>
#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/intersection.hpp>
#include <boost/geometry/strategies/within.hpp>
namespace boost { namespace geometry
{
namespace strategy
{
namespace point_in_geometry
{
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template
<
typename Point,
typename Geometry,
typename Tag1 = typename tag<Point>::type,
typename Tag2 = typename tag<Geometry>::type
>
struct default_strategy
: strategy::within::services::default_strategy
<
Point,
Geometry
>
{
typedef typename default_strategy::type within_strategy_type;
typedef typename strategy::covered_by::services::default_strategy
<
Point,
Geometry
>::type covered_by_strategy_type;
static const bool same_strategies = boost::is_same<within_strategy_type, covered_by_strategy_type>::value;
BOOST_MPL_ASSERT_MSG((same_strategies),
DEFAULT_WITHIN_AND_COVERED_BY_STRATEGIES_NOT_COMPATIBLE,
(within_strategy_type, covered_by_strategy_type));
};
template<typename Point, typename Geometry>
struct default_strategy<Point, Geometry, point_tag, point_tag>
: strategy::within::services::default_strategy<Point, Geometry>
{};
template<typename Point, typename Geometry>
struct default_strategy<Point, Geometry, point_tag, multi_point_tag>
: strategy::within::services::default_strategy<Point, Geometry>
{};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
} // namespace point_in_geometry
namespace relate
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template <typename Geometry>
struct default_intersection_strategy
: strategy::intersection::services::default_strategy
<
typename cs_tag<Geometry>::type
>
{};
template <typename PointLike, typename Geometry>
struct default_point_in_geometry_strategy
: point_in_geometry::services::default_strategy
<
typename point_type<PointLike>::type,
Geometry
>
{};
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template
<
typename Geometry1,
typename Geometry2,
int TopDim1 = geometry::topological_dimension<Geometry1>::value,
int TopDim2 = geometry::topological_dimension<Geometry2>::value
>
struct default_strategy
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_IMPLEMENTED_FOR_THESE_TYPES
, (types<Geometry1, Geometry2>)
);
};
template <typename PointLike1, typename PointLike2>
struct default_strategy<PointLike1, PointLike2, 0, 0>
: detail::default_point_in_geometry_strategy<PointLike1, PointLike2>
{};
template <typename PointLike, typename Geometry, int TopDim2>
struct default_strategy<PointLike, Geometry, 0, TopDim2>
: detail::default_point_in_geometry_strategy<PointLike, Geometry>
{};
template <typename Geometry, typename PointLike, int TopDim1>
struct default_strategy<Geometry, PointLike, TopDim1, 0>
: detail::default_point_in_geometry_strategy<PointLike, Geometry>
{};
template <typename Geometry1, typename Geometry2>
struct default_strategy<Geometry1, Geometry2, 1, 1>
: detail::default_intersection_strategy<Geometry1>
{};
template <typename Geometry1, typename Geometry2>
struct default_strategy<Geometry1, Geometry2, 1, 2>
: detail::default_intersection_strategy<Geometry1>
{};
template <typename Geometry1, typename Geometry2>
struct default_strategy<Geometry1, Geometry2, 2, 1>
: detail::default_intersection_strategy<Geometry1>
{};
template <typename Geometry1, typename Geometry2>
struct default_strategy<Geometry1, Geometry2, 2, 2>
: detail::default_intersection_strategy<Geometry1>
{};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
} // namespace relate
} // namespace strategy
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_RELATE_HPP
@@ -0,0 +1,55 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_SIDE_HPP
#define BOOST_GEOMETRY_STRATEGIES_SIDE_HPP
#include <boost/geometry/strategies/tags.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace side
{
namespace services
{
/*!
\brief Traits class binding a side determination strategy to a coordinate system
\ingroup util
\tparam CSTag tag of coordinate system of point-type
\tparam CalculationType \tparam_calculation
*/
template <typename CSTag, typename CalculationType = void>
struct default_strategy
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_IMPLEMENTED_FOR_THIS_TYPE
, (types<CSTag>)
);
};
} // namespace services
}} // namespace strategy::side
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_SIDE_HPP
@@ -0,0 +1,177 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_SIDE_INFO_HPP
#define BOOST_GEOMETRY_STRATEGIES_SIDE_INFO_HPP
#include <cmath>
#include <utility>
#if defined(BOOST_GEOMETRY_DEBUG_INTERSECTION) || defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
# include <iostream>
#endif
namespace boost { namespace geometry
{
// Silence warning C4127: conditional expression is constant
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4127)
#endif
/*!
\brief Class side_info: small class wrapping for sides (-1,0,1)
*/
class side_info
{
public :
inline side_info(int side_a1 = 0, int side_a2 = 0,
int side_b1 = 0, int side_b2 = 0)
{
sides[0].first = side_a1;
sides[0].second = side_a2;
sides[1].first = side_b1;
sides[1].second = side_b2;
}
template <int Which>
inline void set(int first, int second)
{
sides[Which].first = first;
sides[Which].second = second;
}
template <int Which, int Index>
inline void correct_to_zero()
{
if (Index == 0)
{
sides[Which].first = 0;
}
else
{
sides[Which].second = 0;
}
}
template <int Which, int Index>
inline int get() const
{
return Index == 0 ? sides[Which].first : sides[Which].second;
}
// Returns true if both lying on the same side WRT the other
// (so either 1,1 or -1-1)
template <int Which>
inline bool same() const
{
return sides[Which].first * sides[Which].second == 1;
}
inline bool collinear() const
{
return sides[0].first == 0
&& sides[0].second == 0
&& sides[1].first == 0
&& sides[1].second == 0;
}
inline bool crossing() const
{
return sides[0].first * sides[0].second == -1
&& sides[1].first * sides[1].second == -1;
}
inline bool touching() const
{
return (sides[0].first * sides[1].first == -1
&& sides[0].second == 0 && sides[1].second == 0)
|| (sides[1].first * sides[0].first == -1
&& sides[1].second == 0 && sides[0].second == 0);
}
template <int Which>
inline bool one_touching() const
{
// This is normally a situation which can't occur:
// If one is completely left or right, the other cannot touch
return one_zero<Which>()
&& sides[1 - Which].first * sides[1 - Which].second == 1;
}
inline bool meeting() const
{
// Two of them (in each segment) zero, two not
return one_zero<0>() && one_zero<1>();
}
template <int Which>
inline bool zero() const
{
return sides[Which].first == 0 && sides[Which].second == 0;
}
template <int Which>
inline bool one_zero() const
{
return (sides[Which].first == 0 && sides[Which].second != 0)
|| (sides[Which].first != 0 && sides[Which].second == 0);
}
inline bool one_of_all_zero() const
{
int const sum = std::abs(sides[0].first)
+ std::abs(sides[0].second)
+ std::abs(sides[1].first)
+ std::abs(sides[1].second);
return sum == 3;
}
template <int Which>
inline int zero_index() const
{
return sides[Which].first == 0 ? 0 : 1;
}
#if defined(BOOST_GEOMETRY_DEBUG_INTERSECTION) || defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
inline void debug() const
{
std::cout << sides[0].first << " "
<< sides[0].second << " "
<< sides[1].first << " "
<< sides[1].second
<< std::endl;
}
#endif
inline void reverse()
{
std::swap(sides[0], sides[1]);
}
//private :
std::pair<int, int> sides[2];
};
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_SIDE_INFO_HPP
@@ -0,0 +1,182 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2016-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fisikopoulos, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_HPP
#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_HPP
#include <boost/geometry/formulas/area_formulas.hpp>
#include <boost/geometry/core/radius.hpp>
#include <boost/geometry/core/srs.hpp>
#include <boost/geometry/strategies/area.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace area
{
/*!
\brief Spherical area calculation
\ingroup strategies
\details Calculates area on the surface of a sphere using the trapezoidal rule
\tparam PointOfSegment \tparam_segment_point
\tparam CalculationType \tparam_calculation
\qbk{
[heading See also]
[link geometry.reference.algorithms.area.area_2_with_strategy area (with strategy)]
}
*/
template
<
typename PointOfSegment,
typename CalculationType = void
>
class spherical
{
// Enables special handling of long segments
static const bool LongSegment = false;
typedef typename boost::mpl::if_c
<
boost::is_void<CalculationType>::type::value,
typename select_most_precise
<
typename coordinate_type<PointOfSegment>::type,
double
>::type,
CalculationType
>::type CT;
protected :
struct excess_sum
{
CT m_sum;
// Keep track if encircles some pole
size_t m_crosses_prime_meridian;
inline excess_sum()
: m_sum(0)
, m_crosses_prime_meridian(0)
{}
template <typename SphereType>
inline CT area(SphereType sphere) const
{
CT result;
CT radius = geometry::get_radius<0>(sphere);
// Encircles pole
if(m_crosses_prime_meridian % 2 == 1)
{
size_t times_crosses_prime_meridian
= 1 + (m_crosses_prime_meridian / 2);
result = CT(2)
* geometry::math::pi<CT>()
* times_crosses_prime_meridian
- geometry::math::abs(m_sum);
if(geometry::math::sign<CT>(m_sum) == 1)
{
result = - result;
}
} else {
result = m_sum;
}
result *= radius * radius;
return result;
}
};
public :
typedef CT return_type;
typedef PointOfSegment segment_point_type;
typedef excess_sum state_type;
typedef geometry::srs::sphere<CT> sphere_type;
// For backward compatibility reasons the radius is set to 1
inline spherical()
: m_sphere(1.0)
{}
template <typename T>
explicit inline spherical(geometry::srs::sphere<T> const& sphere)
: m_sphere(geometry::get_radius<0>(sphere))
{}
explicit inline spherical(CT const& radius)
: m_sphere(radius)
{}
inline void apply(PointOfSegment const& p1,
PointOfSegment const& p2,
excess_sum& state) const
{
if (! geometry::math::equals(get<0>(p1), get<0>(p2)))
{
state.m_sum += geometry::formula::area_formulas
<CT>::template spherical<LongSegment>(p1, p2);
// Keep track whenever a segment crosses the prime meridian
geometry::formula::area_formulas
<CT>::crosses_prime_meridian(p1, p2, state);
}
}
inline return_type result(excess_sum const& state) const
{
return state.area(m_sphere);
}
private :
/// srs Sphere
sphere_type m_sphere;
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename Point>
struct default_strategy<spherical_equatorial_tag, Point>
{
typedef strategy::area::spherical<Point> type;
};
// Note: spherical polar coordinate system requires "get_as_radian_equatorial"
template <typename Point>
struct default_strategy<spherical_polar_tag, Point>
{
typedef strategy::area::spherical<Point> type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::area
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_HPP
@@ -0,0 +1,87 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2016-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fisikopoulos, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AZIMUTH_HPP
#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AZIMUTH_HPP
#include <boost/geometry/strategies/azimuth.hpp>
#include <boost/geometry/formulas/spherical.hpp>
#include <boost/mpl/if.hpp>
#include <boost/type_traits/is_void.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace azimuth
{
template
<
typename CalculationType = void
>
class spherical
{
public :
inline spherical()
{}
template <typename T>
static inline void apply(T const& lon1_rad, T const& lat1_rad,
T const& lon2_rad, T const& lat2_rad,
T& a1, T& a2)
{
typedef typename boost::mpl::if_
<
boost::is_void<CalculationType>, T, CalculationType
>::type calc_t;
geometry::formula::result_spherical<calc_t>
result = geometry::formula::spherical_azimuth<calc_t, true>(
calc_t(lon1_rad), calc_t(lat1_rad),
calc_t(lon2_rad), calc_t(lat2_rad));
a1 = result.azimuth;
a2 = result.reverse_azimuth;
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename CalculationType>
struct default_strategy<spherical_equatorial_tag, CalculationType>
{
typedef strategy::azimuth::spherical<CalculationType> type;
};
/*
template <typename CalculationType>
struct default_strategy<spherical_polar_tag, CalculationType>
{
typedef strategy::azimuth::spherical<CalculationType> type;
};
*/
}
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::azimuth
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AZIMUTH_HPP
@@ -0,0 +1,152 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_COMPARE_SPHERICAL_HPP
#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_COMPARE_SPHERICAL_HPP
#include <boost/math/constants/constants.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/strategies/compare.hpp>
#include <boost/geometry/util/math.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace compare
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template <typename Units>
struct shift
{
};
template <>
struct shift<degree>
{
static inline double full() { return 360.0; }
static inline double half() { return 180.0; }
};
template <>
struct shift<radian>
{
static inline double full() { return 2.0 * boost::math::constants::pi<double>(); }
static inline double half() { return boost::math::constants::pi<double>(); }
};
} // namespace detail
#endif
/*!
\brief Compare (in one direction) strategy for spherical coordinates
\ingroup strategies
\tparam Point point-type
\tparam Dimension dimension
*/
template <typename CoordinateType, typename Units, typename Compare>
struct circular_comparator
{
static inline CoordinateType put_in_range(CoordinateType const& c,
double min_border, double max_border)
{
CoordinateType value = c;
while (value < min_border)
{
value += detail::shift<Units>::full();
}
while (value > max_border)
{
value -= detail::shift<Units>::full();
}
return value;
}
inline bool operator()(CoordinateType const& c1, CoordinateType const& c2) const
{
Compare compare;
// Check situation that one of them is e.g. std::numeric_limits.
static const double full = detail::shift<Units>::full();
double mx = 10.0 * full;
if (c1 < -mx || c1 > mx || c2 < -mx || c2 > mx)
{
// do normal comparison, using circular is not useful
return compare(c1, c2);
}
static const double half = full / 2.0;
CoordinateType v1 = put_in_range(c1, -half, half);
CoordinateType v2 = put_in_range(c2, -half, half);
// Two coordinates on a circle are
// at max <= half a circle away from each other.
// So if it is more, shift origin.
CoordinateType diff = geometry::math::abs(v1 - v2);
if (diff > half)
{
v1 = put_in_range(v1, 0, full);
v2 = put_in_range(v2, 0, full);
}
return compare(v1, v2);
}
};
}} // namespace strategy::compare
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
// Specialize for the longitude (dim 0)
template
<
typename Point,
template<typename> class CoordinateSystem,
typename Units
>
struct strategy_compare<spherical_polar_tag, 1, Point, CoordinateSystem<Units>, 0>
{
typedef typename coordinate_type<Point>::type coordinate_type;
typedef strategy::compare::circular_comparator
<
coordinate_type,
Units,
std::less<coordinate_type>
> type;
};
template
<
typename Point,
template<typename> class CoordinateSystem,
typename Units
>
struct strategy_compare<spherical_polar_tag, -1, Point, CoordinateSystem<Units>, 0>
{
typedef typename coordinate_type<Point>::type coordinate_type;
typedef strategy::compare::circular_comparator
<
coordinate_type,
Units,
std::greater<coordinate_type>
> type;
};
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_COMPARE_SPHERICAL_HPP
@@ -0,0 +1,773 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_HPP
#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_HPP
#include <algorithm>
#include <boost/config.hpp>
#include <boost/concept_check.hpp>
#include <boost/mpl/if.hpp>
#include <boost/type_traits/is_void.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/detail/course.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/concepts/distance_concept.hpp>
#include <boost/geometry/strategies/spherical/distance_haversine.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK
# include <boost/geometry/io/dsv/write.hpp>
#endif
namespace boost { namespace geometry
{
namespace strategy { namespace distance
{
namespace comparable
{
/*
Given a spherical segment AB and a point D, we are interested in
computing the distance of D from AB. This is usually known as the
cross track distance.
If the projection (along great circles) of the point D lies inside
the segment AB, then the distance (cross track error) XTD is given
by the formula (see http://williams.best.vwh.net/avform.htm#XTE):
XTD = asin( sin(dist_AD) * sin(crs_AD-crs_AB) )
where dist_AD is the great circle distance between the points A and
B, and crs_AD, crs_AB is the course (bearing) between the points A,
D and A, B, respectively.
If the point D does not project inside the arc AB, then the distance
of D from AB is the minimum of the two distances dist_AD and dist_BD.
Our reference implementation for this procedure is listed below
(this was the old Boost.Geometry implementation of the cross track distance),
where:
* The member variable m_strategy is the underlying haversine strategy.
* p stands for the point D.
* sp1 stands for the segment endpoint A.
* sp2 stands for the segment endpoint B.
================= reference implementation -- start =================
return_type d1 = m_strategy.apply(sp1, p);
return_type d3 = m_strategy.apply(sp1, sp2);
if (geometry::math::equals(d3, 0.0))
{
// "Degenerate" segment, return either d1 or d2
return d1;
}
return_type d2 = m_strategy.apply(sp2, p);
return_type crs_AD = geometry::detail::course<return_type>(sp1, p);
return_type crs_AB = geometry::detail::course<return_type>(sp1, sp2);
return_type crs_BA = crs_AB - geometry::math::pi<return_type>();
return_type crs_BD = geometry::detail::course<return_type>(sp2, p);
return_type d_crs1 = crs_AD - crs_AB;
return_type d_crs2 = crs_BD - crs_BA;
// d1, d2, d3 are in principle not needed, only the sign matters
return_type projection1 = cos( d_crs1 ) * d1 / d3;
return_type projection2 = cos( d_crs2 ) * d2 / d3;
if (projection1 > 0.0 && projection2 > 0.0)
{
return_type XTD
= radius() * math::abs( asin( sin( d1 / radius() ) * sin( d_crs1 ) ));
// Return shortest distance, projected point on segment sp1-sp2
return return_type(XTD);
}
else
{
// Return shortest distance, project either on point sp1 or sp2
return return_type( (std::min)( d1 , d2 ) );
}
================= reference implementation -- end =================
Motivation
----------
In what follows we develop a comparable version of the cross track
distance strategy, that meets the following goals:
* It is more efficient than the original cross track strategy (less
operations and less calls to mathematical functions).
* Distances using the comparable cross track strategy can not only
be compared with other distances using the same strategy, but also with
distances computed with the comparable version of the haversine strategy.
* It can serve as the basis for the computation of the cross track distance,
as it is more efficient to compute its comparable version and
transform that to the actual cross track distance, rather than
follow/use the reference implementation listed above.
Major idea
----------
The idea here is to use the comparable haversine strategy to compute
the distances d1, d2 and d3 in the above listing. Once we have done
that we need also to make sure that instead of returning XTD (as
computed above) that we return a distance CXTD that is compatible
with the comparable haversine distance. To achieve this CXTD must satisfy
the relation:
XTD = 2 * R * asin( sqrt(XTD) )
where R is the sphere's radius.
Below we perform the mathematical analysis that show how to compute CXTD.
Mathematical analysis
---------------------
Below we use the following trigonometric identities:
sin(2 * x) = 2 * sin(x) * cos(x)
cos(asin(x)) = sqrt(1 - x^2)
Observation:
The distance d1 needed when the projection of the point D is within the
segment must be the true distance. However, comparable::haversine<>
returns a comparable distance instead of the one needed.
To remedy this, we implicitly compute what is needed.
More precisely, we need to compute sin(true_d1):
sin(true_d1) = sin(2 * asin(sqrt(d1)))
= 2 * sin(asin(sqrt(d1)) * cos(asin(sqrt(d1)))
= 2 * sqrt(d1) * sqrt(1-(sqrt(d1))^2)
= 2 * sqrt(d1 - d1 * d1)
This relation is used below.
As we mentioned above the goal is to find CXTD (named "a" below for
brevity) such that ("b" below stands for "d1", and "c" for "d_crs1"):
2 * R * asin(sqrt(a)) == R * asin(2 * sqrt(b-b^2) * sin(c))
Analysis:
2 * R * asin(sqrt(a)) == R * asin(2 * sqrt(b-b^2) * sin(c))
<=> 2 * asin(sqrt(a)) == asin(sqrt(b-b^2) * sin(c))
<=> sin(2 * asin(sqrt(a))) == 2 * sqrt(b-b^2) * sin(c)
<=> 2 * sin(asin(sqrt(a))) * cos(asin(sqrt(a))) == 2 * sqrt(b-b^2) * sin(c)
<=> 2 * sqrt(a) * sqrt(1-a) == 2 * sqrt(b-b^2) * sin(c)
<=> sqrt(a) * sqrt(1-a) == sqrt(b-b^2) * sin(c)
<=> sqrt(a-a^2) == sqrt(b-b^2) * sin(c)
<=> a-a^2 == (b-b^2) * (sin(c))^2
Consider the quadratic equation: x^2-x+p^2 == 0,
where p = sqrt(b-b^2) * sin(c); its discriminant is:
d = 1 - 4 * p^2 = 1 - 4 * (b-b^2) * (sin(c))^2
The two solutions are:
a_1 = (1 - sqrt(d)) / 2
a_2 = (1 + sqrt(d)) / 2
Which one to choose?
"a" refers to the distance (on the unit sphere) of D from the
supporting great circle Circ(A,B) of the segment AB.
The two different values for "a" correspond to the lengths of the two
arcs delimited D and the points of intersection of Circ(A,B) and the
great circle perperdicular to Circ(A,B) passing through D.
Clearly, the value we want is the smallest among these two distances,
hence the root we must choose is the smallest root among the two.
So the answer is:
CXTD = ( 1 - sqrt(1 - 4 * (b-b^2) * (sin(c))^2) ) / 2
Therefore, in order to implement the comparable version of the cross
track strategy we need to:
(1) Use the comparable version of the haversine strategy instead of
the non-comparable one.
(2) Instead of return XTD when D projects inside the segment AB, we
need to return CXTD, given by the following formula:
CXTD = ( 1 - sqrt(1 - 4 * (d1-d1^2) * (sin(d_crs1))^2) ) / 2;
Complexity Analysis
-------------------
In the analysis that follows we refer to the actual implementation below.
In particular, instead of computing CXTD as above, we use the more
efficient (operation-wise) computation of CXTD shown here:
return_type sin_d_crs1 = sin(d_crs1);
return_type d1_x_sin = d1 * sin_d_crs1;
return_type d = d1_x_sin * (sin_d_crs1 - d1_x_sin);
return d / (0.5 + math::sqrt(0.25 - d));
Notice that instead of computing:
0.5 - 0.5 * sqrt(1 - 4 * d) = 0.5 - sqrt(0.25 - d)
we use the following formula instead:
d / (0.5 + sqrt(0.25 - d)).
This is done for numerical robustness. The expression 0.5 - sqrt(0.25 - x)
has large numerical errors for values of x close to 0 (if using doubles
the error start to become large even when d is as large as 0.001).
To remedy that, we re-write 0.5 - sqrt(0.25 - x) as:
0.5 - sqrt(0.25 - d)
= (0.5 - sqrt(0.25 - d) * (0.5 - sqrt(0.25 - d)) / (0.5 + sqrt(0.25 - d)).
The numerator is the difference of two squares:
(0.5 - sqrt(0.25 - d) * (0.5 - sqrt(0.25 - d))
= 0.5^2 - (sqrt(0.25 - d))^ = 0.25 - (0.25 - d) = d,
which gives the expression we use.
For the complexity analysis, we distinguish between two cases:
(A) The distance is realized between the point D and an
endpoint of the segment AB
Gains:
Since we are using comparable::haversine<> which is called
3 times, we gain:
-> 3 calls to sqrt
-> 3 calls to asin
-> 6 multiplications
Loses: None
So the net gain is:
-> 6 function calls (sqrt/asin)
-> 6 arithmetic operations
If we use comparable::cross_track<> to compute
cross_track<> we need to account for a call to sqrt, a call
to asin and 2 multiplications. In this case the net gain is:
-> 4 function calls (sqrt/asin)
-> 4 arithmetic operations
(B) The distance is realized between the point D and an
interior point of the segment AB
Gains:
Since we are using comparable::haversine<> which is called
3 times, we gain:
-> 3 calls to sqrt
-> 3 calls to asin
-> 6 multiplications
Also we gain the operations used to compute XTD:
-> 2 calls to sin
-> 1 call to asin
-> 1 call to abs
-> 2 multiplications
-> 1 division
So the total gains are:
-> 9 calls to sqrt/sin/asin
-> 1 call to abs
-> 8 multiplications
-> 1 division
Loses:
To compute a distance compatible with comparable::haversine<>
we need to perform a few more operations, namely:
-> 1 call to sin
-> 1 call to sqrt
-> 2 multiplications
-> 1 division
-> 1 addition
-> 2 subtractions
So roughly speaking the net gain is:
-> 8 fewer function calls and 3 fewer arithmetic operations
If we were to implement cross_track directly from the
comparable version (much like what haversine<> does using
comparable::haversine<>) we need additionally
-> 2 function calls (asin/sqrt)
-> 2 multiplications
So it pays off to re-implement cross_track<> to use
comparable::cross_track<>; in this case the net gain would be:
-> 6 function calls
-> 1 arithmetic operation
Summary/Conclusion
------------------
Following the mathematical and complexity analysis above, the
comparable cross track strategy (as implemented below) satisfies
all the goal mentioned in the beginning:
* It is more efficient than its non-comparable counter-part.
* Comparable distances using this new strategy can also be compared
with comparable distances computed with the comparable haversine
strategy.
* It turns out to be more efficient to compute the actual cross
track distance XTD by first computing CXTD, and then computing
XTD by means of the formula:
XTD = 2 * R * asin( sqrt(CXTD) )
*/
template
<
typename CalculationType = void,
typename Strategy = comparable::haversine<double, CalculationType>
>
class cross_track
{
public :
template <typename Point, typename PointOfSegment>
struct return_type
: promote_floating_point
<
typename select_calculation_type
<
Point,
PointOfSegment,
CalculationType
>::type
>
{};
typedef typename Strategy::radius_type radius_type;
inline cross_track()
{}
explicit inline cross_track(typename Strategy::radius_type const& r)
: m_strategy(r)
{}
inline cross_track(Strategy const& s)
: m_strategy(s)
{}
// It might be useful in the future
// to overload constructor with strategy info.
// crosstrack(...) {}
template <typename Point, typename PointOfSegment>
inline typename return_type<Point, PointOfSegment>::type
apply(Point const& p, PointOfSegment const& sp1, PointOfSegment const& sp2) const
{
#if !defined(BOOST_MSVC)
BOOST_CONCEPT_ASSERT
(
(concepts::PointDistanceStrategy<Strategy, Point, PointOfSegment>)
);
#endif
typedef typename return_type<Point, PointOfSegment>::type return_type;
#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK
std::cout << "Course " << dsv(sp1) << " to " << dsv(p) << " "
<< crs_AD * geometry::math::r2d<return_type>() << std::endl;
std::cout << "Course " << dsv(sp1) << " to " << dsv(sp2) << " "
<< crs_AB * geometry::math::r2d<return_type>() << std::endl;
std::cout << "Course " << dsv(sp2) << " to " << dsv(p) << " "
<< crs_BD * geometry::math::r2d << std::endl;
std::cout << "Projection AD-AB " << projection1 << " : "
<< d_crs1 * geometry::math::r2d<return_type>() << std::endl;
std::cout << "Projection BD-BA " << projection2 << " : "
<< d_crs2 * geometry::math::r2d<return_type>() << std::endl;
#endif
// http://williams.best.vwh.net/avform.htm#XTE
return_type d1 = m_strategy.apply(sp1, p);
return_type d3 = m_strategy.apply(sp1, sp2);
if (geometry::math::equals(d3, 0.0))
{
// "Degenerate" segment, return either d1 or d2
return d1;
}
return_type d2 = m_strategy.apply(sp2, p);
return_type crs_AD = geometry::detail::course<return_type>(sp1, p);
return_type crs_AB = geometry::detail::course<return_type>(sp1, sp2);
return_type crs_BA = crs_AB - geometry::math::pi<return_type>();
return_type crs_BD = geometry::detail::course<return_type>(sp2, p);
return_type d_crs1 = crs_AD - crs_AB;
return_type d_crs2 = crs_BD - crs_BA;
// d1, d2, d3 are in principle not needed, only the sign matters
return_type projection1 = cos( d_crs1 ) * d1 / d3;
return_type projection2 = cos( d_crs2 ) * d2 / d3;
if (projection1 > 0.0 && projection2 > 0.0)
{
#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK
return_type XTD = radius() * geometry::math::abs( asin( sin( d1 ) * sin( d_crs1 ) ));
std::cout << "Projection ON the segment" << std::endl;
std::cout << "XTD: " << XTD
<< " d1: " << (d1 * radius())
<< " d2: " << (d2 * radius())
<< std::endl;
#endif
return_type const half(0.5);
return_type const quarter(0.25);
return_type sin_d_crs1 = sin(d_crs1);
/*
This is the straightforward obvious way to continue:
return_type discriminant
= 1.0 - 4.0 * (d1 - d1 * d1) * sin_d_crs1 * sin_d_crs1;
return 0.5 - 0.5 * math::sqrt(discriminant);
Below we optimize the number of arithmetic operations
and account for numerical robustness:
*/
return_type d1_x_sin = d1 * sin_d_crs1;
return_type d = d1_x_sin * (sin_d_crs1 - d1_x_sin);
return d / (half + math::sqrt(quarter - d));
}
else
{
#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK
std::cout << "Projection OUTSIDE the segment" << std::endl;
#endif
// Return shortest distance, project either on point sp1 or sp2
return return_type( (std::min)( d1 , d2 ) );
}
}
inline typename Strategy::radius_type radius() const
{ return m_strategy.radius(); }
private :
Strategy m_strategy;
};
} // namespace comparable
/*!
\brief Strategy functor for distance point to segment calculation
\ingroup strategies
\details Class which calculates the distance of a point to a segment, for points on a sphere or globe
\see http://williams.best.vwh.net/avform.htm
\tparam CalculationType \tparam_calculation
\tparam Strategy underlying point-point distance strategy, defaults to haversine
\qbk{
[heading See also]
[link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)]
}
*/
template
<
typename CalculationType = void,
typename Strategy = haversine<double, CalculationType>
>
class cross_track
{
public :
template <typename Point, typename PointOfSegment>
struct return_type
: promote_floating_point
<
typename select_calculation_type
<
Point,
PointOfSegment,
CalculationType
>::type
>
{};
typedef typename Strategy::radius_type radius_type;
inline cross_track()
{}
explicit inline cross_track(typename Strategy::radius_type const& r)
: m_strategy(r)
{}
inline cross_track(Strategy const& s)
: m_strategy(s)
{}
// It might be useful in the future
// to overload constructor with strategy info.
// crosstrack(...) {}
template <typename Point, typename PointOfSegment>
inline typename return_type<Point, PointOfSegment>::type
apply(Point const& p, PointOfSegment const& sp1, PointOfSegment const& sp2) const
{
#if !defined(BOOST_MSVC)
BOOST_CONCEPT_ASSERT
(
(concepts::PointDistanceStrategy<Strategy, Point, PointOfSegment>)
);
#endif
typedef typename return_type<Point, PointOfSegment>::type return_type;
typedef cross_track<CalculationType, Strategy> this_type;
typedef typename services::comparable_type
<
this_type
>::type comparable_type;
comparable_type cstrategy
= services::get_comparable<this_type>::apply(m_strategy);
return_type const a = cstrategy.apply(p, sp1, sp2);
return_type const c = return_type(2.0) * asin(math::sqrt(a));
return c * radius();
}
inline typename Strategy::radius_type radius() const
{ return m_strategy.radius(); }
private :
Strategy m_strategy;
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename CalculationType, typename Strategy>
struct tag<cross_track<CalculationType, Strategy> >
{
typedef strategy_tag_distance_point_segment type;
};
template <typename CalculationType, typename Strategy, typename P, typename PS>
struct return_type<cross_track<CalculationType, Strategy>, P, PS>
: cross_track<CalculationType, Strategy>::template return_type<P, PS>
{};
template <typename CalculationType, typename Strategy>
struct comparable_type<cross_track<CalculationType, Strategy> >
{
typedef comparable::cross_track
<
CalculationType, typename comparable_type<Strategy>::type
> type;
};
template
<
typename CalculationType,
typename Strategy
>
struct get_comparable<cross_track<CalculationType, Strategy> >
{
typedef typename comparable_type
<
cross_track<CalculationType, Strategy>
>::type comparable_type;
public :
static inline comparable_type
apply(cross_track<CalculationType, Strategy> const& strategy)
{
return comparable_type(strategy.radius());
}
};
template
<
typename CalculationType,
typename Strategy,
typename P,
typename PS
>
struct result_from_distance<cross_track<CalculationType, Strategy>, P, PS>
{
private :
typedef typename cross_track
<
CalculationType, Strategy
>::template return_type<P, PS>::type return_type;
public :
template <typename T>
static inline return_type
apply(cross_track<CalculationType, Strategy> const& , T const& distance)
{
return distance;
}
};
// Specializations for comparable::cross_track
template <typename RadiusType, typename CalculationType>
struct tag<comparable::cross_track<RadiusType, CalculationType> >
{
typedef strategy_tag_distance_point_segment type;
};
template
<
typename RadiusType,
typename CalculationType,
typename P,
typename PS
>
struct return_type<comparable::cross_track<RadiusType, CalculationType>, P, PS>
: comparable::cross_track
<
RadiusType, CalculationType
>::template return_type<P, PS>
{};
template <typename RadiusType, typename CalculationType>
struct comparable_type<comparable::cross_track<RadiusType, CalculationType> >
{
typedef comparable::cross_track<RadiusType, CalculationType> type;
};
template <typename RadiusType, typename CalculationType>
struct get_comparable<comparable::cross_track<RadiusType, CalculationType> >
{
private :
typedef comparable::cross_track<RadiusType, CalculationType> this_type;
public :
static inline this_type apply(this_type const& input)
{
return input;
}
};
template
<
typename RadiusType,
typename CalculationType,
typename P,
typename PS
>
struct result_from_distance
<
comparable::cross_track<RadiusType, CalculationType>, P, PS
>
{
private :
typedef comparable::cross_track<RadiusType, CalculationType> strategy_type;
typedef typename return_type<strategy_type, P, PS>::type return_type;
public :
template <typename T>
static inline return_type apply(strategy_type const& strategy,
T const& distance)
{
return_type const s
= sin( (distance / strategy.radius()) / return_type(2.0) );
return s * s;
}
};
/*
TODO: spherical polar coordinate system requires "get_as_radian_equatorial<>"
template <typename Point, typename PointOfSegment, typename Strategy>
struct default_strategy
<
segment_tag, Point, PointOfSegment,
spherical_polar_tag, spherical_polar_tag,
Strategy
>
{
typedef cross_track
<
void,
typename boost::mpl::if_
<
boost::is_void<Strategy>,
typename default_strategy
<
point_tag, Point, PointOfSegment,
spherical_polar_tag, spherical_polar_tag
>::type,
Strategy
>::type
> type;
};
*/
template <typename Point, typename PointOfSegment, typename Strategy>
struct default_strategy
<
point_tag, segment_tag, Point, PointOfSegment,
spherical_equatorial_tag, spherical_equatorial_tag,
Strategy
>
{
typedef cross_track
<
void,
typename boost::mpl::if_
<
boost::is_void<Strategy>,
typename default_strategy
<
point_tag, point_tag, Point, PointOfSegment,
spherical_equatorial_tag, spherical_equatorial_tag
>::type,
Strategy
>::type
> type;
};
template <typename PointOfSegment, typename Point, typename Strategy>
struct default_strategy
<
segment_tag, point_tag, PointOfSegment, Point,
spherical_equatorial_tag, spherical_equatorial_tag,
Strategy
>
{
typedef typename default_strategy
<
point_tag, segment_tag, Point, PointOfSegment,
spherical_equatorial_tag, spherical_equatorial_tag,
Strategy
>::type type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::distance
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_HPP
@@ -0,0 +1,364 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2008-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2014, 2015.
// Modifications copyright (c) 2014-2015, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_POINT_BOX_HPP
#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_POINT_BOX_HPP
#include <boost/config.hpp>
#include <boost/concept_check.hpp>
#include <boost/mpl/if.hpp>
#include <boost/type_traits/is_void.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/concepts/distance_concept.hpp>
#include <boost/geometry/strategies/spherical/distance_cross_track.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace distance
{
/*!
\brief Strategy functor for distance point to box calculation
\ingroup strategies
\details Class which calculates the distance of a point to a box, for
points and boxes on a sphere or globe
\tparam CalculationType \tparam_calculation
\tparam Strategy underlying point-segment distance strategy, defaults
to cross track
\qbk{
[heading See also]
[link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)]
}
*/
template
<
typename CalculationType = void,
typename Strategy = cross_track<CalculationType>
>
class cross_track_point_box
{
public:
template <typename Point, typename Box>
struct return_type
: services::return_type<Strategy, Point, typename point_type<Box>::type>
{};
typedef typename Strategy::radius_type radius_type;
inline cross_track_point_box()
{}
explicit inline cross_track_point_box(typename Strategy::radius_type const& r)
: m_ps_strategy(r)
{}
inline cross_track_point_box(Strategy const& s)
: m_ps_strategy(s)
{}
// It might be useful in the future
// to overload constructor with strategy info.
// crosstrack(...) {}
template <typename Point, typename Box>
inline typename return_type<Point, Box>::type
apply(Point const& point, Box const& box) const
{
#if !defined(BOOST_MSVC)
BOOST_CONCEPT_ASSERT
(
(concepts::PointSegmentDistanceStrategy
<
Strategy, Point, typename point_type<Box>::type
>)
);
#endif
// this method assumes that the coordinates of the point and
// the box are normalized
typedef typename return_type<Point, Box>::type return_type;
typedef typename point_type<Box>::type box_point_type;
// TODO: This strategy as well as other cross-track strategies
// and therefore e.g. spherical within(Point, Box) may not work
// properly for a Box degenerated to a Segment or Point
box_point_type bottom_left, bottom_right, top_left, top_right;
geometry::detail::assign_box_corners(box,
bottom_left, bottom_right,
top_left, top_right);
return_type const plon = geometry::get_as_radian<0>(point);
return_type const plat = geometry::get_as_radian<1>(point);
return_type const lon_min = geometry::get_as_radian<0>(bottom_left);
return_type const lat_min = geometry::get_as_radian<1>(bottom_left);
return_type const lon_max = geometry::get_as_radian<0>(top_right);
return_type const lat_max = geometry::get_as_radian<1>(top_right);
return_type const pi = math::pi<return_type>();
return_type const two_pi = math::two_pi<return_type>();
// First check if the point is within the band defined by the
// minimum and maximum longitude of the box; if yes, determine
// if the point is above, below or inside the box and compute
// the distance (easy in this case)
//
// Notice that the point may not be inside the longitude range
// of the box, but the shifted point may be inside the
// longitude range of the box; in this case the point is still
// considered as inside the longitude range band of the box
if ((plon >= lon_min && plon <= lon_max) || plon + two_pi <= lon_max)
{
if (plat > lat_max)
{
return services::result_from_distance
<
Strategy, Point, box_point_type
>::apply(m_ps_strategy, radius() * (plat - lat_max));
}
else if (plat < lat_min)
{
return services::result_from_distance
<
Strategy, Point, box_point_type
>::apply(m_ps_strategy, radius() * (lat_min - plat));
}
else
{
BOOST_GEOMETRY_ASSERT(plat >= lat_min && plat <= lat_max);
return return_type(0);
}
}
// Otherwise determine which among the two medirian segments of the
// box the point is closest to, and compute the distance of
// the point to this closest segment
// Below lon_midway is the longitude of the meridian that:
// (1) is midway between the meridians of the left and right
// meridians of the box, and
// (2) does not intersect the box
return_type const two = 2.0;
bool use_left_segment;
if (lon_max > pi)
{
// the box crosses the antimeridian
// midway longitude = lon_min - (lon_min + (lon_max - 2 * pi)) / 2;
return_type const lon_midway = (lon_min - lon_max) / two + pi;
BOOST_GEOMETRY_ASSERT(lon_midway >= -pi && lon_midway <= pi);
use_left_segment = plon > lon_midway;
}
else
{
// the box does not cross the antimeridian
return_type const lon_sum = lon_min + lon_max;
if (math::equals(lon_sum, return_type(0)))
{
// special case: the box is symmetric with respect to
// the prime meridian; the midway meridian is the antimeridian
use_left_segment = plon < lon_min;
}
else
{
// midway long. = lon_min - (2 * pi - (lon_max - lon_min)) / 2;
return_type lon_midway = (lon_min + lon_max) / two - pi;
// normalize the midway longitude
if (lon_midway > pi)
{
lon_midway -= two_pi;
}
else if (lon_midway < -pi)
{
lon_midway += two_pi;
}
BOOST_GEOMETRY_ASSERT(lon_midway >= -pi && lon_midway <= pi);
// if lon_sum is positive the midway meridian is left
// of the box, or right of the box otherwise
use_left_segment = lon_sum > 0
? (plon < lon_min && plon >= lon_midway)
: (plon <= lon_max || plon > lon_midway);
}
}
return use_left_segment
? m_ps_strategy.apply(point, bottom_left, top_left)
: m_ps_strategy.apply(point, bottom_right, top_right);
}
inline typename Strategy::radius_type radius() const
{
return m_ps_strategy.radius();
}
private:
Strategy m_ps_strategy;
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename CalculationType, typename Strategy>
struct tag<cross_track_point_box<CalculationType, Strategy> >
{
typedef strategy_tag_distance_point_box type;
};
template <typename CalculationType, typename Strategy, typename P, typename Box>
struct return_type<cross_track_point_box<CalculationType, Strategy>, P, Box>
: cross_track_point_box
<
CalculationType, Strategy
>::template return_type<P, Box>
{};
template <typename CalculationType, typename Strategy>
struct comparable_type<cross_track_point_box<CalculationType, Strategy> >
{
typedef cross_track_point_box
<
CalculationType, typename comparable_type<Strategy>::type
> type;
};
template <typename CalculationType, typename Strategy>
struct get_comparable<cross_track_point_box<CalculationType, Strategy> >
{
typedef cross_track_point_box<CalculationType, Strategy> this_strategy;
typedef typename comparable_type<this_strategy>::type comparable_type;
public:
static inline comparable_type apply(this_strategy const& strategy)
{
return comparable_type(strategy.radius());
}
};
template <typename CalculationType, typename Strategy, typename P, typename Box>
struct result_from_distance
<
cross_track_point_box<CalculationType, Strategy>, P, Box
>
{
private:
typedef cross_track_point_box<CalculationType, Strategy> this_strategy;
typedef typename this_strategy::template return_type
<
P, Box
>::type return_type;
public:
template <typename T>
static inline return_type apply(this_strategy const& strategy,
T const& distance)
{
Strategy s(strategy.radius());
return result_from_distance
<
Strategy, P, typename point_type<Box>::type
>::apply(s, distance);
}
};
// define cross_track_point_box<default_point_segment_strategy> as
// default point-box strategy for the spherical equatorial coordinate system
template <typename Point, typename Box, typename Strategy>
struct default_strategy
<
point_tag, box_tag, Point, Box,
spherical_equatorial_tag, spherical_equatorial_tag,
Strategy
>
{
typedef cross_track_point_box
<
void,
typename boost::mpl::if_
<
boost::is_void<Strategy>,
typename default_strategy
<
point_tag, segment_tag,
Point, typename point_type<Box>::type,
spherical_equatorial_tag, spherical_equatorial_tag
>::type,
Strategy
>::type
> type;
};
template <typename Box, typename Point, typename Strategy>
struct default_strategy
<
box_tag, point_tag, Box, Point,
spherical_equatorial_tag, spherical_equatorial_tag,
Strategy
>
{
typedef typename default_strategy
<
point_tag, box_tag, Point, Box,
spherical_equatorial_tag, spherical_equatorial_tag,
Strategy
>::type type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::distance
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_POINT_BOX_HPP
@@ -0,0 +1,305 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_HAVERSINE_HPP
#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_HAVERSINE_HPP
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/strategies/distance.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace distance
{
namespace comparable
{
// Comparable haversine.
// To compare distances, we can avoid:
// - multiplication with radius and 2.0
// - applying sqrt
// - applying asin (which is strictly (monotone) increasing)
template
<
typename RadiusType,
typename CalculationType = void
>
class haversine
{
public :
template <typename Point1, typename Point2>
struct calculation_type
: promote_floating_point
<
typename select_calculation_type
<
Point1,
Point2,
CalculationType
>::type
>
{};
typedef RadiusType radius_type;
explicit inline haversine(RadiusType const& r = 1.0)
: m_radius(r)
{}
template <typename Point1, typename Point2>
static inline typename calculation_type<Point1, Point2>::type
apply(Point1 const& p1, Point2 const& p2)
{
return calculate<typename calculation_type<Point1, Point2>::type>(
get_as_radian<0>(p1), get_as_radian<1>(p1),
get_as_radian<0>(p2), get_as_radian<1>(p2)
);
}
inline RadiusType radius() const
{
return m_radius;
}
private :
template <typename R, typename T1, typename T2>
static inline R calculate(T1 const& lon1, T1 const& lat1,
T2 const& lon2, T2 const& lat2)
{
return math::hav(lat2 - lat1)
+ cos(lat1) * cos(lat2) * math::hav(lon2 - lon1);
}
RadiusType m_radius;
};
} // namespace comparable
/*!
\brief Distance calculation for spherical coordinates
on a perfect sphere using haversine
\ingroup strategies
\tparam RadiusType \tparam_radius
\tparam CalculationType \tparam_calculation
\author Adapted from: http://williams.best.vwh.net/avform.htm
\see http://en.wikipedia.org/wiki/Great-circle_distance
\note (from Wiki:) The great circle distance d between two
points with coordinates {lat1,lon1} and {lat2,lon2} is given by:
d=acos(sin(lat1)*sin(lat2)+cos(lat1)*cos(lat2)*cos(lon1-lon2))
A mathematically equivalent formula, which is less subject
to rounding error for short distances is:
d=2*asin(sqrt((sin((lat1-lat2) / 2))^2
+ cos(lat1)*cos(lat2)*(sin((lon1-lon2) / 2))^2))
\qbk{
[heading See also]
[link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)]
}
*/
template
<
typename RadiusType,
typename CalculationType = void
>
class haversine
{
typedef comparable::haversine<RadiusType, CalculationType> comparable_type;
public :
template <typename Point1, typename Point2>
struct calculation_type
: services::return_type<comparable_type, Point1, Point2>
{};
typedef RadiusType radius_type;
/*!
\brief Constructor
\param radius radius of the sphere, defaults to 1.0 for the unit sphere
*/
inline haversine(RadiusType const& radius = 1.0)
: m_radius(radius)
{}
/*!
\brief applies the distance calculation
\return the calculated distance (including multiplying with radius)
\param p1 first point
\param p2 second point
*/
template <typename Point1, typename Point2>
inline typename calculation_type<Point1, Point2>::type
apply(Point1 const& p1, Point2 const& p2) const
{
typedef typename calculation_type<Point1, Point2>::type calculation_type;
calculation_type const a = comparable_type::apply(p1, p2);
calculation_type const c = calculation_type(2.0) * asin(math::sqrt(a));
return calculation_type(m_radius) * c;
}
/*!
\brief access to radius value
\return the radius
*/
inline RadiusType radius() const
{
return m_radius;
}
private :
RadiusType m_radius;
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename RadiusType, typename CalculationType>
struct tag<haversine<RadiusType, CalculationType> >
{
typedef strategy_tag_distance_point_point type;
};
template <typename RadiusType, typename CalculationType, typename P1, typename P2>
struct return_type<haversine<RadiusType, CalculationType>, P1, P2>
: haversine<RadiusType, CalculationType>::template calculation_type<P1, P2>
{};
template <typename RadiusType, typename CalculationType>
struct comparable_type<haversine<RadiusType, CalculationType> >
{
typedef comparable::haversine<RadiusType, CalculationType> type;
};
template <typename RadiusType, typename CalculationType>
struct get_comparable<haversine<RadiusType, CalculationType> >
{
private :
typedef haversine<RadiusType, CalculationType> this_type;
typedef comparable::haversine<RadiusType, CalculationType> comparable_type;
public :
static inline comparable_type apply(this_type const& input)
{
return comparable_type(input.radius());
}
};
template <typename RadiusType, typename CalculationType, typename P1, typename P2>
struct result_from_distance<haversine<RadiusType, CalculationType>, P1, P2>
{
private :
typedef haversine<RadiusType, CalculationType> this_type;
typedef typename return_type<this_type, P1, P2>::type return_type;
public :
template <typename T>
static inline return_type apply(this_type const& , T const& value)
{
return return_type(value);
}
};
// Specializations for comparable::haversine
template <typename RadiusType, typename CalculationType>
struct tag<comparable::haversine<RadiusType, CalculationType> >
{
typedef strategy_tag_distance_point_point type;
};
template <typename RadiusType, typename CalculationType, typename P1, typename P2>
struct return_type<comparable::haversine<RadiusType, CalculationType>, P1, P2>
: comparable::haversine<RadiusType, CalculationType>::template calculation_type<P1, P2>
{};
template <typename RadiusType, typename CalculationType>
struct comparable_type<comparable::haversine<RadiusType, CalculationType> >
{
typedef comparable::haversine<RadiusType, CalculationType> type;
};
template <typename RadiusType, typename CalculationType>
struct get_comparable<comparable::haversine<RadiusType, CalculationType> >
{
private :
typedef comparable::haversine<RadiusType, CalculationType> this_type;
public :
static inline this_type apply(this_type const& input)
{
return input;
}
};
template <typename RadiusType, typename CalculationType, typename P1, typename P2>
struct result_from_distance<comparable::haversine<RadiusType, CalculationType>, P1, P2>
{
private :
typedef comparable::haversine<RadiusType, CalculationType> strategy_type;
typedef typename return_type<strategy_type, P1, P2>::type return_type;
public :
template <typename T>
static inline return_type apply(strategy_type const& strategy, T const& distance)
{
return_type const s = sin((distance / strategy.radius()) / return_type(2));
return s * s;
}
};
// Register it as the default for point-types
// in a spherical equatorial coordinate system
template <typename Point1, typename Point2>
struct default_strategy
<
point_tag, point_tag, Point1, Point2,
spherical_equatorial_tag, spherical_equatorial_tag
>
{
typedef strategy::distance::haversine<typename select_coordinate_type<Point1, Point2>::type> type;
};
// Note: spherical polar coordinate system requires "get_as_radian_equatorial"
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::distance
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_HAVERSINE_HPP
@@ -0,0 +1,86 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2017 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fisikopoulos, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_ENVELOPE_SEGMENT_HPP
#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_ENVELOPE_SEGMENT_HPP
#include <boost/geometry/algorithms/detail/envelope/segment.hpp>
#include <boost/geometry/algorithms/detail/normalize.hpp>
#include <boost/geometry/strategies/envelope.hpp>
#include <boost/geometry/strategies/spherical/azimuth.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace envelope
{
template
<
typename CalculationType = void
>
class spherical_segment
{
public :
inline spherical_segment()
{}
template <typename Point1, typename Point2, typename Box>
inline void
apply(Point1 const& point1, Point2 const& point2, Box& box) const
{
Point1 p1_normalized = detail::return_normalized<Point1>(point1);
Point2 p2_normalized = detail::return_normalized<Point2>(point2);
geometry::strategy::azimuth::spherical<CalculationType> azimuth_spherical;
typedef typename coordinate_system<Point1>::type::units units_type;
geometry::detail::envelope::envelope_segment_impl<spherical_equatorial_tag>
::template apply<units_type>(geometry::get<0>(p1_normalized),
geometry::get<1>(p1_normalized),
geometry::get<0>(p2_normalized),
geometry::get<1>(p2_normalized),
box,
azimuth_spherical);
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename CalculationType>
struct default_strategy<spherical_equatorial_tag, CalculationType>
{
typedef strategy::envelope::spherical_segment<CalculationType> type;
};
template <typename CalculationType>
struct default_strategy<spherical_polar_tag, CalculationType>
{
typedef strategy::envelope::spherical_segment<CalculationType> type;
};
}
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::envelope
}} //namepsace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_ENVELOPE_SEGMENT_HPP
@@ -0,0 +1,980 @@
// Boost.Geometry
// Copyright (c) 2016-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_INTERSECTION_HPP
#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_INTERSECTION_HPP
#include <algorithm>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/detail/assign_values.hpp>
#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/arithmetic/cross_product.hpp>
#include <boost/geometry/arithmetic/dot_product.hpp>
#include <boost/geometry/arithmetic/normalize.hpp>
#include <boost/geometry/formulas/spherical.hpp>
#include <boost/geometry/geometries/concepts/point_concept.hpp>
#include <boost/geometry/geometries/concepts/segment_concept.hpp>
#include <boost/geometry/policies/robustness/segment_ratio.hpp>
#include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp>
#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/intersection.hpp>
#include <boost/geometry/strategies/intersection_result.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/strategies/side_info.hpp>
#include <boost/geometry/strategies/spherical/area.hpp>
#include <boost/geometry/strategies/spherical/distance_haversine.hpp>
#include <boost/geometry/strategies/spherical/ssf.hpp>
#include <boost/geometry/strategies/within.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace intersection
{
// NOTE:
// The coordinates of crossing IP may be calculated with small precision in some cases.
// For double, near the equator noticed error ~1e-9 so far greater than
// machine epsilon which is ~1e-16. This error is ~0.04m.
// E.g. consider two cases, one near the origin and the second one rotated by 90 deg around Z or SN axis.
// After the conversion from spherical degrees to cartesian 3d the following coordinates
// are calculated:
// for sph (-1 -1, 1 1) deg cart3d ys are -0.017449748351250485 and 0.017449748351250485
// for sph (89 -1, 91 1) deg cart3d xs are 0.017449748351250571 and -0.017449748351250450
// During the conversion degrees must first be converted to radians and then radians
// are passed into trigonometric functions. The error may have several causes:
// 1. Radians cannot represent exactly the same angles as degrees.
// 2. Different longitudes are passed into sin() for x, corresponding to cos() for y,
// and for different angle the error of the result may be different.
// 3. These non-corresponding cartesian coordinates are used in calculation,
// e.g. multiplied several times in cross and dot products.
// If it was a problem this strategy could e.g. "normalize" longitudes before the conversion using the source units
// by rotating the globe around Z axis, so moving longitudes always the same way towards the origin,
// assuming this could help which is not clear.
// For now, intersection points near the endpoints are checked explicitly if needed (if the IP is near the endpoint)
// to generate precise result for them. Only the crossing (i) case may suffer from lower precision.
template
<
typename CalcPolicy,
typename CalculationType = void
>
struct ecef_segments
{
typedef side::spherical_side_formula<CalculationType> side_strategy_type;
static inline side_strategy_type get_side_strategy()
{
return side_strategy_type();
}
template <typename Geometry1, typename Geometry2>
struct point_in_geometry_strategy
{
typedef strategy::within::winding
<
typename point_type<Geometry1>::type,
typename point_type<Geometry2>::type,
side_strategy_type,
CalculationType
> type;
};
template <typename Geometry1, typename Geometry2>
static inline typename point_in_geometry_strategy<Geometry1, Geometry2>::type
get_point_in_geometry_strategy()
{
typedef typename point_in_geometry_strategy
<
Geometry1, Geometry2
>::type strategy_type;
return strategy_type();
}
template <typename Geometry>
struct area_strategy
{
typedef area::spherical
<
typename point_type<Geometry>::type,
CalculationType
> type;
};
template <typename Geometry>
static inline typename area_strategy<Geometry>::type get_area_strategy()
{
typedef typename area_strategy<Geometry>::type strategy_type;
return strategy_type();
}
template <typename Geometry>
struct distance_strategy
{
typedef distance::haversine
<
typename coordinate_type<Geometry>::type,
CalculationType
> type;
};
template <typename Geometry>
static inline typename distance_strategy<Geometry>::type get_distance_strategy()
{
typedef typename distance_strategy<Geometry>::type strategy_type;
return strategy_type();
}
enum intersection_point_flag { ipi_inters = 0, ipi_at_a1, ipi_at_a2, ipi_at_b1, ipi_at_b2 };
// segment_intersection_info cannot outlive relate_ecef_segments
template <typename CoordinateType, typename SegmentRatio, typename Vector3d>
struct segment_intersection_info
{
typedef typename select_most_precise
<
CoordinateType, double
>::type promoted_type;
segment_intersection_info(CalcPolicy const& calc)
: calc_policy(calc)
{}
promoted_type comparable_length_a() const
{
return robust_ra.denominator();
}
promoted_type comparable_length_b() const
{
return robust_rb.denominator();
}
template <typename Point, typename Segment1, typename Segment2>
void assign_a(Point& point, Segment1 const& a, Segment2 const& b) const
{
assign(point, a, b);
}
template <typename Point, typename Segment1, typename Segment2>
void assign_b(Point& point, Segment1 const& a, Segment2 const& b) const
{
assign(point, a, b);
}
template <typename Point, typename Segment1, typename Segment2>
void assign(Point& point, Segment1 const& a, Segment2 const& b) const
{
if (ip_flag == ipi_inters)
{
// TODO: assign the rest of coordinates
point = calc_policy.template from_cart3d<Point>(intersection_point);
}
else if (ip_flag == ipi_at_a1)
{
detail::assign_point_from_index<0>(a, point);
}
else if (ip_flag == ipi_at_a2)
{
detail::assign_point_from_index<1>(a, point);
}
else if (ip_flag == ipi_at_b1)
{
detail::assign_point_from_index<0>(b, point);
}
else // ip_flag == ipi_at_b2
{
detail::assign_point_from_index<1>(b, point);
}
}
Vector3d intersection_point;
SegmentRatio robust_ra;
SegmentRatio robust_rb;
intersection_point_flag ip_flag;
CalcPolicy const& calc_policy;
};
// Relate segments a and b
template
<
typename Segment1,
typename Segment2,
typename Policy,
typename RobustPolicy
>
static inline typename Policy::return_type
apply(Segment1 const& a, Segment2 const& b,
Policy const& policy, RobustPolicy const& robust_policy)
{
typedef typename point_type<Segment1>::type point1_t;
typedef typename point_type<Segment2>::type point2_t;
point1_t a1, a2;
point2_t b1, b2;
// TODO: use indexed_point_view if possible?
detail::assign_point_from_index<0>(a, a1);
detail::assign_point_from_index<1>(a, a2);
detail::assign_point_from_index<0>(b, b1);
detail::assign_point_from_index<1>(b, b2);
return apply(a, b, policy, robust_policy, a1, a2, b1, b2);
}
// Relate segments a and b
template
<
typename Segment1,
typename Segment2,
typename Policy,
typename RobustPolicy,
typename Point1,
typename Point2
>
static inline typename Policy::return_type
apply(Segment1 const& a, Segment2 const& b,
Policy const&, RobustPolicy const&,
Point1 const& a1, Point1 const& a2, Point2 const& b1, Point2 const& b2)
{
// For now create it using default constructor. In the future it could
// be stored in strategy. However then apply() wouldn't be static and
// all relops and setops would have to take the strategy or model.
// Initialize explicitly to prevent compiler errors in case of PoD type
CalcPolicy const calc_policy = CalcPolicy();
BOOST_CONCEPT_ASSERT( (concepts::ConstSegment<Segment1>) );
BOOST_CONCEPT_ASSERT( (concepts::ConstSegment<Segment2>) );
// TODO: check only 2 first coordinates here?
using geometry::detail::equals::equals_point_point;
bool a_is_point = equals_point_point(a1, a2);
bool b_is_point = equals_point_point(b1, b2);
if(a_is_point && b_is_point)
{
return equals_point_point(a1, b2)
? Policy::degenerate(a, true)
: Policy::disjoint()
;
}
typedef typename select_calculation_type
<Segment1, Segment2, CalculationType>::type calc_t;
calc_t const c0 = 0;
calc_t const c1 = 1;
typedef model::point<calc_t, 3, cs::cartesian> vec3d_t;
vec3d_t const a1v = calc_policy.template to_cart3d<vec3d_t>(a1);
vec3d_t const a2v = calc_policy.template to_cart3d<vec3d_t>(a2);
vec3d_t const b1v = calc_policy.template to_cart3d<vec3d_t>(b1);
vec3d_t const b2v = calc_policy.template to_cart3d<vec3d_t>(b2);
side_info sides;
typename CalcPolicy::template plane<vec3d_t>
plane2 = calc_policy.get_plane(b1v, b2v);
// not normalized normals, the same as in side strategy
sides.set<0>(plane2.side_value(a1v), plane2.side_value(a2v));
if (sides.same<0>())
{
// Both points are at same side of other segment, we can leave
return Policy::disjoint();
}
typename CalcPolicy::template plane<vec3d_t>
plane1 = calc_policy.get_plane(a1v, a2v);
// not normalized normals, the same as in side strategy
sides.set<1>(plane1.side_value(b1v), plane1.side_value(b2v));
if (sides.same<1>())
{
// Both points are at same side of other segment, we can leave
return Policy::disjoint();
}
// NOTE: at this point the segments may still be disjoint
calc_t len1, len2;
// point or opposite sides of a sphere/spheroid, assume point
if (! detail::vec_normalize(plane1.normal, len1))
{
a_is_point = true;
if (sides.get<0, 0>() == 0 || sides.get<0, 1>() == 0)
{
sides.set<0>(0, 0);
}
}
if (! detail::vec_normalize(plane2.normal, len2))
{
b_is_point = true;
if (sides.get<1, 0>() == 0 || sides.get<1, 1>() == 0)
{
sides.set<1>(0, 0);
}
}
// check both degenerated once more
if (a_is_point && b_is_point)
{
return equals_point_point(a1, b2)
? Policy::degenerate(a, true)
: Policy::disjoint()
;
}
// NOTE: at this point the segments may still be disjoint
// NOTE: at this point one of the segments may be degenerated
bool collinear = sides.collinear();
if (! collinear)
{
// NOTE: for some approximations it's possible that both points may lie
// on the same geodesic but still some of the sides may be != 0.
// This is e.g. true for long segments represented as elliptic arcs
// with origin different than the center of the coordinate system.
// So make the sides consistent
// WARNING: the side strategy doesn't have the info about the other
// segment so it may return results inconsistent with this intersection
// strategy, as it checks both segments for consistency
if (sides.get<0, 0>() == 0 && sides.get<0, 1>() == 0)
{
collinear = true;
sides.set<1>(0, 0);
}
else if (sides.get<1, 0>() == 0 && sides.get<1, 1>() == 0)
{
collinear = true;
sides.set<0>(0, 0);
}
}
calc_t dot_n1n2 = dot_product(plane1.normal, plane2.normal);
// NOTE: this is technically not needed since theoretically above sides
// are calculated, but just in case check the normals.
// Have in mind that SSF side strategy doesn't check this.
// collinear if normals are equal or opposite: cos(a) in {-1, 1}
if (! collinear && math::equals(math::abs(dot_n1n2), c1))
{
collinear = true;
sides.set<0>(0, 0);
sides.set<1>(0, 0);
}
if (collinear)
{
if (a_is_point)
{
return collinear_one_degenerated<Policy, calc_t>(a, true, b1, b2, a1, a2, b1v, b2v, plane2, a1v);
}
else if (b_is_point)
{
// b2 used to be consistent with (degenerated) checks above (is it needed?)
return collinear_one_degenerated<Policy, calc_t>(b, false, a1, a2, b1, b2, a1v, a2v, plane1, b1v);
}
else
{
calc_t dist_a1_a2, dist_a1_b1, dist_a1_b2;
calc_t dist_b1_b2, dist_b1_a1, dist_b1_a2;
// use shorter segment
if (len1 <= len2)
{
calculate_collinear_data(a1, a2, b1, b2, a1v, a2v, plane1, b1v, dist_a1_a2, dist_a1_b1);
calculate_collinear_data(a1, a2, b1, b2, a1v, a2v, plane1, b2v, dist_a1_a2, dist_a1_b2);
dist_b1_b2 = dist_a1_b2 - dist_a1_b1;
dist_b1_a1 = -dist_a1_b1;
dist_b1_a2 = dist_a1_a2 - dist_a1_b1;
}
else
{
calculate_collinear_data(b1, b2, a1, a2, b1v, b2v, plane2, a1v, dist_b1_b2, dist_b1_a1);
calculate_collinear_data(b1, b2, a1, a2, b1v, b2v, plane2, a2v, dist_b1_b2, dist_b1_a2);
dist_a1_a2 = dist_b1_a2 - dist_b1_a1;
dist_a1_b1 = -dist_b1_a1;
dist_a1_b2 = dist_b1_b2 - dist_b1_a1;
}
segment_ratio<calc_t> ra_from(dist_b1_a1, dist_b1_b2);
segment_ratio<calc_t> ra_to(dist_b1_a2, dist_b1_b2);
segment_ratio<calc_t> rb_from(dist_a1_b1, dist_a1_a2);
segment_ratio<calc_t> rb_to(dist_a1_b2, dist_a1_a2);
// NOTE: this is probably not needed
int const a1_wrt_b = position_value(c0, dist_a1_b1, dist_a1_b2);
int const a2_wrt_b = position_value(dist_a1_a2, dist_a1_b1, dist_a1_b2);
int const b1_wrt_a = position_value(c0, dist_b1_a1, dist_b1_a2);
int const b2_wrt_a = position_value(dist_b1_b2, dist_b1_a1, dist_b1_a2);
if (a1_wrt_b == 1)
{
ra_from.assign(0, dist_b1_b2);
rb_from.assign(0, dist_a1_a2);
}
else if (a1_wrt_b == 3)
{
ra_from.assign(dist_b1_b2, dist_b1_b2);
rb_to.assign(0, dist_a1_a2);
}
if (a2_wrt_b == 1)
{
ra_to.assign(0, dist_b1_b2);
rb_from.assign(dist_a1_a2, dist_a1_a2);
}
else if (a2_wrt_b == 3)
{
ra_to.assign(dist_b1_b2, dist_b1_b2);
rb_to.assign(dist_a1_a2, dist_a1_a2);
}
if ((a1_wrt_b < 1 && a2_wrt_b < 1) || (a1_wrt_b > 3 && a2_wrt_b > 3))
{
return Policy::disjoint();
}
bool const opposite = dot_n1n2 < c0;
return Policy::segments_collinear(a, b, opposite,
a1_wrt_b, a2_wrt_b, b1_wrt_a, b2_wrt_a,
ra_from, ra_to, rb_from, rb_to);
}
}
else // crossing
{
if (a_is_point || b_is_point)
{
return Policy::disjoint();
}
vec3d_t i1;
intersection_point_flag ip_flag;
calc_t dist_a1_a2, dist_a1_i1, dist_b1_b2, dist_b1_i1;
if (calculate_ip_data(a1, a2, b1, b2, a1v, a2v, b1v, b2v,
plane1, plane2, calc_policy, sides,
i1, dist_a1_a2, dist_a1_i1, dist_b1_b2, dist_b1_i1, ip_flag))
{
// intersects
segment_intersection_info
<
calc_t,
segment_ratio<calc_t>,
vec3d_t
> sinfo(calc_policy);
sinfo.robust_ra.assign(dist_a1_i1, dist_a1_a2);
sinfo.robust_rb.assign(dist_b1_i1, dist_b1_b2);
sinfo.intersection_point = i1;
sinfo.ip_flag = ip_flag;
return Policy::segments_crosses(sides, sinfo, a, b);
}
else
{
return Policy::disjoint();
}
}
}
private:
template <typename Policy, typename CalcT, typename Segment, typename Point1, typename Point2, typename Vec3d, typename Plane>
static inline typename Policy::return_type
collinear_one_degenerated(Segment const& segment, bool degenerated_a,
Point1 const& a1, Point1 const& a2,
Point2 const& b1, Point2 const& b2,
Vec3d const& v1, Vec3d const& v2,
Plane const& plane,
Vec3d const& vother)
{
CalcT dist_1_2, dist_1_o;
return ! calculate_collinear_data(a1, a2, b1, b2, v1, v2, plane, vother, dist_1_2, dist_1_o)
? Policy::disjoint()
: Policy::one_degenerate(segment, segment_ratio<CalcT>(dist_1_o, dist_1_2), degenerated_a);
}
template <typename Point1, typename Point2, typename Vec3d, typename Plane, typename CalcT>
static inline bool calculate_collinear_data(Point1 const& a1, Point1 const& a2, // in
Point2 const& b1, Point2 const& b2, // in
Vec3d const& a1v, // in
Vec3d const& a2v, // in
Plane const& plane1, // in
Vec3d const& b1v_or_b2v, // in
CalcT& dist_a1_a2, CalcT& dist_a1_i1) // out
{
// calculate dist_a1_a2 and dist_a1_i1
calculate_dists(a1v, a2v, plane1, b1v_or_b2v, dist_a1_a2, dist_a1_i1);
// if i1 is close to a1 and b1 or b2 is equal to a1
if (is_endpoint_equal(dist_a1_i1, a1, b1, b2))
{
dist_a1_i1 = 0;
return true;
}
// or i1 is close to a2 and b1 or b2 is equal to a2
else if (is_endpoint_equal(dist_a1_a2 - dist_a1_i1, a2, b1, b2))
{
dist_a1_i1 = dist_a1_a2;
return true;
}
// or i1 is on b
return segment_ratio<CalcT>(dist_a1_i1, dist_a1_a2).on_segment();
}
template <typename Point1, typename Point2, typename Vec3d, typename Plane, typename CalcT>
static inline bool calculate_ip_data(Point1 const& a1, Point1 const& a2, // in
Point2 const& b1, Point2 const& b2, // in
Vec3d const& a1v, Vec3d const& a2v, // in
Vec3d const& b1v, Vec3d const& b2v, // in
Plane const& plane1, // in
Plane const& plane2, // in
CalcPolicy const& calc_policy, // in
side_info const& sides, // in
Vec3d & ip, // out
CalcT& dist_a1_a2, CalcT& dist_a1_ip, // out
CalcT& dist_b1_b2, CalcT& dist_b1_ip, // out
intersection_point_flag& ip_flag) // out
{
Vec3d ip1, ip2;
calc_policy.intersection_points(plane1, plane2, ip1, ip2);
calculate_dists(a1v, a2v, plane1, ip1, dist_a1_a2, dist_a1_ip);
ip = ip1;
// choose the opposite side of the globe if the distance is shorter
{
CalcT const d = abs_distance(dist_a1_a2, dist_a1_ip);
if (d > CalcT(0))
{
// TODO: this should be ok not only for sphere
// but requires more investigation
CalcT const dist_a1_i2 = dist_of_i2(dist_a1_ip);
CalcT const d2 = abs_distance(dist_a1_a2, dist_a1_i2);
if (d2 < d)
{
dist_a1_ip = dist_a1_i2;
ip = ip2;
}
}
}
bool is_on_a = false, is_near_a1 = false, is_near_a2 = false;
if (! is_potentially_crossing(dist_a1_a2, dist_a1_ip, is_on_a, is_near_a1, is_near_a2))
{
return false;
}
calculate_dists(b1v, b2v, plane2, ip, dist_b1_b2, dist_b1_ip);
bool is_on_b = false, is_near_b1 = false, is_near_b2 = false;
if (! is_potentially_crossing(dist_b1_b2, dist_b1_ip, is_on_b, is_near_b1, is_near_b2))
{
return false;
}
// reassign the IP if some endpoints overlap
using geometry::detail::equals::equals_point_point;
if (is_near_a1)
{
if (is_near_b1 && equals_point_point(a1, b1))
{
dist_a1_ip = 0;
dist_b1_ip = 0;
//i1 = a1v;
ip_flag = ipi_at_a1;
return true;
}
if (is_near_b2 && equals_point_point(a1, b2))
{
dist_a1_ip = 0;
dist_b1_ip = dist_b1_b2;
//i1 = a1v;
ip_flag = ipi_at_a1;
return true;
}
}
if (is_near_a2)
{
if (is_near_b1 && equals_point_point(a2, b1))
{
dist_a1_ip = dist_a1_a2;
dist_b1_ip = 0;
//i1 = a2v;
ip_flag = ipi_at_a2;
return true;
}
if (is_near_b2 && equals_point_point(a2, b2))
{
dist_a1_ip = dist_a1_a2;
dist_b1_ip = dist_b1_b2;
//i1 = a2v;
ip_flag = ipi_at_a2;
return true;
}
}
// at this point we know that the endpoints doesn't overlap
// reassign IP and distance if the IP is on a segment and one of
// the endpoints of the other segment lies on the former segment
if (is_on_a)
{
if (is_near_b1 && sides.template get<1, 0>() == 0) // b1 wrt a
{
dist_b1_ip = 0;
//i1 = b1v;
ip_flag = ipi_at_b1;
return true;
}
if (is_near_b2 && sides.template get<1, 1>() == 0) // b2 wrt a
{
dist_b1_ip = dist_b1_b2;
//i1 = b2v;
ip_flag = ipi_at_b2;
return true;
}
}
if (is_on_b)
{
if (is_near_a1 && sides.template get<0, 0>() == 0) // a1 wrt b
{
dist_a1_ip = 0;
//i1 = a1v;
ip_flag = ipi_at_a1;
return true;
}
if (is_near_a2 && sides.template get<0, 1>() == 0) // a2 wrt b
{
dist_a1_ip = dist_a1_a2;
//i1 = a2v;
ip_flag = ipi_at_a2;
return true;
}
}
ip_flag = ipi_inters;
return is_on_a && is_on_b;
}
template <typename Vec3d, typename Plane, typename CalcT>
static inline void calculate_dists(Vec3d const& a1v, // in
Vec3d const& a2v, // in
Plane const& plane1, // in
Vec3d const& i1, // in
CalcT& dist_a1_a2, // out
CalcT& dist_a1_i1) // out
{
//CalcT const c0 = 0;
CalcT const c1 = 1;
CalcT const c2 = 2;
CalcT const c4 = 4;
CalcT cos_a1_a2 = plane1.cos_angle_between(a1v, a2v);
dist_a1_a2 = -cos_a1_a2 + c1; // [1, -1] -> [0, 2] representing [0, pi]
bool is_forward = true;
CalcT cos_a1_i1 = plane1.cos_angle_between(a1v, i1, is_forward);
dist_a1_i1 = -cos_a1_i1 + c1; // [0, 2] representing [0, pi]
if (! is_forward) // left or right of a1 on a
{
dist_a1_i1 = -dist_a1_i1; // [0, 2] -> [0, -2] representing [0, -pi]
}
if (dist_a1_i1 <= -c2) // <= -pi
{
dist_a1_i1 += c4; // += 2pi
}
}
// the dist of the ip on the other side of the sphere
template <typename CalcT>
static inline CalcT dist_of_i2(CalcT const& dist_a1_i1)
{
CalcT const c2 = 2;
CalcT const c4 = 4;
CalcT dist_a1_i2 = dist_a1_i1 - c2; // dist_a1_i2 = dist_a1_i1 - pi;
if (dist_a1_i2 <= -c2) // <= -pi
{
dist_a1_i2 += c4; // += 2pi;
}
return dist_a1_i2;
}
template <typename CalcT>
static inline CalcT abs_distance(CalcT const& dist_a1_a2, CalcT const& dist_a1_i1)
{
if (dist_a1_i1 < CalcT(0))
return -dist_a1_i1;
else if (dist_a1_i1 > dist_a1_a2)
return dist_a1_i1 - dist_a1_a2;
else
return CalcT(0);
}
template <typename CalcT>
static inline bool is_potentially_crossing(CalcT const& dist_a1_a2, CalcT const& dist_a1_i1, // in
bool& is_on_a, bool& is_near_a1, bool& is_near_a2) // out
{
is_on_a = segment_ratio<CalcT>(dist_a1_i1, dist_a1_a2).on_segment();
is_near_a1 = is_near(dist_a1_i1);
is_near_a2 = is_near(dist_a1_a2 - dist_a1_i1);
return is_on_a || is_near_a1 || is_near_a2;
}
template <typename CalcT, typename P1, typename P2>
static inline bool is_endpoint_equal(CalcT const& dist,
P1 const& ai, P2 const& b1, P2 const& b2)
{
using geometry::detail::equals::equals_point_point;
return is_near(dist) && (equals_point_point(ai, b1) || equals_point_point(ai, b2));
}
template <typename CalcT>
static inline bool is_near(CalcT const& dist)
{
CalcT const small_number = CalcT(boost::is_same<CalcT, float>::value ? 0.0001 : 0.00000001);
return math::abs(dist) <= small_number;
}
template <typename ProjCoord1, typename ProjCoord2>
static inline int position_value(ProjCoord1 const& ca1,
ProjCoord2 const& cb1,
ProjCoord2 const& cb2)
{
// S1x 0 1 2 3 4
// S2 |---------->
return math::equals(ca1, cb1) ? 1
: math::equals(ca1, cb2) ? 3
: cb1 < cb2 ?
( ca1 < cb1 ? 0
: ca1 > cb2 ? 4
: 2 )
: ( ca1 > cb1 ? 0
: ca1 < cb2 ? 4
: 2 );
}
};
struct spherical_segments_calc_policy
{
template <typename Point, typename Point3d>
static Point from_cart3d(Point3d const& point_3d)
{
return formula::cart3d_to_sph<Point>(point_3d);
}
template <typename Point3d, typename Point>
static Point3d to_cart3d(Point const& point)
{
return formula::sph_to_cart3d<Point3d>(point);
}
template <typename Point3d>
struct plane
{
typedef typename coordinate_type<Point3d>::type coord_t;
// not normalized
plane(Point3d const& p1, Point3d const& p2)
: normal(cross_product(p1, p2))
{}
int side_value(Point3d const& pt) const
{
return formula::sph_side_value(normal, pt);
}
static coord_t cos_angle_between(Point3d const& p1, Point3d const& p2)
{
return dot_product(p1, p2);
}
coord_t cos_angle_between(Point3d const& p1, Point3d const& p2, bool & is_forward) const
{
coord_t const c0 = 0;
is_forward = dot_product(normal, cross_product(p1, p2)) >= c0;
return dot_product(p1, p2);
}
Point3d normal;
};
template <typename Point3d>
static plane<Point3d> get_plane(Point3d const& p1, Point3d const& p2)
{
return plane<Point3d>(p1, p2);
}
template <typename Point3d>
static bool intersection_points(plane<Point3d> const& plane1,
plane<Point3d> const& plane2,
Point3d & ip1, Point3d & ip2)
{
typedef typename coordinate_type<Point3d>::type coord_t;
ip1 = cross_product(plane1.normal, plane2.normal);
// NOTE: the length should be greater than 0 at this point
// if the normals were not normalized and their dot product
// not checked before this function is called the length
// should be checked here (math::equals(len, c0))
coord_t const len = math::sqrt(dot_product(ip1, ip1));
divide_value(ip1, len); // normalize i1
ip2 = ip1;
multiply_value(ip2, coord_t(-1));
return true;
}
};
template
<
typename CalculationType = void
>
struct spherical_segments
: ecef_segments
<
spherical_segments_calc_policy,
CalculationType
>
{};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
/*template <typename CalculationType>
struct default_strategy<spherical_polar_tag, CalculationType>
{
typedef spherical_segments<CalculationType> type;
};*/
template <typename CalculationType>
struct default_strategy<spherical_equatorial_tag, CalculationType>
{
typedef spherical_segments<CalculationType> type;
};
template <typename CalculationType>
struct default_strategy<geographic_tag, CalculationType>
{
// NOTE: Spherical strategy returns the same result as the geographic one
// representing segments as great elliptic arcs. If the elliptic arcs are
// not great elliptic arcs (the origin not in the center of the coordinate
// system) then there may be problems with consistency of the side and
// intersection strategies.
typedef spherical_segments<CalculationType> type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::intersection
namespace strategy
{
namespace within { namespace services
{
template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2>
struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, linear_tag, linear_tag, spherical_tag, spherical_tag>
{
typedef strategy::intersection::spherical_segments<> type;
};
template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2>
struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, linear_tag, polygonal_tag, spherical_tag, spherical_tag>
{
typedef strategy::intersection::spherical_segments<> type;
};
template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2>
struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, polygonal_tag, linear_tag, spherical_tag, spherical_tag>
{
typedef strategy::intersection::spherical_segments<> type;
};
template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2>
struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, polygonal_tag, polygonal_tag, spherical_tag, spherical_tag>
{
typedef strategy::intersection::spherical_segments<> type;
};
}} // within::services
namespace covered_by { namespace services
{
template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2>
struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, linear_tag, linear_tag, spherical_tag, spherical_tag>
{
typedef strategy::intersection::spherical_segments<> type;
};
template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2>
struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, linear_tag, polygonal_tag, spherical_tag, spherical_tag>
{
typedef strategy::intersection::spherical_segments<> type;
};
template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2>
struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, polygonal_tag, linear_tag, spherical_tag, spherical_tag>
{
typedef strategy::intersection::spherical_segments<> type;
};
template <typename Geometry1, typename Geometry2, typename AnyTag1, typename AnyTag2>
struct default_strategy<Geometry1, Geometry2, AnyTag1, AnyTag2, polygonal_tag, polygonal_tag, spherical_tag, spherical_tag>
{
typedef strategy::intersection::spherical_segments<> type;
};
}} // within::services
} // strategy
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_INTERSECTION_HPP
@@ -0,0 +1,76 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_SIDE_BY_CROSS_TRACK_HPP
#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_SIDE_BY_CROSS_TRACK_HPP
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/algorithms/detail/course.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/strategies/side.hpp>
//#include <boost/geometry/strategies/concepts/side_concept.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace side
{
/*!
\brief Check at which side of a Great Circle segment a point lies
left of segment (> 0), right of segment (< 0), on segment (0)
\ingroup strategies
\tparam CalculationType \tparam_calculation
*/
template <typename CalculationType = void>
class side_by_cross_track
{
public :
template <typename P1, typename P2, typename P>
static inline int apply(P1 const& p1, P2 const& p2, P const& p)
{
typedef typename promote_floating_point
<
typename select_calculation_type_alt
<
CalculationType,
P1, P2, P
>::type
>::type calc_t;
calc_t d1 = 0.001; // m_strategy.apply(sp1, p);
calc_t crs_AD = geometry::detail::course<calc_t>(p1, p);
calc_t crs_AB = geometry::detail::course<calc_t>(p1, p2);
calc_t XTD = asin(sin(d1) * sin(crs_AD - crs_AB));
return math::equals(XTD, 0) ? 0 : XTD < 0 ? 1 : -1;
}
};
}} // namespace strategy::side
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_SIDE_BY_CROSS_TRACK_HPP
@@ -0,0 +1,141 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2011-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2016.
// Modifications copyright (c) 2016, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_SSF_HPP
#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_SSF_HPP
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/strategies/side.hpp>
//#include <boost/geometry/strategies/concepts/side_concept.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace side
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template <typename T>
int spherical_side_formula(T const& lambda1, T const& delta1,
T const& lambda2, T const& delta2,
T const& lambda, T const& delta)
{
// Create temporary points (vectors) on unit a sphere
T const cos_delta1 = cos(delta1);
T const c1x = cos_delta1 * cos(lambda1);
T const c1y = cos_delta1 * sin(lambda1);
T const c1z = sin(delta1);
T const cos_delta2 = cos(delta2);
T const c2x = cos_delta2 * cos(lambda2);
T const c2y = cos_delta2 * sin(lambda2);
T const c2z = sin(delta2);
// (Third point is converted directly)
T const cos_delta = cos(delta);
// Apply the "Spherical Side Formula" as presented on my blog
T const dist
= (c1y * c2z - c1z * c2y) * cos_delta * cos(lambda)
+ (c1z * c2x - c1x * c2z) * cos_delta * sin(lambda)
+ (c1x * c2y - c1y * c2x) * sin(delta);
T zero = T();
return math::equals(dist, zero) ? 0
: dist > zero ? 1
: -1; // dist < zero
}
}
#endif // DOXYGEN_NO_DETAIL
/*!
\brief Check at which side of a Great Circle segment a point lies
left of segment (> 0), right of segment (< 0), on segment (0)
\ingroup strategies
\tparam CalculationType \tparam_calculation
*/
template <typename CalculationType = void>
class spherical_side_formula
{
public :
template <typename P1, typename P2, typename P>
static inline int apply(P1 const& p1, P2 const& p2, P const& p)
{
typedef typename promote_floating_point
<
typename select_calculation_type_alt
<
CalculationType,
P1, P2, P
>::type
>::type calculation_type;
calculation_type const lambda1 = get_as_radian<0>(p1);
calculation_type const delta1 = get_as_radian<1>(p1);
calculation_type const lambda2 = get_as_radian<0>(p2);
calculation_type const delta2 = get_as_radian<1>(p2);
calculation_type const lambda = get_as_radian<0>(p);
calculation_type const delta = get_as_radian<1>(p);
return detail::spherical_side_formula(lambda1, delta1,
lambda2, delta2,
lambda, delta);
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
/*template <typename CalculationType>
struct default_strategy<spherical_polar_tag, CalculationType>
{
typedef spherical_side_formula<CalculationType> type;
};*/
template <typename CalculationType>
struct default_strategy<spherical_equatorial_tag, CalculationType>
{
typedef spherical_side_formula<CalculationType> type;
};
template <typename CalculationType>
struct default_strategy<geographic_tag, CalculationType>
{
typedef spherical_side_formula<CalculationType> type;
};
}
#endif
}} // namespace strategy::side
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_SSF_HPP
@@ -0,0 +1,109 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// This file was modified by Oracle on 2014-2017.
// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_STRATEGIES_HPP
#define BOOST_GEOMETRY_STRATEGIES_STRATEGIES_HPP
#include <boost/geometry/strategies/tags.hpp>
#include <boost/geometry/strategies/area.hpp>
#include <boost/geometry/strategies/azimuth.hpp>
#include <boost/geometry/strategies/buffer.hpp>
#include <boost/geometry/strategies/centroid.hpp>
#include <boost/geometry/strategies/compare.hpp>
#include <boost/geometry/strategies/convex_hull.hpp>
#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/disjoint.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/envelope.hpp>
#include <boost/geometry/strategies/intersection.hpp>
#include <boost/geometry/strategies/intersection_strategies.hpp> // for backward compatibility
#include <boost/geometry/strategies/relate.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/strategies/transform.hpp>
#include <boost/geometry/strategies/within.hpp>
#include <boost/geometry/strategies/cartesian/area_surveyor.hpp>
#include <boost/geometry/strategies/cartesian/azimuth.hpp>
#include <boost/geometry/strategies/cartesian/box_in_box.hpp>
#include <boost/geometry/strategies/cartesian/buffer_end_flat.hpp>
#include <boost/geometry/strategies/cartesian/buffer_end_round.hpp>
#include <boost/geometry/strategies/cartesian/buffer_join_miter.hpp>
#include <boost/geometry/strategies/cartesian/buffer_join_round.hpp>
#include <boost/geometry/strategies/cartesian/buffer_join_round_by_divide.hpp>
#include <boost/geometry/strategies/cartesian/buffer_point_circle.hpp>
#include <boost/geometry/strategies/cartesian/buffer_point_square.hpp>
#include <boost/geometry/strategies/cartesian/buffer_side_straight.hpp>
#include <boost/geometry/strategies/cartesian/centroid_average.hpp>
#include <boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp>
#include <boost/geometry/strategies/cartesian/centroid_weighted_length.hpp>
#include <boost/geometry/strategies/cartesian/disjoint_segment_box.hpp>
#include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp>
#include <boost/geometry/strategies/cartesian/distance_pythagoras_point_box.hpp>
#include <boost/geometry/strategies/cartesian/distance_pythagoras_box_box.hpp>
#include <boost/geometry/strategies/cartesian/distance_projected_point.hpp>
#include <boost/geometry/strategies/cartesian/distance_projected_point_ax.hpp>
#include <boost/geometry/strategies/cartesian/envelope_segment.hpp>
#include <boost/geometry/strategies/cartesian/intersection.hpp>
#include <boost/geometry/strategies/cartesian/point_in_box.hpp>
#include <boost/geometry/strategies/cartesian/point_in_poly_franklin.hpp>
#include <boost/geometry/strategies/cartesian/point_in_poly_crossings_multiply.hpp>
#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>
#include <boost/geometry/strategies/spherical/area.hpp>
#include <boost/geometry/strategies/spherical/azimuth.hpp>
#include <boost/geometry/strategies/spherical/distance_haversine.hpp>
#include <boost/geometry/strategies/spherical/distance_cross_track.hpp>
#include <boost/geometry/strategies/spherical/distance_cross_track_point_box.hpp>
#include <boost/geometry/strategies/spherical/compare_circular.hpp>
#include <boost/geometry/strategies/spherical/envelope_segment.hpp>
#include <boost/geometry/strategies/spherical/intersection.hpp>
#include <boost/geometry/strategies/spherical/ssf.hpp>
#include <boost/geometry/strategies/geographic/area.hpp>
#include <boost/geometry/strategies/geographic/azimuth.hpp>
#include <boost/geometry/strategies/geographic/distance.hpp>
#include <boost/geometry/strategies/geographic/distance_andoyer.hpp>
#include <boost/geometry/strategies/geographic/distance_thomas.hpp>
#include <boost/geometry/strategies/geographic/distance_vincenty.hpp>
#include <boost/geometry/strategies/geographic/envelope_segment.hpp>
#include <boost/geometry/strategies/geographic/intersection.hpp>
//#include <boost/geometry/strategies/geographic/intersection_elliptic.hpp>
#include <boost/geometry/strategies/geographic/side.hpp>
#include <boost/geometry/strategies/geographic/side_andoyer.hpp>
#include <boost/geometry/strategies/geographic/side_thomas.hpp>
#include <boost/geometry/strategies/geographic/side_vincenty.hpp>
#include <boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp>
#include <boost/geometry/strategies/agnostic/buffer_distance_asymmetric.hpp>
#include <boost/geometry/strategies/agnostic/hull_graham_andrew.hpp>
#include <boost/geometry/strategies/agnostic/point_in_box_by_side.hpp>
#include <boost/geometry/strategies/agnostic/point_in_point.hpp>
#include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp>
#include <boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp>
#include <boost/geometry/strategies/strategy_transform.hpp>
#include <boost/geometry/strategies/transform/matrix_transformers.hpp>
#include <boost/geometry/strategies/transform/map_transformer.hpp>
#include <boost/geometry/strategies/transform/inverse_transformer.hpp>
#endif // BOOST_GEOMETRY_STRATEGIES_STRATEGIES_HPP
@@ -0,0 +1,527 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2015.
// Modifications copyright (c) 2015 Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP
#define BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP
#include <cstddef>
#include <cmath>
#include <functional>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/strategies/transform.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace transform
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template
<
typename Src, typename Dst,
std::size_t D, std::size_t N,
template <typename> class F
>
struct transform_coordinates
{
template <typename T>
static inline void transform(Src const& source, Dst& dest, T value)
{
typedef typename select_coordinate_type<Src, Dst>::type coordinate_type;
F<coordinate_type> function;
set<D>(dest, boost::numeric_cast<coordinate_type>(function(get<D>(source), value)));
transform_coordinates<Src, Dst, D + 1, N, F>::transform(source, dest, value);
}
};
template
<
typename Src, typename Dst,
std::size_t N,
template <typename> class F
>
struct transform_coordinates<Src, Dst, N, N, F>
{
template <typename T>
static inline void transform(Src const& , Dst& , T )
{
}
};
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
/*!
\brief Transformation strategy to copy one point to another using assignment operator
\ingroup transform
\tparam P point type
*/
template <typename P>
struct copy_direct
{
inline bool apply(P const& p1, P& p2) const
{
p2 = p1;
return true;
}
};
/*!
\brief Transformation strategy to do copy a point, copying per coordinate.
\ingroup transform
\tparam P1 first point type
\tparam P2 second point type
*/
template <typename P1, typename P2>
struct copy_per_coordinate
{
inline bool apply(P1 const& p1, P2& p2) const
{
// Defensive check, dimensions are equal, selected by specialization
assert_dimension_equal<P1, P2>();
geometry::convert(p1, p2);
return true;
}
};
/*!
\brief Transformation strategy to go from degree to radian and back
\ingroup transform
\tparam P1 first point type
\tparam P2 second point type
\tparam F additional functor to divide or multiply with d2r
*/
template <typename P1, typename P2, template <typename> class F>
struct degree_radian_vv
{
inline bool apply(P1 const& p1, P2& p2) const
{
// Spherical coordinates always have 2 coordinates measured in angles
// The optional third one is distance/height, provided in another strategy
// Polar coordinates having one angle, will be also in another strategy
assert_dimension<P1, 2>();
assert_dimension<P2, 2>();
typedef typename promote_floating_point
<
typename select_coordinate_type<P1, P2>::type
>::type calculation_type;
detail::transform_coordinates
<
P1, P2, 0, 2, F
>::transform(p1, p2, math::d2r<calculation_type>());
return true;
}
};
template <typename P1, typename P2, template <typename> class F>
struct degree_radian_vv_3
{
inline bool apply(P1 const& p1, P2& p2) const
{
assert_dimension<P1, 3>();
assert_dimension<P2, 3>();
typedef typename promote_floating_point
<
typename select_coordinate_type<P1, P2>::type
>::type calculation_type;
detail::transform_coordinates
<
P1, P2, 0, 2, F
>::transform(p1, p2, math::d2r<calculation_type>());
// Copy height or other third dimension
set<2>(p2, get<2>(p1));
return true;
}
};
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
/// Helper function for conversion, phi/theta are in radians
template <typename P, typename T, typename R>
inline void spherical_polar_to_cartesian(T phi, T theta, R r, P& p)
{
assert_dimension<P, 3>();
// http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_spherical_coordinates
// http://www.vias.org/comp_geometry/math_coord_convert_3d.htm
// https://moodle.polymtl.ca/file.php/1183/Autres_Documents/Derivation_for_Spherical_Co-ordinates.pdf
// http://en.citizendium.org/wiki/Spherical_polar_coordinates
// Phi = first, theta is second, r is third, see documentation on cs::spherical
// (calculations are splitted to implement ttmath)
T r_sin_theta = r;
T r_cos_theta = r;
r_sin_theta *= sin(theta);
r_cos_theta *= cos(theta);
set<0>(p, r_sin_theta * cos(phi));
set<1>(p, r_sin_theta * sin(phi));
set<2>(p, r_cos_theta);
}
/// Helper function for conversion, lambda/delta (lon lat) are in radians
template <typename P, typename T, typename R>
inline void spherical_equatorial_to_cartesian(T lambda, T delta, R r, P& p)
{
assert_dimension<P, 3>();
// http://mathworld.wolfram.com/GreatCircle.html
// http://www.spenvis.oma.be/help/background/coortran/coortran.html WRONG
T r_cos_delta = r;
T r_sin_delta = r;
r_cos_delta *= cos(delta);
r_sin_delta *= sin(delta);
set<0>(p, r_cos_delta * cos(lambda));
set<1>(p, r_cos_delta * sin(lambda));
set<2>(p, r_sin_delta);
}
/// Helper function for conversion
template <typename P, typename T>
inline bool cartesian_to_spherical2(T x, T y, T z, P& p)
{
assert_dimension<P, 2>();
// http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates
#if defined(BOOST_GEOMETRY_TRANSFORM_CHECK_UNIT_SPHERE)
// TODO: MAYBE ONLY IF TO BE CHECKED?
T const r = /*sqrt not necessary, sqrt(1)=1*/ (x * x + y * y + z * z);
// Unit sphere, so r should be 1
if (geometry::math::abs(r - 1.0) > T(1e-6))
{
return false;
}
// end todo
#endif
set_from_radian<0>(p, atan2(y, x));
set_from_radian<1>(p, acos(z));
return true;
}
template <typename P, typename T>
inline bool cartesian_to_spherical_equatorial2(T x, T y, T z, P& p)
{
assert_dimension<P, 2>();
set_from_radian<0>(p, atan2(y, x));
set_from_radian<1>(p, asin(z));
return true;
}
template <typename P, typename T>
inline bool cartesian_to_spherical3(T x, T y, T z, P& p)
{
assert_dimension<P, 3>();
// http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates
T const r = math::sqrt(x * x + y * y + z * z);
set<2>(p, r);
set_from_radian<0>(p, atan2(y, x));
if (r > 0.0)
{
set_from_radian<1>(p, acos(z / r));
return true;
}
return false;
}
template <typename P, typename T>
inline bool cartesian_to_spherical_equatorial3(T x, T y, T z, P& p)
{
assert_dimension<P, 3>();
// http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_Cartesian_coordinates
T const r = math::sqrt(x * x + y * y + z * z);
set<2>(p, r);
set_from_radian<0>(p, atan2(y, x));
if (r > 0.0)
{
set_from_radian<1>(p, asin(z / r));
return true;
}
return false;
}
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
/*!
\brief Transformation strategy for 2D spherical (phi,theta) to 3D cartesian (x,y,z)
\details on Unit sphere
\ingroup transform
\tparam P1 first point type
\tparam P2 second point type
*/
template <typename P1, typename P2>
struct from_spherical_polar_2_to_cartesian_3
{
inline bool apply(P1 const& p1, P2& p2) const
{
assert_dimension<P1, 2>();
detail::spherical_polar_to_cartesian(get_as_radian<0>(p1), get_as_radian<1>(p1), 1.0, p2);
return true;
}
};
template <typename P1, typename P2>
struct from_spherical_equatorial_2_to_cartesian_3
{
inline bool apply(P1 const& p1, P2& p2) const
{
assert_dimension<P1, 2>();
detail::spherical_equatorial_to_cartesian(get_as_radian<0>(p1), get_as_radian<1>(p1), 1.0, p2);
return true;
}
};
/*!
\brief Transformation strategy for 3D spherical (phi,theta,r) to 3D cartesian (x,y,z)
\ingroup transform
\tparam P1 first point type
\tparam P2 second point type
*/
template <typename P1, typename P2>
struct from_spherical_polar_3_to_cartesian_3
{
inline bool apply(P1 const& p1, P2& p2) const
{
assert_dimension<P1, 3>();
detail::spherical_polar_to_cartesian(
get_as_radian<0>(p1), get_as_radian<1>(p1), get<2>(p1), p2);
return true;
}
};
template <typename P1, typename P2>
struct from_spherical_equatorial_3_to_cartesian_3
{
inline bool apply(P1 const& p1, P2& p2) const
{
assert_dimension<P1, 3>();
detail::spherical_equatorial_to_cartesian(
get_as_radian<0>(p1), get_as_radian<1>(p1), get<2>(p1), p2);
return true;
}
};
/*!
\brief Transformation strategy for 3D cartesian (x,y,z) to 2D spherical (phi,theta)
\details on Unit sphere
\ingroup transform
\tparam P1 first point type
\tparam P2 second point type
\note If x,y,z point is not lying on unit sphere, transformation will return false
*/
template <typename P1, typename P2>
struct from_cartesian_3_to_spherical_polar_2
{
inline bool apply(P1 const& p1, P2& p2) const
{
assert_dimension<P1, 3>();
return detail::cartesian_to_spherical2(get<0>(p1), get<1>(p1), get<2>(p1), p2);
}
};
template <typename P1, typename P2>
struct from_cartesian_3_to_spherical_equatorial_2
{
inline bool apply(P1 const& p1, P2& p2) const
{
assert_dimension<P1, 3>();
return detail::cartesian_to_spherical_equatorial2(get<0>(p1), get<1>(p1), get<2>(p1), p2);
}
};
/*!
\brief Transformation strategy for 3D cartesian (x,y,z) to 3D spherical (phi,theta,r)
\ingroup transform
\tparam P1 first point type
\tparam P2 second point type
*/
template <typename P1, typename P2>
struct from_cartesian_3_to_spherical_polar_3
{
inline bool apply(P1 const& p1, P2& p2) const
{
assert_dimension<P1, 3>();
return detail::cartesian_to_spherical3(get<0>(p1), get<1>(p1), get<2>(p1), p2);
}
};
template <typename P1, typename P2>
struct from_cartesian_3_to_spherical_equatorial_3
{
inline bool apply(P1 const& p1, P2& p2) const
{
assert_dimension<P1, 3>();
return detail::cartesian_to_spherical_equatorial3(get<0>(p1), get<1>(p1), get<2>(p1), p2);
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
/// Specialization for same coordinate system family, same system, same dimension, same point type, can be copied
template <typename CoordSysTag, typename CoordSys, std::size_t D, typename P>
struct default_strategy<CoordSysTag, CoordSysTag, CoordSys, CoordSys, D, D, P, P>
{
typedef copy_direct<P> type;
};
/// Specialization for same coordinate system family and system, same dimension, different point type, copy per coordinate
template <typename CoordSysTag, typename CoordSys, std::size_t D, typename P1, typename P2>
struct default_strategy<CoordSysTag, CoordSysTag, CoordSys, CoordSys, D, D, P1, P2>
{
typedef copy_per_coordinate<P1, P2> type;
};
/// Specialization to transform from degree to radian for any coordinate system / point type combination
template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<degree>, CoordSys<radian>, 2, 2, P1, P2>
{
typedef degree_radian_vv<P1, P2, std::multiplies> type;
};
/// Specialization to transform from radian to degree for any coordinate system / point type combination
template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<radian>, CoordSys<degree>, 2, 2, P1, P2>
{
typedef degree_radian_vv<P1, P2, std::divides> type;
};
/// Specialization degree->radian in 3D
template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<degree>, CoordSys<radian>, 3, 3, P1, P2>
{
typedef degree_radian_vv_3<P1, P2, std::multiplies> type;
};
/// Specialization radian->degree in 3D
template <typename CoordSysTag, template<typename> class CoordSys, typename P1, typename P2>
struct default_strategy<CoordSysTag, CoordSysTag, CoordSys<radian>, CoordSys<degree>, 3, 3, P1, P2>
{
typedef degree_radian_vv_3<P1, P2, std::divides> type;
};
/// Specialization to transform from unit sphere(phi,theta) to XYZ
template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
struct default_strategy<spherical_polar_tag, cartesian_tag, CoordSys1, CoordSys2, 2, 3, P1, P2>
{
typedef from_spherical_polar_2_to_cartesian_3<P1, P2> type;
};
/// Specialization to transform from sphere(phi,theta,r) to XYZ
template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
struct default_strategy<spherical_polar_tag, cartesian_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
{
typedef from_spherical_polar_3_to_cartesian_3<P1, P2> type;
};
template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
struct default_strategy<spherical_equatorial_tag, cartesian_tag, CoordSys1, CoordSys2, 2, 3, P1, P2>
{
typedef from_spherical_equatorial_2_to_cartesian_3<P1, P2> type;
};
template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
struct default_strategy<spherical_equatorial_tag, cartesian_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
{
typedef from_spherical_equatorial_3_to_cartesian_3<P1, P2> type;
};
/// Specialization to transform from XYZ to unit sphere(phi,theta)
template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
struct default_strategy<cartesian_tag, spherical_polar_tag, CoordSys1, CoordSys2, 3, 2, P1, P2>
{
typedef from_cartesian_3_to_spherical_polar_2<P1, P2> type;
};
template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
struct default_strategy<cartesian_tag, spherical_equatorial_tag, CoordSys1, CoordSys2, 3, 2, P1, P2>
{
typedef from_cartesian_3_to_spherical_equatorial_2<P1, P2> type;
};
/// Specialization to transform from XYZ to sphere(phi,theta,r)
template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
struct default_strategy<cartesian_tag, spherical_polar_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
{
typedef from_cartesian_3_to_spherical_polar_3<P1, P2> type;
};
template <typename CoordSys1, typename CoordSys2, typename P1, typename P2>
struct default_strategy<cartesian_tag, spherical_equatorial_tag, CoordSys1, CoordSys2, 3, 3, P1, P2>
{
typedef from_cartesian_3_to_spherical_equatorial_3<P1, P2> type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::transform
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_STRATEGY_TRANSFORM_HPP
@@ -0,0 +1,43 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_TAGS_HPP
#define BOOST_GEOMETRY_STRATEGIES_TAGS_HPP
namespace boost { namespace geometry
{
namespace strategy
{
/*!
\brief Indicate compiler/library user that strategy is not implemented.
\details Strategies are defined for point types or for point type
combinations. If there is no implementation for that specific point type, or point type
combination, the calculation cannot be done. To indicate this, this not_implemented
class is used as a typedef stub.
*/
struct not_implemented {};
}
struct strategy_tag_distance_point_point {};
struct strategy_tag_distance_point_segment {};
struct strategy_tag_distance_point_box {};
struct strategy_tag_distance_box_box {};
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_TAGS_HPP
@@ -0,0 +1,63 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_TRANSFORM_HPP
#define BOOST_GEOMETRY_STRATEGIES_TRANSFORM_HPP
#include <cstddef>
#include <boost/mpl/assert.hpp>
#include <boost/geometry/strategies/tags.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace transform { namespace services
{
/*!
\brief Traits class binding a transformation strategy to a coordinate system
\ingroup transform
\details Can be specialized
- per coordinate system family (tag)
- per coordinate system (or groups of them)
- per dimension
- per point type
\tparam CoordinateSystemTag 1,2 coordinate system tags
\tparam CoordinateSystem 1,2 coordinate system
\tparam D 1, 2 dimension
\tparam Point 1, 2 point type
*/
template
<
typename CoordinateSystemTag1, typename CoordinateSystemTag2,
typename CoordinateSystem1, typename CoordinateSystem2,
std::size_t Dimension1, std::size_t Dimension2,
typename Point1, typename Point2
>
struct default_strategy
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_IMPLEMENTED_FOR_THIS_POINT_TYPES
, (types<Point1, Point2>)
);
};
}}} // namespace strategy::transform::services
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_TRANSFORM_HPP
@@ -0,0 +1,57 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_TRANSFORM_INVERSE_TRANSFORMER_HPP
#define BOOST_GEOMETRY_STRATEGIES_TRANSFORM_INVERSE_TRANSFORMER_HPP
#include <boost/qvm/mat.hpp>
#include <boost/qvm/mat_operations.hpp>
#include <boost/geometry/strategies/transform/matrix_transformers.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace transform
{
/*!
\brief Transformation strategy to do an inverse transformation in a Cartesian coordinate system
\ingroup strategies
*/
template
<
typename CalculationType,
std::size_t Dimension1,
std::size_t Dimension2
>
class inverse_transformer
: public matrix_transformer<CalculationType, Dimension1, Dimension2>
{
public :
template <typename Transformer>
inline inverse_transformer(Transformer const& input)
{
this->m_matrix = boost::qvm::inverse(input.matrix());
}
};
}} // namespace strategy::transform
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_TRANSFORM_INVERSE_TRANSFORMER_HPP
@@ -0,0 +1,172 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_TRANSFORM_MAP_TRANSFORMER_HPP
#define BOOST_GEOMETRY_STRATEGIES_TRANSFORM_MAP_TRANSFORMER_HPP
#include <cstddef>
#include <boost/geometry/strategies/transform/matrix_transformers.hpp>
namespace boost { namespace geometry
{
// Silence warning C4127: conditional expression is constant
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4127)
#endif
namespace strategy { namespace transform
{
/*!
\brief Transformation strategy to map from one to another Cartesian coordinate system
\ingroup strategies
\tparam Mirror if true map is mirrored upside-down (in most cases pixels
are from top to bottom, while map is from bottom to top)
*/
template
<
typename CalculationType,
std::size_t Dimension1,
std::size_t Dimension2,
bool Mirror = false,
bool SameScale = true
>
class map_transformer
: public matrix_transformer<CalculationType, Dimension1, Dimension2>
{
typedef boost::qvm::mat<CalculationType, Dimension1 + 1, Dimension2 + 1> M;
typedef boost::qvm::mat<CalculationType, 3, 3> matrix33;
public :
template <typename B, typename D>
explicit inline map_transformer(B const& box, D const& width, D const& height)
{
set_transformation(
get<min_corner, 0>(box), get<min_corner, 1>(box),
get<max_corner, 0>(box), get<max_corner, 1>(box),
width, height);
}
template <typename W, typename D>
explicit inline map_transformer(W const& wx1, W const& wy1, W const& wx2, W const& wy2,
D const& width, D const& height)
{
set_transformation(wx1, wy1, wx2, wy2, width, height);
}
private :
template <typename W, typename P, typename S>
inline void set_transformation_point(W const& wx, W const& wy,
P const& px, P const& py,
S const& scalex, S const& scaley)
{
// Translate to a coordinate system centered on world coordinates (-wx, -wy)
matrix33 t1;
qvm::A<0,0>(t1) = 1; qvm::A<0,1>(t1) = 0; qvm::A<0,2>(t1) = -wx;
qvm::A<1,0>(t1) = 0; qvm::A<1,1>(t1) = 1; qvm::A<1,2>(t1) = -wy;
qvm::A<2,0>(t1) = 0; qvm::A<2,1>(t1) = 0; qvm::A<2,2>(t1) = 1;
// Scale the map
matrix33 s;
qvm::A<0,0>(s) = scalex; qvm::A<0,1>(s) = 0; qvm::A<0,2>(s) = 0;
qvm::A<1,0>(s) = 0; qvm::A<1,1>(s) = scaley; qvm::A<1,2>(s) = 0;
qvm::A<2,0>(s) = 0; qvm::A<2,1>(s) = 0; qvm::A<2,2>(s) = 1;
// Translate to a coordinate system centered on the specified pixels (+px, +py)
matrix33 t2;
qvm::A<0,0>(t2) = 1; qvm::A<0,1>(t2) = 0; qvm::A<0,2>(t2) = px;
qvm::A<1,0>(t2) = 0; qvm::A<1,1>(t2) = 1; qvm::A<1,2>(t2) = py;
qvm::A<2,0>(t2) = 0; qvm::A<2,1>(t2) = 0; qvm::A<2,2>(t2) = 1;
// Calculate combination matrix in two steps
this->m_matrix = s * t1;
this->m_matrix = t2 * this->m_matrix;
}
template <typename W, typename D>
void set_transformation(W const& wx1, W const& wy1, W const& wx2, W const& wy2,
D const& width, D const& height)
{
D px1 = 0;
D py1 = 0;
D px2 = width;
D py2 = height;
// Get the same type, but at least a double
typedef typename select_most_precise<D, double>::type type;
// Calculate appropriate scale, take min because whole box must fit
// Scale is in PIXELS/MAPUNITS (meters)
W wdx = wx2 - wx1;
W wdy = wy2 - wy1;
type sx = (px2 - px1) / boost::numeric_cast<type>(wdx);
type sy = (py2 - py1) / boost::numeric_cast<type>(wdy);
if (SameScale)
{
type scale = (std::min)(sx, sy);
sx = scale;
sy = scale;
}
// Calculate centerpoints
W wtx = wx1 + wx2;
W wty = wy1 + wy2;
W two = 2;
W wmx = wtx / two;
W wmy = wty / two;
type pmx = (px1 + px2) / 2.0;
type pmy = (py1 + py2) / 2.0;
set_transformation_point(wmx, wmy, pmx, pmy, sx, sy);
if (Mirror)
{
// Mirror in y-direction
matrix33 m;
qvm::A<0,0>(m) = 1; qvm::A<0,1>(m) = 0; qvm::A<0,2>(m) = 0;
qvm::A<1,0>(m) = 0; qvm::A<1,1>(m) = -1; qvm::A<1,2>(m) = 0;
qvm::A<2,0>(m) = 0; qvm::A<2,1>(m) = 0; qvm::A<2,2>(m) = 1;
// Translate in y-direction such that it fits again
matrix33 y;
qvm::A<0,0>(y) = 1; qvm::A<0,1>(y) = 0; qvm::A<0,2>(y) = 0;
qvm::A<1,0>(y) = 0; qvm::A<1,1>(y) = 1; qvm::A<1,2>(y) = height;
qvm::A<2,0>(y) = 0; qvm::A<2,1>(y) = 0; qvm::A<2,2>(y) = 1;
// Calculate combination matrix in two steps
this->m_matrix = m * this->m_matrix;
this->m_matrix = y * this->m_matrix;
}
}
};
}} // namespace strategy::transform
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_TRANSFORM_MAP_TRANSFORMER_HPP
@@ -0,0 +1,399 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2015.
// Modifications copyright (c) 2015 Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_TRANSFORM_MATRIX_TRANSFORMERS_HPP
#define BOOST_GEOMETRY_STRATEGIES_TRANSFORM_MATRIX_TRANSFORMERS_HPP
#include <cstddef>
#include <boost/qvm/mat.hpp>
#include <boost/qvm/mat_access.hpp>
#include <boost/qvm/mat_operations.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace transform
{
/*!
\brief Affine transformation strategy in Cartesian system.
\details The strategy serves as a generic definition of affine transformation matrix
and procedure of application it to given point.
\see http://en.wikipedia.org/wiki/Affine_transformation
and http://www.devmaster.net/wiki/Transformation_matrices
\ingroup strategies
\tparam Dimension1 number of dimensions to transform from
\tparam Dimension2 number of dimensions to transform to
*/
template
<
typename CalculationType,
std::size_t Dimension1,
std::size_t Dimension2
>
class matrix_transformer
{
};
template <typename CalculationType>
class matrix_transformer<CalculationType, 2, 2>
{
protected :
typedef CalculationType ct;
typedef boost::qvm::mat<ct, 3, 3> matrix_type;
matrix_type m_matrix;
public :
inline matrix_transformer(
ct const& m_0_0, ct const& m_0_1, ct const& m_0_2,
ct const& m_1_0, ct const& m_1_1, ct const& m_1_2,
ct const& m_2_0, ct const& m_2_1, ct const& m_2_2)
{
qvm::A<0,0>(m_matrix) = m_0_0; qvm::A<0,1>(m_matrix) = m_0_1; qvm::A<0,2>(m_matrix) = m_0_2;
qvm::A<1,0>(m_matrix) = m_1_0; qvm::A<1,1>(m_matrix) = m_1_1; qvm::A<1,2>(m_matrix) = m_1_2;
qvm::A<2,0>(m_matrix) = m_2_0; qvm::A<2,1>(m_matrix) = m_2_1; qvm::A<2,2>(m_matrix) = m_2_2;
}
inline matrix_transformer(matrix_type const& matrix)
: m_matrix(matrix)
{}
inline matrix_transformer() {}
template <typename P1, typename P2>
inline bool apply(P1 const& p1, P2& p2) const
{
assert_dimension_greater_equal<P1, 2>();
assert_dimension_greater_equal<P2, 2>();
ct const& c1 = get<0>(p1);
ct const& c2 = get<1>(p1);
ct p2x = c1 * qvm::A<0,0>(m_matrix) + c2 * qvm::A<0,1>(m_matrix) + qvm::A<0,2>(m_matrix);
ct p2y = c1 * qvm::A<1,0>(m_matrix) + c2 * qvm::A<1,1>(m_matrix) + qvm::A<1,2>(m_matrix);
typedef typename geometry::coordinate_type<P2>::type ct2;
set<0>(p2, boost::numeric_cast<ct2>(p2x));
set<1>(p2, boost::numeric_cast<ct2>(p2y));
return true;
}
matrix_type const& matrix() const { return m_matrix; }
};
// It IS possible to go from 3 to 2 coordinates
template <typename CalculationType>
class matrix_transformer<CalculationType, 3, 2> : public matrix_transformer<CalculationType, 2, 2>
{
typedef CalculationType ct;
public :
inline matrix_transformer(
ct const& m_0_0, ct const& m_0_1, ct const& m_0_2,
ct const& m_1_0, ct const& m_1_1, ct const& m_1_2,
ct const& m_2_0, ct const& m_2_1, ct const& m_2_2)
: matrix_transformer<CalculationType, 2, 2>(
m_0_0, m_0_1, m_0_2,
m_1_0, m_1_1, m_1_2,
m_2_0, m_2_1, m_2_2)
{}
inline matrix_transformer()
: matrix_transformer<CalculationType, 2, 2>()
{}
};
template <typename CalculationType>
class matrix_transformer<CalculationType, 3, 3>
{
protected :
typedef CalculationType ct;
typedef boost::qvm::mat<ct, 4, 4> matrix_type;
matrix_type m_matrix;
public :
inline matrix_transformer(
ct const& m_0_0, ct const& m_0_1, ct const& m_0_2, ct const& m_0_3,
ct const& m_1_0, ct const& m_1_1, ct const& m_1_2, ct const& m_1_3,
ct const& m_2_0, ct const& m_2_1, ct const& m_2_2, ct const& m_2_3,
ct const& m_3_0, ct const& m_3_1, ct const& m_3_2, ct const& m_3_3
)
{
qvm::A<0,0>(m_matrix) = m_0_0; qvm::A<0,1>(m_matrix) = m_0_1; qvm::A<0,2>(m_matrix) = m_0_2; qvm::A<0,3>(m_matrix) = m_0_3;
qvm::A<1,0>(m_matrix) = m_1_0; qvm::A<1,1>(m_matrix) = m_1_1; qvm::A<1,2>(m_matrix) = m_1_2; qvm::A<1,3>(m_matrix) = m_1_3;
qvm::A<2,0>(m_matrix) = m_2_0; qvm::A<2,1>(m_matrix) = m_2_1; qvm::A<2,2>(m_matrix) = m_2_2; qvm::A<2,3>(m_matrix) = m_2_3;
qvm::A<3,0>(m_matrix) = m_3_0; qvm::A<3,1>(m_matrix) = m_3_1; qvm::A<3,2>(m_matrix) = m_3_2; qvm::A<3,3>(m_matrix) = m_3_3;
}
inline matrix_transformer() {}
template <typename P1, typename P2>
inline bool apply(P1 const& p1, P2& p2) const
{
ct const& c1 = get<0>(p1);
ct const& c2 = get<1>(p1);
ct const& c3 = get<2>(p1);
typedef typename geometry::coordinate_type<P2>::type ct2;
set<0>(p2, boost::numeric_cast<ct2>(
c1 * m_matrix(0,0) + c2 * m_matrix(0,1) + c3 * m_matrix(0,2) + m_matrix(0,3)));
set<1>(p2, boost::numeric_cast<ct2>(
c1 * m_matrix(1,0) + c2 * m_matrix(1,1) + c3 * m_matrix(1,2) + m_matrix(1,3)));
set<2>(p2, boost::numeric_cast<ct2>(
c1 * m_matrix(2,0) + c2 * m_matrix(2,1) + c3 * m_matrix(2,2) + m_matrix(2,3)));
return true;
}
matrix_type const& matrix() const { return m_matrix; }
};
/*!
\brief Strategy of translate transformation in Cartesian system.
\details Translate moves a geometry a fixed distance in 2 or 3 dimensions.
\see http://en.wikipedia.org/wiki/Translation_%28geometry%29
\ingroup strategies
\tparam Dimension1 number of dimensions to transform from
\tparam Dimension2 number of dimensions to transform to
*/
template
<
typename CalculationType,
std::size_t Dimension1,
std::size_t Dimension2
>
class translate_transformer
{
};
template<typename CalculationType>
class translate_transformer<CalculationType, 2, 2> : public matrix_transformer<CalculationType, 2, 2>
{
public :
// To have translate transformers compatible for 2/3 dimensions, the
// constructor takes an optional third argument doing nothing.
inline translate_transformer(CalculationType const& translate_x,
CalculationType const& translate_y,
CalculationType const& = 0)
: matrix_transformer<CalculationType, 2, 2>(
1, 0, translate_x,
0, 1, translate_y,
0, 0, 1)
{}
};
template <typename CalculationType>
class translate_transformer<CalculationType, 3, 3> : public matrix_transformer<CalculationType, 3, 3>
{
public :
inline translate_transformer(CalculationType const& translate_x,
CalculationType const& translate_y,
CalculationType const& translate_z)
: matrix_transformer<CalculationType, 3, 3>(
1, 0, 0, translate_x,
0, 1, 0, translate_y,
0, 0, 1, translate_z,
0, 0, 0, 1)
{}
};
/*!
\brief Strategy of scale transformation in Cartesian system.
\details Scale scales a geometry up or down in all its dimensions.
\see http://en.wikipedia.org/wiki/Scaling_%28geometry%29
\ingroup strategies
\tparam Dimension1 number of dimensions to transform from
\tparam Dimension2 number of dimensions to transform to
*/
template
<
typename CalculationType,
std::size_t Dimension1,
std::size_t Dimension2
>
class scale_transformer
{
};
template <typename CalculationType>
class scale_transformer<CalculationType, 2, 2> : public matrix_transformer<CalculationType, 2, 2>
{
public :
inline scale_transformer(CalculationType const& scale_x,
CalculationType const& scale_y,
CalculationType const& = 0)
: matrix_transformer<CalculationType, 2, 2>(
scale_x, 0, 0,
0, scale_y, 0,
0, 0, 1)
{}
inline scale_transformer(CalculationType const& scale)
: matrix_transformer<CalculationType, 2, 2>(
scale, 0, 0,
0, scale, 0,
0, 0, 1)
{}
};
template <typename CalculationType>
class scale_transformer<CalculationType, 3, 3> : public matrix_transformer<CalculationType, 3, 3>
{
public :
inline scale_transformer(CalculationType const& scale_x,
CalculationType const& scale_y,
CalculationType const& scale_z)
: matrix_transformer<CalculationType, 3, 3>(
scale_x, 0, 0, 0,
0, scale_y, 0, 0,
0, 0, scale_z, 0,
0, 0, 0, 1)
{}
inline scale_transformer(CalculationType const& scale)
: matrix_transformer<CalculationType, 3, 3>(
scale, 0, 0, 0,
0, scale, 0, 0,
0, 0, scale, 0,
0, 0, 0, 1)
{}
};
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template <typename DegreeOrRadian>
struct as_radian
{};
template <>
struct as_radian<radian>
{
template <typename T>
static inline T get(T const& value)
{
return value;
}
};
template <>
struct as_radian<degree>
{
template <typename T>
static inline T get(T const& value)
{
typedef typename promote_floating_point<T>::type promoted_type;
return value * math::d2r<promoted_type>();
}
};
template
<
typename CalculationType,
std::size_t Dimension1,
std::size_t Dimension2
>
class rad_rotate_transformer
: public matrix_transformer<CalculationType, Dimension1, Dimension2>
{
public :
inline rad_rotate_transformer(CalculationType const& angle)
: matrix_transformer<CalculationType, Dimension1, Dimension2>(
cos(angle), sin(angle), 0,
-sin(angle), cos(angle), 0,
0, 0, 1)
{}
};
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
/*!
\brief Strategy for rotate transformation in Cartesian coordinate system.
\details Rotate rotates a geometry of specified angle about a fixed point (e.g. origin).
\see http://en.wikipedia.org/wiki/Rotation_%28mathematics%29
\ingroup strategies
\tparam DegreeOrRadian degree/or/radian, type of rotation angle specification
\note A single angle is needed to specify a rotation in 2D.
Not yet in 3D, the 3D version requires special things to allow
for rotation around X, Y, Z or arbitrary axis.
\todo The 3D version will not compile.
*/
template
<
typename DegreeOrRadian,
typename CalculationType,
std::size_t Dimension1,
std::size_t Dimension2
>
class rotate_transformer : public detail::rad_rotate_transformer<CalculationType, Dimension1, Dimension2>
{
public :
inline rotate_transformer(CalculationType const& angle)
: detail::rad_rotate_transformer
<
CalculationType, Dimension1, Dimension2
>(detail::as_radian<DegreeOrRadian>::get(angle))
{}
};
}} // namespace strategy::transform
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_TRANSFORM_MATRIX_TRANSFORMERS_HPP
@@ -0,0 +1,98 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
#ifndef BOOST_GEOMETRY_STRATEGIES_WITHIN_HPP
#define BOOST_GEOMETRY_STRATEGIES_WITHIN_HPP
#include <boost/mpl/assert.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/tag_cast.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace within
{
namespace services
{
/*!
\brief Traits class binding a within determination strategy to a coordinate system
\ingroup within
\tparam GeometryContained geometry-type of input (possibly) contained type
\tparam GeometryContaining geometry-type of input (possibly) containing type
\tparam TagContained casted tag of (possibly) contained type
\tparam TagContaining casted tag of (possibly) containing type
\tparam CsTagContained tag of coordinate system of (possibly) contained type
\tparam CsTagContaining tag of coordinate system of (possibly) containing type
*/
template
<
typename GeometryContained,
typename GeometryContaining,
typename TagContained = typename tag<GeometryContained>::type,
typename TagContaining = typename tag<GeometryContaining>::type,
typename CastedTagContained = typename tag_cast
<
typename tag<GeometryContained>::type,
pointlike_tag, linear_tag, polygonal_tag, areal_tag
>::type,
typename CastedTagContaining = typename tag_cast
<
typename tag<GeometryContaining>::type,
pointlike_tag, linear_tag, polygonal_tag, areal_tag
>::type,
typename CsTagContained = typename tag_cast
<
typename cs_tag<typename point_type<GeometryContained>::type>::type,
spherical_tag
>::type,
typename CsTagContaining = typename tag_cast
<
typename cs_tag<typename point_type<GeometryContaining>::type>::type,
spherical_tag
>::type
>
struct default_strategy
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_IMPLEMENTED_FOR_THESE_TYPES
, (types<GeometryContained, GeometryContaining>)
);
};
} // namespace services
}} // namespace strategy::within
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_WITHIN_HPP