Added thirdparty: boost library

This commit is contained in:
Viacheslav Demydiuk
2024-01-06 19:55:56 +02:00
parent bf49f439e1
commit bccd1e7051
15683 changed files with 3239840 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
// Boost.Geometry
// Copyright (c) 2020, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_AREA_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_AREA_HPP
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("This include file is deprecated and will be removed in the future.")
#include <boost/geometry/strategy/cartesian/area.hpp>
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_AREA_HPP
@@ -0,0 +1,21 @@
// Boost.Geometry
// Copyright (c) 2020, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_AREA_SURVEYOR_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_AREA_SURVEYOR_HPP
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("This include file is deprecated and will be removed in the future.")
#include <boost/geometry/strategy/cartesian/area.hpp>
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_AREA_SURVEYOR_HPP
+100
View File
@@ -0,0 +1,100 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2016-2021 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 <cmath>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/coordinate_promotion.hpp>
#include <boost/geometry/strategies/azimuth.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace azimuth
{
template <typename CalculationType = void>
class cartesian
{
public:
template <typename T1, typename T2>
struct result_type
: geometry::select_most_precise
<
// NOTE: this promotes any integer type to double
typename geometry::promote_floating_point<T1, double>::type,
typename geometry::promote_floating_point<T2, double>::type,
CalculationType
>
{};
template <typename T1, typename T2, typename Result>
static inline void apply(T1 const& x1, T1 const& y1,
T2 const& x2, T2 const& y2,
Result& a1, Result& a2)
{
compute(x1, y1, x2, y2, a1, a2);
}
template <typename T1, typename T2, typename Result>
static inline void apply(T1 const& x1, T1 const& y1,
T2 const& x2, T2 const& y2,
Result& a1)
{
compute(x1, y1, x2, y2, a1, a1);
}
template <typename T1, typename T2, typename Result>
static inline void apply_reverse(T1 const& x1, T1 const& y1,
T2 const& x2, T2 const& y2,
Result& a2)
{
compute(x1, y1, x2, y2, a2, a2);
}
private:
template <typename T1, typename T2, typename Result>
static inline void compute(T1 const& x1, T1 const& y1,
T2 const& x2, T2 const& y2,
Result& a1, Result& a2)
{
typedef typename result_type<T1, T2>::type calc_t;
// NOTE: azimuth 0 is at Y axis, increasing right
// as in spherical/geographic where 0 is at North axis
a1 = a2 = atan2(calc_t(x2) - calc_t(x1), calc_t(y2) - calc_t(y1));
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <>
struct default_strategy<cartesian_tag>
{
typedef strategy::azimuth::cartesian<> type;
};
}
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::azimuth
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_AZIMUTH_HPP
+367
View File
@@ -0,0 +1,367 @@
// 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-2020.
// Modifications copyright (c) 2016-2020, 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
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
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;
}
};
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 geometry::detail::cs_angular_units<Geometry>::type 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*/;
}
};
template
<
template <typename, std::size_t, typename> class SubStrategy,
typename CSTag,
std::size_t Dimension,
std::size_t DimensionCount
>
struct relate_box_box_loop
{
template <typename Box1, typename Box2>
static inline bool apply(Box1 const& b_contained, Box2 const& b_containing)
{
assert_dimension_equal<Box1, Box2>();
if (! SubStrategy<Box1, Dimension, CSTag>::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 within::detail::relate_box_box_loop
<
SubStrategy, CSTag,
Dimension + 1, DimensionCount
>::apply(b_contained, b_containing);
}
};
template
<
template <typename, std::size_t, typename> class SubStrategy,
typename CSTag,
std::size_t DimensionCount
>
struct relate_box_box_loop<SubStrategy, CSTag, DimensionCount, DimensionCount>
{
template <typename Box1, typename Box2>
static inline bool apply(Box1 const& , Box2 const& )
{
return true;
}
};
template <typename Geometry, std::size_t Dimension, typename CSTag>
struct box_within_range
: within::detail::box_within_coord
{};
template <typename Geometry, std::size_t Dimension, typename CSTag>
struct box_covered_by_range
: within::detail::box_covered_by_coord
{};
// 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>
: within::detail::box_longitude_range
<
Geometry,
within::detail::box_within_coord,
within::detail::box_within_longitude_diff
>
{};
template <typename Geometry>
struct box_covered_by_range<Geometry, 0, spherical_tag>
: within::detail::box_longitude_range
<
Geometry,
within::detail::box_covered_by_coord,
within::detail::box_covered_by_longitude_diff
>
{};
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
struct cartesian_box_box
{
template <typename Box1, typename Box2>
static inline bool apply(Box1 const& box1, Box2 const& box2)
{
return within::detail::relate_box_box_loop
<
within::detail::box_within_range,
cartesian_tag,
0, dimension<Box1>::type::value
>::apply(box1, box2);
}
};
struct spherical_box_box
{
template <typename Box1, typename Box2>
static inline bool apply(Box1 const& box1, Box2 const& box2)
{
return within::detail::relate_box_box_loop
<
within::detail::box_within_range,
spherical_tag,
0, dimension<Box1>::type::value
>::apply(box1, box2);
}
};
} // namespace within
namespace covered_by
{
struct cartesian_box_box
{
template <typename Box1, typename Box2>
static inline bool apply(Box1 const& box1, Box2 const& box2)
{
return within::detail::relate_box_box_loop
<
within::detail::box_covered_by_range,
cartesian_tag,
0, dimension<Box1>::type::value
>::apply(box1, box2);
}
};
struct spherical_box_box
{
template <typename Box1, typename Box2>
static inline bool apply(Box1 const& box1, Box2 const& box2)
{
return within::detail::relate_box_box_loop
<
within::detail::box_covered_by_range,
spherical_tag,
0, dimension<Box1>::type::value
>::apply(box1, box2);
}
};
}
#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 cartesian_box_box 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 spherical_box_box 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 cartesian_box_box 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 spherical_box_box 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,107 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2018.
// Modifications copyright (c) 2018, 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_BUFFER_END_FLAT_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_FLAT_HPP
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/strategies/buffer.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>
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 DistanceStrategy, typename RangeOut>
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
{
auto const dist_left = distance.apply(penultimate_point, ultimate_point, buffer_side_left);
auto const dist_right = distance.apply(penultimate_point, ultimate_point, buffer_side_right);
bool const 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 it is 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,181 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2015 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2015-2023.
// Modifications copyright (c) 2015-2023, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, 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_BUFFER_END_ROUND_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_END_ROUND_HPP
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/access.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>
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;
geometry::set<0>(p, geometry::get<0>(point) + buffer_distance * cos(alpha));
geometry::set<1>(p, geometry::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 Number of points (minimum 4) that would be used for a full circle
explicit inline end_round(std::size_t points_per_circle = default_points_per_circle)
: m_points_per_circle(get_point_count_for_end(points_per_circle))
{}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
//! Fills output_range with a round end
template <typename Point, typename DistanceStrategy, typename RangeOut>
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
{
boost::ignore_unused(perp_left_point);
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);
promoted_type const alpha
= calculate_angle<promoted_type>(penultimate_point, ultimate_point)
- geometry::math::half_pi<promoted_type>();
if (geometry::math::equals(dist_left, dist_right))
{
generate_points(ultimate_point, alpha, dist_left, range_out);
}
else
{
static promoted_type const two = 2.0;
promoted_type const dist_average = (dist_left + dist_right) / two;
promoted_type const dist_half
= (side == buffer_side_right
? (dist_right - dist_left)
: (dist_left - dist_right)) / two;
Point shifted_point;
geometry::set<0>(shifted_point, geometry::get<0>(ultimate_point) + dist_half * cos(alpha));
geometry::set<1>(shifted_point, geometry::get<1>(ultimate_point) + dist_half * sin(alpha));
generate_points(shifted_point, alpha, dist_average, 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)
promoted_type const dx = get<0>(p) - get<0>(vertex);
promoted_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,177 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland.
// 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 Number of points (minimum 4) that would be used for a full circle
explicit inline join_round(std::size_t points_per_circle = default_points_per_circle)
: m_points_per_circle(get_point_count_for_join(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))
{
boost::ignore_unused(ip);
#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_WARN
std::cout << "Corner for equal points " << geometry::wkt(ip) << " " << geometry::wkt(perp1) << std::endl;
#endif
return false;
}
range_out.push_back(perp1);
generate_points<promoted_type>(vertex, perp1, perp2, geometry::math::abs(buffer_distance), 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,152 @@
// 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
{
// Generate 'vectors'
PromotedType const vp1_x = get<0>(p1) - get<0>(vertex);
PromotedType const vp1_y = get<1>(p1) - get<1>(vertex);
PromotedType const vp2_x = (get<0>(p2) - get<0>(vertex));
PromotedType const vp2_y = (get<1>(p2) - get<1>(vertex));
// Average them to generate vector in between
PromotedType const two = 2;
PromotedType const v_x = (vp1_x + vp2_x) / two;
PromotedType const v_y = (vp1_y + vp2_y) / two;
PromotedType const length2 = geometry::math::sqrt(v_x * v_x + v_y * v_y);
PromotedType const 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'
promoted_type const vix = (get<0>(ip) - get<0>(vertex));
promoted_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 const 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,119 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2015 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2015, 2018.
// Modifications copyright (c) 2015, 2018, 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_BUFFER_POINT_CIRCLE_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_POINT_CIRCLE_HPP
#include <cstddef>
#include <boost/range/value_type.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/strategies/buffer.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_most_precise.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]
\* [link geometry.reference.strategies.strategy_buffer_geographic_point_circle geographic_point_circle]
}
*/
class point_circle
{
public :
//! \brief Constructs the strategy
//! \param count Number of points (minimum 3) for the created circle
explicit point_circle(std::size_t count = default_points_per_circle)
: m_count(get_point_count_for_circle(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,117 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2018.
// Modifications copyright (c) 2018, 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_BUFFER_POINT_SQUARE_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_POINT_SQUARE_HPP
#include <cstddef>
#include <boost/range/value_type.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/strategies/buffer.hpp>
#include <boost/geometry/util/math.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]
\* [link geometry.reference.strategies.strategy_buffer_geographic_point_circle geographic_point_circle]
}
*/
class point_square
{
template
<
typename Point,
typename DistanceType,
typename MultiplierType,
typename OutputRange
>
inline void add_point(Point const& point,
DistanceType const& distance,
MultiplierType const& x,
MultiplierType 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,143 @@
// 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
// Returns true if the buffer distance is always the same
static inline bool equidistant()
{
return true;
}
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)
promoted_type const dx = get<0>(input_p2) - get<0>(input_p1);
promoted_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,136 @@
// 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.
// Copyright (c) 2017-2023 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2015-2021.
// Modifications copyright (c) 2015-2021 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/algorithms/detail/signed_size_type.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 Ignored1 = void,
typename Ignored2 = void
>
class average
{
private :
/*! subclass to keep state */
template <typename GeometryPoint, typename ResultPoint>
class sum
{
friend class average;
signed_size_type count;
ResultPoint centroid;
public :
inline sum()
: count(0)
{
assign_zero(centroid);
}
};
public :
template <typename GeometryPoint, typename ResultPoint>
struct state_type
{
typedef sum<GeometryPoint, ResultPoint> type;
};
template <typename GeometryPoint, typename ResultPoint>
static inline void apply(GeometryPoint const& p,
sum<GeometryPoint, ResultPoint>& state)
{
add_point(state.centroid, p);
state.count++;
}
template <typename GeometryPoint, typename ResultPoint>
static inline bool result(sum<GeometryPoint, ResultPoint> const& state,
ResultPoint& centroid)
{
centroid = state.centroid;
if ( state.count > 0 )
{
using coord_t = typename coordinate_type<ResultPoint>::type;
divide_value(centroid, static_cast<coord_t>(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,269 @@
// 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-2021.
// Modifications copyright (c) 2015-2021, 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/numeric/conversion/cast.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/math.hpp>
#include <boost/geometry/util/select_most_precise.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 Ignored1 = void,
typename Ignored2 = void,
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
template <typename GeometryPoint, typename ResultPoint>
struct calculation_type
: std::conditional
<
std::is_void<CalculationType>::value,
typename select_most_precise
<
typename coordinate_type<GeometryPoint>::type,
typename coordinate_type<ResultPoint>::type,
double
>::type,
CalculationType
>
{};
/*! subclass to keep state */
template <typename GeometryPoint, typename ResultPoint>
class sums
{
typedef typename calculation_type<GeometryPoint, ResultPoint>::type calc_type;
friend class bashein_detmer;
std::size_t count;
calc_type sum_a2;
calc_type sum_x;
calc_type sum_y;
public :
inline sums()
: count(0)
, sum_a2(calc_type())
, sum_x(calc_type())
, sum_y(calc_type())
{}
};
public :
template <typename GeometryPoint, typename ResultPoint>
struct state_type
{
typedef sums<GeometryPoint, ResultPoint> type;
};
template <typename GeometryPoint, typename ResultPoint>
static inline void apply(GeometryPoint const& p1, GeometryPoint const& p2,
sums<GeometryPoint, ResultPoint>& 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) )
*/
typedef typename calculation_type<GeometryPoint, ResultPoint>::type calc_type;
// Get coordinates and promote them to calculation_type
calc_type const x1 = boost::numeric_cast<calc_type>(get<0>(p1));
calc_type const y1 = boost::numeric_cast<calc_type>(get<1>(p1));
calc_type const x2 = boost::numeric_cast<calc_type>(get<0>(p2));
calc_type const y2 = boost::numeric_cast<calc_type>(get<1>(p2));
calc_type const ai = geometry::detail::determinant<calc_type>(p1, p2);
state.count++;
state.sum_a2 += ai;
state.sum_x += ai * (x1 + x2);
state.sum_y += ai * (y1 + y2);
}
template <typename GeometryPoint, typename ResultPoint>
static inline bool result(sums<GeometryPoint, ResultPoint> const& state,
ResultPoint& centroid)
{
typedef typename calculation_type<GeometryPoint, ResultPoint>::type calc_type;
calc_type const zero = calc_type();
if (state.count > 0 && ! math::equals(state.sum_a2, zero))
{
calc_type const v3 = 3;
calc_type const a3 = v3 * state.sum_a2;
typedef typename geometry::coordinate_type
<
ResultPoint
>::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,185 @@
// 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-2023.
// Modifications copyright (c) 2015-2023, 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_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/assign.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
// Helper geometry
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp>
#include <boost/geometry/strategies/centroid.hpp>
#include <boost/geometry/util/algorithm.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace centroid
{
template
<
typename Ignored1 = void,
typename Ignored2 = void,
typename CalculationType = void
>
class weighted_length
{
private :
typedef geometry::strategy::distance::pythagoras<CalculationType> pythagoras_strategy;
template <typename GeometryPoint, typename ResultPoint>
struct calculation_type
{
// Below the distance between two GeometryPoints is calculated.
// ResultPoint is taken into account by passing them together here.
typedef typename pythagoras_strategy::template calculation_type
<
GeometryPoint, ResultPoint
>::type type;
};
template <typename GeometryPoint, typename ResultPoint>
class sums
{
friend class weighted_length;
template <typename, typename> friend struct set_sum_div_length;
typedef typename calculation_type<GeometryPoint, ResultPoint>::type calc_type;
typedef typename geometry::model::point
<
calc_type,
geometry::dimension<ResultPoint>::value,
cs::cartesian
> work_point;
calc_type length;
work_point average_sum;
public:
inline sums()
: length(calc_type())
{
geometry::assign_zero(average_sum);
}
};
public :
template <typename GeometryPoint, typename ResultPoint>
struct state_type
{
typedef sums<GeometryPoint, ResultPoint> type;
};
template <typename GeometryPoint, typename ResultPoint>
static inline void apply(GeometryPoint const& p1, GeometryPoint const& p2,
sums<GeometryPoint, ResultPoint>& state)
{
typedef typename calculation_type<GeometryPoint, ResultPoint>::type distance_type;
distance_type const d = pythagoras_strategy::apply(p1, p2);
state.length += d;
distance_type const d_half = d / distance_type(2);
geometry::detail::for_each_dimension<ResultPoint>([&](auto dimension)
{
distance_type const coord1 = get<dimension>(p1);
distance_type const coord2 = get<dimension>(p2);
distance_type const wm = (coord1 + coord2) * d_half; // weighted median
set<dimension>(state.average_sum, get<dimension>(state.average_sum) + wm);
});
}
template <typename GeometryPoint, typename ResultPoint>
static inline bool result(sums<GeometryPoint, ResultPoint> const& state,
ResultPoint& centroid)
{
typedef typename calculation_type<GeometryPoint, ResultPoint>::type distance_type;
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::detail::for_each_dimension<ResultPoint>([&](auto dimension)
{
typedef typename geometry::coordinate_type<ResultPoint>::type coordinate_type;
geometry::set<dimension>(
centroid,
boost::numeric_cast<coordinate_type>(
geometry::get<dimension>(state.average_sum) / state.length
)
);
});
return true;
}
return false;
}
};
#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,146 @@
// Boost.Geometry
// Copyright (c) 2021-2023, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CLOSEST_POINTS_PT_SEG_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CLOSEST_POINTS_PT_SEG_HPP
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/core/coordinate_promotion.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp>
#include <boost/geometry/strategies/closest_points/services.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace closest_points
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template <typename CalculationType>
struct compute_closest_point_to_segment
{
template <typename Point, typename PointOfSegment>
static inline auto
apply(Point const& p, PointOfSegment const& p1, PointOfSegment const& p2)
{
// A projected point of points in Integer coordinates must be able to be
// represented in FP.
using fp_point_type = model::point
<
CalculationType,
dimension<PointOfSegment>::value,
typename coordinate_system<PointOfSegment>::type
>;
// For convenience
using fp_vector_type = fp_point_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);
CalculationType const zero = CalculationType();
CalculationType const c1 = dot_product(w, v);
if (c1 <= zero)
{
fp_vector_type fp_p1;
geometry::convert(p1, fp_p1);
return fp_p1;
}
CalculationType const c2 = dot_product(v, v);
if (c2 <= c1)
{
fp_vector_type fp_p2;
geometry::convert(p2, fp_p2);
return fp_p2;
}
// See above, c1 > 0 AND c2 > c1 so: c2 != 0
CalculationType const b = c1 / c2;
multiply_value(v, b);
add_point(projected, v);
return projected;
}
};
}
#endif // DOXYGEN_NO_DETAIL
template
<
typename CalculationType = void
>
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 select_most_precise
<
typename coordinate_type<Point>::type,
typename coordinate_type<PointOfSegment>::type,
CalculationType
>::type
>
{};
template <typename Point, typename PointOfSegment>
inline auto
apply(Point const& p, PointOfSegment const& p1, PointOfSegment const& p2) const
{
assert_dimension_equal<Point, PointOfSegment>();
using calculation_type = typename calculation_type<Point, PointOfSegment>::type;
return detail::compute_closest_point_to_segment<calculation_type>::apply(p, p1, p2);
}
};
}} // namespace strategy::closest_points
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CLOSEST_POINTS_PT_SEG_HPP
+128
View File
@@ -0,0 +1,128 @@
// Boost.Geometry
// Copyright (c) 2017-2021, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DENSIFY_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DENSIFY_HPP
#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
#include <boost/geometry/algorithms/detail/signed_size_type.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/arithmetic/dot_product.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/strategies/densify.hpp>
#include <boost/geometry/util/algorithm.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace densify
{
/*!
\brief Densification of cartesian segment.
\ingroup strategies
\tparam CalculationType \tparam_calculation
\qbk{
[heading See also]
[link geometry.reference.algorithms.densify.densify_4_with_strategy densify (with strategy)]
}
*/
template
<
typename CalculationType = void
>
class cartesian
{
public:
template <typename Point, typename AssignPolicy, typename T>
static inline void apply(Point const& p0, Point const& p1, AssignPolicy & policy, T const& length_threshold)
{
typedef typename AssignPolicy::point_type out_point_t;
typedef typename coordinate_type<out_point_t>::type out_coord_t;
typedef typename select_most_precise
<
typename coordinate_type<Point>::type, out_coord_t,
CalculationType
>::type calc_t;
typedef model::point<calc_t, geometry::dimension<Point>::value, cs::cartesian> calc_point_t;
assert_dimension_equal<calc_point_t, out_point_t>();
calc_point_t cp0, dir01;
// dir01 = p1 - p0
geometry::detail::for_each_dimension<calc_point_t>([&](auto index)
{
calc_t const coord0 = boost::numeric_cast<calc_t>(get<index>(p0));
calc_t const coord1 = boost::numeric_cast<calc_t>(get<index>(p1));
set<index>(cp0, coord0);
set<index>(dir01, coord1 - coord0);
});
calc_t const dot01 = geometry::dot_product(dir01, dir01);
calc_t const len = math::sqrt(dot01);
BOOST_GEOMETRY_ASSERT(length_threshold > T(0));
signed_size_type const n = signed_size_type(len / length_threshold);
if (n <= 0)
{
return;
}
calc_t const den = calc_t(n + 1);
for (signed_size_type i = 0 ; i < n ; ++i)
{
out_point_t out;
calc_t const num = calc_t(i + 1);
geometry::detail::for_each_dimension<out_point_t>([&](auto index)
{
// out = p0 + d * dir01
calc_t const coord = get<index>(cp0) + get<index>(dir01) * num / den;
set<index>(out, boost::numeric_cast<out_coord_t>(coord));
});
policy.apply(out);
}
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <>
struct default_strategy<cartesian_tag>
{
typedef strategy::densify::cartesian<> type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::densify
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DENSIFY_HPP
@@ -0,0 +1,112 @@
// 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 2013-2018.
// Modifications copyright (c) 2013-2018, 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
// 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_DISJOINT_BOX_BOX_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISJOINT_BOX_BOX_HPP
#include <cstddef>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/strategies/disjoint.hpp>
namespace boost { namespace geometry { namespace strategy { namespace disjoint
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template
<
typename Box1, typename Box2,
std::size_t Dimension = 0,
std::size_t DimensionCount = dimension<Box1>::value
>
struct box_box
{
static inline bool apply(Box1 const& box1, Box2 const& box2)
{
if (get<max_corner, Dimension>(box1) < get<min_corner, Dimension>(box2))
{
return true;
}
if (get<min_corner, Dimension>(box1) > get<max_corner, Dimension>(box2))
{
return true;
}
return box_box
<
Box1, Box2,
Dimension + 1, DimensionCount
>::apply(box1, box2);
}
};
template <typename Box1, typename Box2, std::size_t DimensionCount>
struct box_box<Box1, Box2, DimensionCount, DimensionCount>
{
static inline bool apply(Box1 const& , Box2 const& )
{
return false;
}
};
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
struct cartesian_box_box
{
template <typename Box1, typename Box2>
static inline bool apply(Box1 const& box1, Box2 const& box2)
{
return detail::box_box<Box1, Box2>::apply(box1, box2);
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename Box1, typename Box2, int TopDim1, int TopDim2>
struct default_strategy<Box1, Box2, box_tag, box_tag, TopDim1, TopDim2, cartesian_tag, cartesian_tag>
{
typedef disjoint::cartesian_box_box type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}}}} // namespace boost::geometry::strategy::disjoint
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISJOINT_BOX_BOX_HPP
@@ -0,0 +1,309 @@
// 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-2019.
// Modifications copyright (c) 2013-2019, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// 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_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/cartesian/point_in_box.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
{
typedef covered_by::cartesian_point_box disjoint_point_box_strategy_type;
static inline disjoint_point_box_strategy_type get_disjoint_point_box_strategy()
{
return disjoint_point_box_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
{
template <typename Linear, typename Box, typename LinearTag>
struct default_strategy<Linear, Box, LinearTag, box_tag, 1, 2, cartesian_tag, cartesian_tag>
{
typedef disjoint::segment_box type;
};
template <typename Box, typename Linear, typename LinearTag>
struct default_strategy<Box, Linear, box_tag, LinearTag, 2, 1, cartesian_tag, cartesian_tag>
{
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,236 @@
// 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-2021.
// Modifications copyright (c) 2014-2021, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// 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_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PROJECTED_POINT_HPP
#include <type_traits>
#include <boost/concept_check.hpp>
#include <boost/core/ignore_unused.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/closest_points_pt_seg.hpp>
#include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp>
#include <boost/geometry/strategies/cartesian/point_in_point.hpp>
#include <boost/geometry/strategies/cartesian/intersection.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
>
{};
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;
auto closest_point = closest_points::detail::compute_closest_point_to_segment
<calculation_type>::apply(p, p1, p2);
return Strategy().apply(p, closest_point);
}
template <typename CT>
inline CT vertical_or_meridian(CT const& lat1, CT const& lat2) const
{
return lat1 - lat2;
}
};
#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,
std::conditional_t
<
std::is_void<Strategy>::value,
typename default_strategy
<
point_tag, point_tag, Point, PointOfSegment,
cartesian_tag, cartesian_tag
>::type,
Strategy
>
> 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,315 @@
// 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/core/ignore_unused.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(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,295 @@
// 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.
// This file was modified by Oracle on 2018.
// Modifications copyright (c) 2018, 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_DISTANCE_PYTHAGORAS_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_HPP
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/geometries/concepts/point_concept.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,341 @@
// 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, 2018.
// Modifications copyright (c) 2014, 2018, 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_PYTHAGORAS_BOX_BOX_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_BOX_BOX_HPP
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/geometries/concepts/point_concept.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,353 @@
// 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, 2018.
// Modifications copyright (c) 2014, 2018, 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_PYTHAGORAS_POINT_BOX_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_POINT_BOX_HPP
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/geometries/concepts/point_concept.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,183 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2018-2021 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_DISTANCE_SEGMENT_BOX_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_SEGMENT_BOX_HPP
#include <boost/geometry/algorithms/detail/distance/segment_to_box.hpp>
#include <boost/geometry/strategies/cartesian/distance_projected_point.hpp>
#include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp>
#include <boost/geometry/strategies/cartesian/distance_pythagoras_point_box.hpp>
#include <boost/geometry/strategies/cartesian/point_in_point.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace distance
{
template
<
typename CalculationType = void,
typename Strategy = pythagoras<CalculationType>
>
struct cartesian_segment_box
{
template <typename PointOfSegment, typename PointOfBox>
struct calculation_type
: promote_floating_point
<
typename strategy::distance::services::return_type
<
Strategy,
PointOfSegment,
PointOfBox
>::type
>
{};
typedef cartesian_tag cs_tag;
template
<
typename LessEqual, typename ReturnType,
typename SegmentPoint, typename BoxPoint,
typename Strategies
>
inline ReturnType segment_below_of_box(SegmentPoint const& p0,
SegmentPoint const& p1,
BoxPoint const&,
BoxPoint const&,
BoxPoint const&,
BoxPoint const& bottom_right,
Strategies const& strategies) const
{
// TODO: The strategy should not call the algorithm like that
return geometry::detail::distance::segment_to_box_2D
<
ReturnType,
SegmentPoint,
BoxPoint,
Strategies
>::template call_above_of_box
<
typename LessEqual::other
>(p1, p0, bottom_right, strategies);
}
template <typename SPoint, typename BPoint>
static void mirror(SPoint&,
SPoint&,
BPoint&,
BPoint&,
BPoint&,
BPoint&)
{}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename CalculationType, typename Strategy>
struct tag<cartesian_segment_box<CalculationType, Strategy> >
{
typedef strategy_tag_distance_segment_box type;
};
template <typename CalculationType, typename Strategy, typename PS, typename PB>
struct return_type<cartesian_segment_box<CalculationType, Strategy>, PS, PB>
: cartesian_segment_box<CalculationType, Strategy>::template calculation_type<PS, PB>
{};
template <typename CalculationType, typename Strategy>
struct comparable_type<cartesian_segment_box<CalculationType, Strategy> >
{
// Define a cartesian_segment_box strategy with its underlying point-point
// strategy being comparable
typedef cartesian_segment_box
<
CalculationType,
typename comparable_type<Strategy>::type
> type;
};
template <typename CalculationType, typename Strategy>
struct get_comparable<cartesian_segment_box<CalculationType, Strategy> >
{
typedef typename comparable_type
<
cartesian_segment_box<CalculationType, Strategy>
>::type comparable_type;
public :
static inline comparable_type apply(cartesian_segment_box<CalculationType, Strategy> const& )
{
return comparable_type();
}
};
template <typename CalculationType, typename Strategy, typename PS, typename PB>
struct result_from_distance<cartesian_segment_box<CalculationType, Strategy>, PS, PB>
{
private :
typedef typename return_type<
cartesian_segment_box
<
CalculationType,
Strategy
>,
PS,
PB
>::type return_type;
public :
template <typename T>
static inline return_type apply(cartesian_segment_box<CalculationType,
Strategy> const& ,
T const& value)
{
Strategy s;
return result_from_distance<Strategy, PS, PB>::apply(s, value);
}
};
template <typename Segment, typename Box>
struct default_strategy
<
segment_tag, box_tag, Segment, Box,
cartesian_tag, cartesian_tag
>
{
typedef cartesian_segment_box<> type;
};
template <typename Box, typename Segment>
struct default_strategy
<
box_tag, segment_tag, Box, Segment,
cartesian_tag, cartesian_tag
>
{
typedef typename default_strategy
<
segment_tag, box_tag, Segment, Box,
cartesian_tag, cartesian_tag
>::type type;
};
}
#endif
}} // namespace strategy::distance
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_SEGMENT_BOX_HPP
+21
View File
@@ -0,0 +1,21 @@
// Boost.Geometry
// Copyright (c) 2020, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_ENVELOPE_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_ENVELOPE_HPP
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("This include file is deprecated and will be removed in the future.")
#include <boost/geometry/strategy/cartesian/envelope.hpp>
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_ENVELOPE_HPP
+21
View File
@@ -0,0 +1,21 @@
// Boost.Geometry
// Copyright (c) 2020, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_ENVELOPE_BOX_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_ENVELOPE_BOX_HPP
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("This include file is deprecated and will be removed in the future.")
#include <boost/geometry/strategy/cartesian/envelope_box.hpp>
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_ENVELOPE_BOX_HPP
@@ -0,0 +1,21 @@
// Boost.Geometry
// Copyright (c) 2020, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_ENVELOPE_MULTIPOINT_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_ENVELOPE_MULTIPOINT_HPP
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("This include file is deprecated and will be removed in the future.")
#include <boost/geometry/strategy/cartesian/envelope_multipoint.hpp>
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_ENVELOPE_MULTIPOINT_HPP
@@ -0,0 +1,21 @@
// Boost.Geometry
// Copyright (c) 2020, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_ENVELOPE_POINT_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_ENVELOPE_POINT_HPP
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("This include file is deprecated and will be removed in the future.")
#include <boost/geometry/strategy/cartesian/envelope_point.hpp>
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_ENVELOPE_POINT_HPP
@@ -0,0 +1,21 @@
// Boost.Geometry
// Copyright (c) 2020, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_ENVELOPE_SEGMENT_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_ENVELOPE_SEGMENT_HPP
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("This include file is deprecated and will be removed in the future.")
#include <boost/geometry/strategy/cartesian/envelope_segment.hpp>
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_ENVELOPE_SEGMENT_HPP
+21
View File
@@ -0,0 +1,21 @@
// Boost.Geometry
// Copyright (c) 2020, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_EXPAND_BOX_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_EXPAND_BOX_HPP
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("This include file is deprecated and will be removed in the future.")
#include <boost/geometry/strategy/cartesian/expand_box.hpp>
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_EXPAND_BOX_HPP
+21
View File
@@ -0,0 +1,21 @@
// Boost.Geometry
// Copyright (c) 2020, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_EXPAND_POINT_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_EXPAND_POINT_HPP
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("This include file is deprecated and will be removed in the future.")
#include <boost/geometry/strategy/cartesian/expand_point.hpp>
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_EXPAND_POINT_HPP
@@ -0,0 +1,21 @@
// Boost.Geometry
// Copyright (c) 2020, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_EXPAND_SEGMENT_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_EXPAND_SEGMENT_HPP
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("This include file is deprecated and will be removed in the future.")
#include <boost/geometry/strategy/cartesian/expand_segment.hpp>
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_EXPAND_SEGMENT_HPP
+850
View File
@@ -0,0 +1,850 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2013-2023 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2014-2021.
// Modifications copyright (c) 2014-2021, 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/geometries/segment.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/strategy/cartesian/area.hpp>
#include <boost/geometry/strategy/cartesian/envelope.hpp>
#include <boost/geometry/strategy/cartesian/expand_box.hpp>
#include <boost/geometry/strategy/cartesian/expand_segment.hpp>
#include <boost/geometry/strategies/cartesian/disjoint_box_box.hpp>
#include <boost/geometry/strategies/cartesian/disjoint_segment_box.hpp>
#include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp>
#include <boost/geometry/strategies/cartesian/point_in_point.hpp>
#include <boost/geometry/strategies/cartesian/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/within.hpp>
#include <boost/geometry/policies/robustness/rescale_policy_tags.hpp>
#include <boost/geometry/policies/robustness/robust_point_type.hpp>
#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
# include <boost/geometry/io/wkt/write.hpp>
#endif
namespace boost { namespace geometry
{
namespace strategy { namespace intersection
{
namespace detail_usage
{
// When calculating the intersection, the information of "a" or "b" can be used.
// Theoretically this gives equal results, but due to floating point precision
// there might be tiny differences. These are edge cases.
// This structure is to determine if "a" or "b" should be used.
// Prefer the segment closer to the endpoint.
// If both are about equally close, then prefer the longer segment
// To avoid hard thresholds, behavior is made fluent.
// Calculate comparable length indications,
// the longer the segment (relatively), the lower the value
// such that the shorter lengths are evaluated higher and will
// be preferred.
template <bool IsArithmetic>
struct use_a
{
template <typename Ct, typename Ev>
static bool apply(Ct const& cla, Ct const& clb, Ev const& eva, Ev const& evb)
{
auto const clm = (std::max)(cla, clb);
if (clm <= 0)
{
return true;
}
// Relative comparible length
auto const rcla = Ct(1.0) - cla / clm;
auto const rclb = Ct(1.0) - clb / clm;
// Multipliers for edgevalue (ev) and relative comparible length (rcl)
// They determine the balance between edge value (should be larger)
// and segment length. In 99.9xx% of the cases there is no difference
// at all (if either a or b is used). Therefore the values of the
// constants are not sensitive for the majority of the situations.
// One known case is #mysql_23023665_6 (difference) which needs mev >= 2
Ev const mev = 5;
Ev const mrcl = 1;
return mev * eva + mrcl * rcla > mev * evb + mrcl * rclb;
}
};
// Specialization for non arithmetic types. They will always use "a"
template <>
struct use_a<false>
{
template <typename Ct, typename Ev>
static bool apply(Ct const& , Ct const& , Ev const& , Ev const& )
{
return true;
}
};
}
/*!
\see http://mathworld.wolfram.com/Line-LineIntersection.html
*/
template
<
typename CalculationType = void
>
struct cartesian_segments
{
typedef cartesian_tag cs_tag;
template <typename CoordinateType, typename SegmentRatio>
struct segment_intersection_info
{
private :
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
// The division, postponed until here, is done now. In case of integer this
// results in an integer which rounds to the nearest integer.
BOOST_GEOMETRY_ASSERT(ratio.denominator() != typename SegmentRatio::int_type(0));
typedef typename promote_integral<CoordinateType>::type calc_type;
calc_type const numerator
= boost::numeric_cast<calc_type>(ratio.numerator());
calc_type const denominator
= boost::numeric_cast<calc_type>(ratio.denominator());
calc_type const dx_calc = boost::numeric_cast<calc_type>(dx);
calc_type const dy_calc = boost::numeric_cast<calc_type>(dy);
set<0>(point, get<0, 0>(segment)
+ boost::numeric_cast<CoordinateType>(
math::divide<calc_type>(numerator * dx_calc, denominator)));
set<1>(point, get<0, 1>(segment)
+ boost::numeric_cast<CoordinateType>(
math::divide<calc_type>(numerator * dy_calc, denominator)));
}
template <int Index, int Dim, typename Point, typename Segment>
static bool exceeds_side_in_dimension(Point& p, Segment const& s)
{
// Situation a (positive)
// 0>-------------->1 segment
// * point left of segment<I> in D x or y
// Situation b (negative)
// 1<--------------<0 segment
// * point right of segment<I>
// Situation c (degenerate), return false (check other dimension)
auto const& c = get<Dim>(p);
auto const& c0 = get<Index, Dim>(s);
auto const& c1 = get<1 - Index, Dim>(s);
return c0 < c1 ? math::smaller(c, c0)
: c0 > c1 ? math::larger(c, c0)
: false;
}
template <int Index, typename Point, typename Segment>
static bool exceeds_side_of_segment(Point& p, Segment const& s)
{
return exceeds_side_in_dimension<Index, 0>(p, s)
|| exceeds_side_in_dimension<Index, 1>(p, s);
}
template <typename Point, typename Segment>
static void assign_if_exceeds(Point& point, Segment const& s)
{
if (exceeds_side_of_segment<0>(point, s))
{
detail::assign_point_from_index<0>(s, point);
}
else if (exceeds_side_of_segment<1>(point, s))
{
detail::assign_point_from_index<1>(s, point);
}
}
public :
template <typename Point, typename Segment1, typename Segment2>
void calculate(Point& point, Segment1 const& a, Segment2 const& b) const
{
bool const use_a
= detail_usage::use_a
<
std::is_arithmetic<CoordinateType>::value
>::apply(comparable_length_a(), comparable_length_b(),
robust_ra.edge_value(), robust_rb.edge_value());
if (use_a)
{
assign_a(point, a, b);
}
else
{
assign_b(point, a, b);
}
#ifndef BOOST_GEOMETRY_USE_RESCALING
// Verify nearly collinear cases (the threshold is arbitrary
// but influences performance). If the intersection is located
// outside the segments, then it should be moved.
if (robust_ra.possibly_collinear(1.0e-3)
&& robust_rb.possibly_collinear(1.0e-3))
{
// The segments are nearly collinear and because of the calculation
// method with very small denominator, the IP appears outside the
// segment(s). Correct it to the end point.
// Because they are nearly collinear, it doesn't really matter to
// to which endpoint (or it is corrected twice).
assign_if_exceeds(point, a);
assign_if_exceeds(point, b);
}
#endif
}
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& nominator, ResultType& denominator)
{
// Cramers rule
nominator = geometry::detail::determinant<ResultType>(dx_b, dy_b, wx, wy);
denominator = geometry::detail::determinant<ResultType>(dx_a, dy_a, dx_b, dy_b);
// Ratio r = nominator/denominator
// Collinear if denominator == 0, intersecting if 0 <= r <= 1
// IntersectionPoint = (x1 + r * dx_a, y1 + r * dy_a)
}
// Version for non-rescaled policies
template
<
typename UniqueSubRange1,
typename UniqueSubRange2,
typename Policy
>
static inline typename Policy::return_type
apply(UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
Policy const& policy)
{
// Pass the same ranges both as normal ranges and as modelled ranges
return apply(range_p, range_q, policy, range_p, range_q);
}
// Version for non rescaled versions.
// The "modelled" parameter might be rescaled (will be removed later)
template
<
typename UniqueSubRange1,
typename UniqueSubRange2,
typename Policy,
typename ModelledUniqueSubRange1,
typename ModelledUniqueSubRange2
>
static inline typename Policy::return_type
apply(UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
Policy const& policy,
ModelledUniqueSubRange1 const& modelled_range_p,
ModelledUniqueSubRange2 const& modelled_range_q)
{
typedef typename UniqueSubRange1::point_type point1_type;
typedef typename UniqueSubRange2::point_type point2_type;
BOOST_CONCEPT_ASSERT( (concepts::ConstPoint<point1_type>) );
BOOST_CONCEPT_ASSERT( (concepts::ConstPoint<point2_type>) );
point1_type const& p1 = range_p.at(0);
point1_type const& p2 = range_p.at(1);
point2_type const& q1 = range_q.at(0);
point2_type const& q2 = range_q.at(1);
// Declare segments, currently necessary for the policies
// (segment_crosses, segment_colinear, degenerate, one_degenerate, etc)
model::referring_segment<point1_type const> const p(p1, p2);
model::referring_segment<point2_type const> const q(q1, q2);
typedef typename select_most_precise
<
typename geometry::coordinate_type<typename ModelledUniqueSubRange1::point_type>::type,
typename geometry::coordinate_type<typename ModelledUniqueSubRange1::point_type>::type
>::type modelled_coordinate_type;
typedef segment_ratio<modelled_coordinate_type> ratio_type;
segment_intersection_info
<
typename select_calculation_type<point1_type, point2_type, CalculationType>::type,
ratio_type
> sinfo;
sinfo.dx_a = get<0>(p2) - get<0>(p1); // distance in x-dir
sinfo.dx_b = get<0>(q2) - get<0>(q1);
sinfo.dy_a = get<1>(p2) - get<1>(p1); // distance in y-dir
sinfo.dy_b = get<1>(q2) - get<1>(q1);
return unified<ratio_type>(sinfo, p, q, policy, modelled_range_p, modelled_range_q);
}
//! Returns true if two segments do not overlap.
//! If not, then no further calculations need to be done.
template
<
std::size_t Dimension,
typename PointP,
typename PointQ
>
static inline bool disjoint_by_range(PointP const& p1, PointP const& p2,
PointQ const& q1, PointQ const& q2)
{
auto minp = get<Dimension>(p1);
auto maxp = get<Dimension>(p2);
auto minq = get<Dimension>(q1);
auto maxq = get<Dimension>(q2);
if (minp > maxp)
{
std::swap(minp, maxp);
}
if (minq > maxq)
{
std::swap(minq, maxq);
}
// In this case, max(p) < min(q)
// P Q
// <-------> <------->
// (and the space in between is not extremely small)
return math::smaller(maxp, minq) || math::smaller(maxq, minp);
}
// Implementation for either rescaled or non rescaled versions.
template
<
typename RatioType,
typename SegmentInfo,
typename Segment1,
typename Segment2,
typename Policy,
typename UniqueSubRange1,
typename UniqueSubRange2
>
static inline typename Policy::return_type
unified(SegmentInfo& sinfo,
Segment1 const& p, Segment2 const& q, Policy const&,
UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q)
{
typedef typename UniqueSubRange1::point_type point1_type;
typedef typename UniqueSubRange2::point_type point2_type;
typedef typename select_most_precise
<
typename geometry::coordinate_type<point1_type>::type,
typename geometry::coordinate_type<point2_type>::type
>::type coordinate_type;
point1_type const& p1 = range_p.at(0);
point1_type const& p2 = range_p.at(1);
point2_type const& q1 = range_q.at(0);
point2_type const& q2 = range_q.at(1);
bool const p_is_point = equals_point_point(p1, p2);
bool const q_is_point = equals_point_point(q1, q2);
if (p_is_point && q_is_point)
{
return equals_point_point(p1, q2)
? Policy::degenerate(p, true)
: Policy::disjoint()
;
}
if (disjoint_by_range<0>(p1, p2, q1, q2)
|| disjoint_by_range<1>(p1, p2, q1, q2))
{
return Policy::disjoint();
}
using side_strategy_type
= typename side::services::default_strategy
<cartesian_tag, CalculationType>::type;
side_info sides;
sides.set<0>(side_strategy_type::apply(q1, q2, p1),
side_strategy_type::apply(q1, q2, p2));
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(p1, p2, q1),
side_strategy_type::apply(p1, p2, q2));
if (sides.same<1>())
{
// Both points are at same side of other segment, we can leave
return Policy::disjoint();
}
bool collinear = sides.collinear();
// Calculate the differences again
// (for rescaled version, this is different from dx_p etc)
coordinate_type const dx_p = get<0>(p2) - get<0>(p1);
coordinate_type const dx_q = get<0>(q2) - get<0>(q1);
coordinate_type const dy_p = get<1>(p2) - get<1>(p1);
coordinate_type const dy_q = get<1>(q2) - get<1>(q1);
// r: ratio 0-1 where intersection divides A/B
// (only calculated for non-collinear segments)
if (! collinear)
{
coordinate_type denominator_a, nominator_a;
coordinate_type denominator_b, nominator_b;
cramers_rule(dx_p, dy_p, dx_q, dy_q,
get<0>(p1) - get<0>(q1),
get<1>(p1) - get<1>(q1),
nominator_a, denominator_a);
cramers_rule(dx_q, dy_q, dx_p, dy_p,
get<0>(q1) - get<0>(p1),
get<1>(q1) - get<1>(p1),
nominator_b, denominator_b);
math::detail::equals_factor_policy<coordinate_type>
policy(dx_p, dy_p, dx_q, dy_q);
coordinate_type const zero = 0;
if (math::detail::equals_by_policy(denominator_a, zero, policy)
|| math::detail::equals_by_policy(denominator_b, 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(nominator_a, denominator_a);
sinfo.robust_rb.assign(nominator_b, denominator_b);
}
}
if (collinear)
{
std::pair<bool, bool> const collinear_use_first
= is_x_more_significant(geometry::math::abs(dx_p),
geometry::math::abs(dy_p),
geometry::math::abs(dx_q),
geometry::math::abs(dy_q),
p_is_point, q_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, RatioType>(p, q,
p1, p2, q1, q2,
p_is_point, q_is_point);
}
else
{
// Y direction contains larger segments (maybe dx is zero)
return relate_collinear<1, Policy, RatioType>(p, q,
p1, p2, q1, q2,
p_is_point, q_is_point);
}
}
}
return Policy::segments_crosses(sides, sinfo, p, q);
}
private:
// first is true if x is more significant
// second is true if the more significant difference is not 0
template <typename CoordinateType>
static inline std::pair<bool, bool>
is_x_more_significant(CoordinateType const& abs_dx_a,
CoordinateType const& abs_dy_a,
CoordinateType const& abs_dx_b,
CoordinateType const& abs_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_dx_b >= abs_dy_b, true);
}
else if (b_is_point)
{
return std::make_pair(abs_dx_a >= abs_dy_a, true);
}
else
{
CoordinateType const min_dx = (std::min)(abs_dx_a, abs_dx_b);
CoordinateType const min_dy = (std::min)(abs_dy_a, abs_dy_b);
return min_dx == min_dy ?
std::make_pair(true, min_dx > CoordinateType(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 Type1,
typename Type2
>
static inline typename Policy::return_type
relate_collinear(Segment1 const& a, Segment2 const& b,
Type1 oa_1, Type1 oa_2,
Type2 ob_1, Type2 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)
Type1 const length_a = oa_2 - oa_1; // no abs, see above
Type2 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 Type1,
typename Type2
>
static inline typename Policy::return_type
relate_one_degenerate(DegenerateSegment const& degenerate_segment,
Type1 d, Type2 s1, Type2 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 );
}
template <typename Point1, typename Point2>
static inline bool equals_point_point(Point1 const& point1, Point2 const& point2)
{
return strategy::within::cartesian_point_point::apply(point1, point2);
}
};
#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,99 @@
// Boost.Geometry
// Copyright (c) 2018-2021, 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
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_LINE_INTERPOLATE_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_LINE_INTERPOLATE_HPP
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/strategies/line_interpolate.hpp>
#include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp>
#include <boost/geometry/util/algorithm.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace line_interpolate
{
/*!
\brief Interpolate point on a cartesian segment.
\ingroup strategies
\tparam CalculationType \tparam_calculation
\tparam DistanceStrategy The underlying point-point distance strategy
\qbk{
[heading See also]
\* [link geometry.reference.algorithms.line_interpolate.line_interpolate_4_with_strategy line_interpolate (with strategy)]
}
*/
template
<
typename CalculationType = void,
typename DistanceStrategy = distance::pythagoras<CalculationType>
>
class cartesian
{
public:
template <typename Point, typename Fraction, typename Distance>
inline void apply(Point const& p0,
Point const& p1,
Fraction const& fraction,
Point & p,
Distance const&) const
{
typedef typename select_calculation_type_alt
<
CalculationType, Point
>::type calc_t;
typedef typename coordinate_type<Point>::type coord_t;
//segment convex combination: p0*fraction + p1*(1-fraction)
Fraction const one_minus_fraction = 1-fraction;
geometry::detail::for_each_dimension<Point>([&](auto dimension)
{
// NOTE: numeric_cast is a leftover from convert, it could probably be ommited.
// NOTE: the order of points is different than in the formula above
// this is also a leftover from the previous implementation
calc_t coord0 = boost::numeric_cast<calc_t>(get<dimension>(p0));
calc_t coord1 = boost::numeric_cast<calc_t>(get<dimension>(p1));
calc_t result = calc_t(coord1 * fraction) + calc_t(coord0 * one_minus_fraction);
set<dimension>(p, boost::numeric_cast<coord_t>(result));
});
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <>
struct default_strategy<cartesian_tag>
{
typedef strategy::line_interpolate::cartesian<> type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::line_interpolate
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_LINE_INTERPOLATE_HPP
+332
View File
@@ -0,0 +1,332 @@
// 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-2018.
// Modifications copyright (c) 2015-2018, 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/core/cs.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
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
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 geometry::detail::cs_angular_units<Geometry>::type 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 CSTag, // cartesian_tag or spherical_tag
std::size_t Dimension,
std::size_t DimensionCount
>
struct relate_point_box_loop
{
template <typename Point, typename Box>
static inline bool apply(Point const& point, Box const& box)
{
if (! SubStrategy<Point, Dimension, CSTag>::apply(get<Dimension>(point),
get<min_corner, Dimension>(box),
get<max_corner, Dimension>(box))
)
{
return false;
}
return relate_point_box_loop
<
SubStrategy,
CSTag,
Dimension + 1, DimensionCount
>::apply(point, box);
}
};
template
<
template <typename, std::size_t, typename> class SubStrategy,
typename CSTag,
std::size_t DimensionCount
>
struct relate_point_box_loop<SubStrategy, CSTag, DimensionCount, DimensionCount>
{
template <typename Point, typename Box>
static inline bool apply(Point const& , Box const& )
{
return true;
}
};
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
struct cartesian_point_box
{
template <typename Point, typename Box>
static inline bool apply(Point const& point, Box const& box)
{
return detail::relate_point_box_loop
<
detail::within_range,
cartesian_tag,
0, dimension<Point>::value
>::apply(point, box);
}
};
struct spherical_point_box
{
template <typename Point, typename Box>
static inline bool apply(Point const& point, Box const& box)
{
return detail::relate_point_box_loop
<
detail::within_range,
spherical_tag,
0, dimension<Point>::value
>::apply(point, box);
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
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::cartesian_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::spherical_point_box type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
} // namespace within
namespace covered_by
{
struct cartesian_point_box
{
template <typename Point, typename Box>
static inline bool apply(Point const& point, Box const& box)
{
return within::detail::relate_point_box_loop
<
within::detail::covered_by_range,
cartesian_tag,
0, dimension<Point>::value
>::apply(point, box);
}
};
struct spherical_point_box
{
template <typename Point, typename Box>
static inline bool apply(Point const& point, Box const& box)
{
return within::detail::relate_point_box_loop
<
within::detail::covered_by_range,
spherical_tag,
0, dimension<Point>::value
>::apply(point, box);
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
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 covered_by::cartesian_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 covered_by::spherical_point_box type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
} // namespace covered_by
}}} // namespace boost::geometry::strategy
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_IN_BOX_HPP
+126
View File
@@ -0,0 +1,126 @@
// 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 2013, 2014, 2015, 2017, 2018, 2019.
// Modifications copyright (c) 2013-2019, 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
// 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_CARTESIAN_POINT_IN_POINT_HPP
#define BOOST_GEOMETRY_STRATEGY_CARTESIAN_POINT_IN_POINT_HPP
#include <cstddef>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/within.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace within
{
template <std::size_t Dimension, std::size_t DimensionCount>
struct point_point_generic
{
template <typename Point1, typename Point2>
static inline bool apply(Point1 const& p1, Point2 const& p2)
{
if (! geometry::math::equals(get<Dimension>(p1), get<Dimension>(p2)))
{
return false;
}
return
point_point_generic<Dimension + 1, DimensionCount>::apply(p1, p2);
}
};
template <std::size_t DimensionCount>
struct point_point_generic<DimensionCount, DimensionCount>
{
template <typename Point1, typename Point2>
static inline bool apply(Point1 const&, Point2 const& )
{
return true;
}
};
}} // namespace detail::within
#endif // DOXYGEN_NO_DETAIL
namespace strategy { namespace within
{
struct cartesian_point_point
{
typedef cartesian_tag cs_tag;
template <typename Point1, typename Point2>
static inline bool apply(Point1 const& point1, Point2 const& point2)
{
return geometry::detail::within::point_point_generic
<
0, dimension<Point1>::type::value
>::apply(point1, point2);
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename PointLike1, typename PointLike2, typename Tag1, typename Tag2>
struct default_strategy<PointLike1, PointLike2, Tag1, Tag2, pointlike_tag, pointlike_tag, cartesian_tag, cartesian_tag>
{
typedef strategy::within::cartesian_point_point type;
};
} // namespace services
#endif
}} // namespace strategy::within
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace strategy { namespace covered_by { namespace services
{
template <typename PointLike1, typename PointLike2, typename Tag1, typename Tag2>
struct default_strategy<PointLike1, PointLike2, Tag1, Tag2, pointlike_tag, pointlike_tag, cartesian_tag, cartesian_tag>
{
typedef strategy::within::cartesian_point_point type;
};
}}} // namespace strategy::covered_by::services
#endif
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGY_CARTESIAN_POINT_IN_POINT_HPP
@@ -0,0 +1,134 @@
// 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 2018, 2019.
// Modifications copyright (c) 2018, 2019, 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_POLY_CROSSINGS_MULTIPLY_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_IN_POLY_CROSSINGS_MULTIPLY_HPP
#include <boost/geometry/core/access.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_, // for backward compatibility
typename PointOfSegment_ = Point_, // for backward compatibility
typename CalculationType = void
>
class crossings_multiply
{
template <typename Point, typename PointOfSegment>
struct calculation_type
: select_calculation_type
<
Point,
PointOfSegment,
CalculationType
>
{};
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 flags state_type;
template <typename Point, typename PointOfSegment>
static inline bool apply(Point const& point,
PointOfSegment const& seg1, PointOfSegment const& seg2,
flags& state)
{
typedef typename calculation_type<Point, PointOfSegment>::type calc_t;
calc_t const tx = get<0>(point);
calc_t const ty = get<1>(point);
calc_t const x0 = get<0>(seg1);
calc_t const y0 = get<1>(seg1);
calc_t const x1 = get<0>(seg2);
calc_t 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,128 @@
// 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 2018, 2019.
// Modifications copyright (c) 2018, 2019, 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_POLY_FRANKLIN_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_IN_POLY_FRANKLIN_HPP
#include <boost/geometry/core/access.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_, // for backward compatibility
typename PointOfSegment_ = Point_, // for backward compatibility
typename CalculationType = void
>
class franklin
{
template <typename Point, typename PointOfSegment>
struct calculation_type
: select_calculation_type
<
Point,
PointOfSegment,
CalculationType
>
{};
/*! subclass to keep state */
class crossings
{
bool crosses;
public :
friend class franklin;
inline crossings()
: crosses(false)
{}
};
public :
typedef crossings state_type;
template <typename Point, typename PointOfSegment>
static inline bool apply(Point const& point,
PointOfSegment const& seg1, PointOfSegment const& seg2,
crossings& state)
{
typedef typename calculation_type<Point, PointOfSegment>::type calc_t;
calc_t const& px = get<0>(point);
calc_t const& py = get<1>(point);
calc_t const& x1 = get<0>(seg1);
calc_t const& y1 = get<1>(seg1);
calc_t const& x2 = get<0>(seg2);
calc_t 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,297 @@
// 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-2021.
// Modifications copyright (c) 2013-2021 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_CARTESIAN_POINT_IN_POLY_WINDING_HPP
#define BOOST_GEOMETRY_STRATEGY_CARTESIAN_POINT_IN_POLY_WINDING_HPP
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/strategy/cartesian/expand_point.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/strategies/cartesian/point_in_box.hpp>
#include <boost/geometry/strategies/cartesian/disjoint_box_box.hpp>
#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/within.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace within
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
/*!
\brief Within detection using winding rule in cartesian coordinate system.
\ingroup strategies
\tparam SideStrategy A strategy defining creation along sides
\tparam CalculationType \tparam_calculation
*/
template <typename SideStrategy, typename CalculationType>
class cartesian_winding_base
{
template <typename Point, typename PointOfSegment>
struct calculation_type
: select_calculation_type
<
Point,
PointOfSegment,
CalculationType
>
{};
/*! 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 cartesian_winding_base;
inline counter()
: m_count(0)
, m_touches(false)
{}
};
public:
typedef cartesian_tag cs_tag;
// Typedefs and static methods to fulfill the concept
typedef counter state_type;
template <typename Point, typename PointOfSegment>
static inline bool apply(Point const& point,
PointOfSegment const& s1, PointOfSegment const& s2,
counter& state)
{
bool eq1 = false;
bool eq2 = false;
int count = check_segment(point, s1, s2, state, eq1, eq2);
if (count != 0)
{
int side = 0;
if (count == 1 || count == -1)
{
side = side_equal(point, eq1 ? s1 : s2, count);
}
else // count == 2 || count == -2
{
// 1 left, -1 right
side = SideStrategy::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 left, 2 for right (or -1/1)
// Side positive thus means RIGHT and LEFTSIDE or LEFT 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:
template <typename Point, typename PointOfSegment>
static inline int check_segment(Point const& point,
PointOfSegment const& seg1,
PointOfSegment const& seg2,
counter& state,
bool& eq1, bool& eq2)
{
if (check_touch(point, seg1, seg2, state, eq1, eq2))
{
return 0;
}
return calculate_count(point, seg1, seg2, eq1, eq2);
}
template <typename Point, typename PointOfSegment>
static inline bool check_touch(Point const& point,
PointOfSegment const& seg1,
PointOfSegment const& seg2,
counter& state,
bool& eq1, bool& eq2)
{
typedef typename calculation_type<Point, PointOfSegment>::type calc_t;
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;
}
template <typename Point, typename PointOfSegment>
static inline int calculate_count(Point const& point,
PointOfSegment const& seg1,
PointOfSegment const& seg2,
bool eq1, bool eq2)
{
typedef typename calculation_type<Point, PointOfSegment>::type calc_t;
calc_t const p = get<0>(point);
calc_t const s1 = get<0>(seg1);
calc_t const s2 = get<0>(seg2);
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;
}
template <typename Point, typename PointOfSegment>
static inline int side_equal(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) ;
}
};
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
/*!
\brief Within detection using winding rule in cartesian coordinate system.
\ingroup strategies
\tparam Point_ \tparam_point
\tparam PointOfSegment_ \tparam_segment_point
\tparam CalculationType \tparam_calculation
\qbk{
[heading See also]
[link geometry.reference.algorithms.within.within_3_with_strategy within (with strategy)]
}
*/
template
<
typename Point_ = void, // for backward compatibility
typename PointOfSegment_ = Point_, // for backward compatibility
typename CalculationType = void
>
class cartesian_winding
: public detail::cartesian_winding_base
<
typename side::services::default_strategy<cartesian_tag, CalculationType>::type,
CalculationType
>
{};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2>
struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, polygonal_tag, cartesian_tag, cartesian_tag>
{
using type = cartesian_winding<>;
};
template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2>
struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, linear_tag, cartesian_tag, cartesian_tag>
{
using type = cartesian_winding<>;
};
} // namespace services
#endif
}} // namespace strategy::within
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace strategy { namespace covered_by { namespace services
{
template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2>
struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, polygonal_tag, cartesian_tag, cartesian_tag>
{
using type = within::cartesian_winding<>;
};
template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2>
struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, linear_tag, cartesian_tag, cartesian_tag>
{
using type = within::cartesian_winding<>;
};
}}} // namespace strategy::covered_by::services
#endif
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGY_CARTESIAN_POINT_IN_POLY_WINDING_HPP
+54
View File
@@ -0,0 +1,54 @@
// Boost.Geometry
// Copyright (c) 2019-2020, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_ORDER_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_ORDER_HPP
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/strategy/cartesian/area.hpp>
#include <boost/geometry/strategies/point_order.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace point_order
{
template <typename CalculationType = void>
struct cartesian
: strategy::area::cartesian<CalculationType>
{
typedef area_tag version_tag;
// TEMP
static strategy::area::cartesian<CalculationType> get_area_strategy()
{
return strategy::area::cartesian<CalculationType>();
}
};
namespace services
{
template <>
struct default_strategy<cartesian_tag>
{
typedef cartesian<> type;
};
} // namespace services
}} // namespace strategy::point_order
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_ORDER_HPP
@@ -0,0 +1,21 @@
// Boost.Geometry
// Copyright (c) 2021, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_SIDE_BY_TRIANGLE_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_SIDE_BY_TRIANGLE_HPP
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("This include file is deprecated and will be removed in the future.")
#include <boost/geometry/strategy/cartesian/side_by_triangle.hpp>
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_SIDE_BY_TRIANGLE_HPP
@@ -0,0 +1,65 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2021 Tinko Bartels, Berlin, Germany.
// This file was modified by Oracle on 2023.
// Modifications copyright (c) 2023 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, 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_CARTESIAN_SIDE_ROUNDED_INPUT_HPP
#define BOOST_GEOMETRY_STRATEGY_CARTESIAN_SIDE_ROUNDED_INPUT_HPP
#include <limits>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/config.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace side
{
template <typename CalculationType = void, int Coeff1 = 5, int Coeff2 = 32>
struct side_rounded_input
{
using cs_tag = cartesian_tag;
template <typename P1, typename P2, typename P>
static inline int apply(P1 const& p1, P2 const& p2, P const& p)
{
using coor_t = typename select_calculation_type_alt<CalculationType, P1, P2, P>::type;
coor_t const p1_x = geometry::get<0>(p1);
coor_t const p1_y = geometry::get<1>(p1);
coor_t const p2_x = geometry::get<0>(p2);
coor_t const p2_y = geometry::get<1>(p2);
coor_t const p_x = geometry::get<0>(p);
coor_t const p_y = geometry::get<1>(p);
static coor_t const eps = std::numeric_limits<coor_t>::epsilon() / 2;
coor_t const det = (p1_x - p_x) * (p2_y - p_y) - (p1_y - p_y) * (p2_x - p_x);
coor_t const err_bound = (Coeff1 * eps + Coeff2 * eps * eps) *
( (geometry::math::abs(p1_x) + geometry::math::abs(p_x))
* (geometry::math::abs(p2_y) + geometry::math::abs(p_y))
+ (geometry::math::abs(p2_x) + geometry::math::abs(p_x))
* (geometry::math::abs(p1_y) + geometry::math::abs(p_y)));
return (det > err_bound) - (det < -err_bound);
}
};
}} // namespace strategy::side
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGY_CARTESIAN_SIDE_ROUNDED_INPUT_HPP
@@ -0,0 +1,230 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2020 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2023.
// Modifications copyright (c) 2023 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, 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_TURN_IN_RING_WINDING_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_TURN_IN_RING_WINDING_HPP
#include <boost/geometry/arithmetic/infinite_line_functions.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/config.hpp>
#include <boost/geometry/algorithms/detail/make/make.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/strategies/cartesian/side_rounded_input.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace buffer
{
#ifndef DOXYGEN_NO_DETAIL
enum place_on_ring_type
{
// +----offsetted----> (offsetted is considered as outside)
// | |
// | |
// left right (first point outside, rest inside)
// | |
// | |
// <-----original----+ (original is considered as inside)
place_on_ring_offsetted,
place_on_ring_original,
place_on_ring_to_offsetted,
place_on_ring_from_offsetted,
};
template <typename CalculationType>
class turn_in_ring_winding
{
// Implements the winding rule.
// Basic calculations (on a clockwise ring of 5 segments)
// (as everywhere in BG, -1 = right, 0 = on segment, +1 = left)
// +--------2--------+ // P : For 1/3, nothing happens, it returns
// | | // For 2, side is right (-1), multiplier=2, -2
// | P | // For 4, side is right (-1), multiplier=1, -1
// 1 3 // For 5, side is right (-1), multiplier=1, -1, total -4
// | Q | // Q : For 2: -2, for 4: -2, total -4
// | | // R : For 2: -2, for 5: +2, total 0
// +----5---*----4---+ // S : For 2: -1, 3: nothing, 4: +1, total 0
//
// R S
//
public:
struct counter
{
//! Counter, is increased if point is left of a segment (outside),
//! and decreased if point is right of a segment (inside)
int count{0};
int count_on_offsetted{0};
int count_on_origin{0};
int count_on_edge{0};
CalculationType edge_min_fraction{(std::numeric_limits<CalculationType>::max)()};
#if defined(BOOST_GEOMETRY_USE_RESCALING)
CalculationType inside_min_measure{(std::numeric_limits<CalculationType>::max)()};
#endif
inline bool is_inside() const
{
return count < 0 || count_on_origin > 0;
}
inline bool is_on_boundary() const
{
return count_on_origin == 0
&& (count_on_offsetted > 0
|| (count_on_edge > 0 && edge_min_fraction < 1.0e-3)
#if defined(BOOST_GEOMETRY_USE_RESCALING)
|| (count < 0 && inside_min_measure < 1.0e-5)
#endif
);
}
};
using state_type = counter;
template <typename Point, typename PointOfSegment>
static inline bool is_in_vertical_range(Point const& point,
PointOfSegment const& s1,
PointOfSegment const& s2)
{
CalculationType const py = get<1>(point);
CalculationType const s1y = get<1>(s1);
CalculationType const s2y = get<1>(s2);
return s1y < s2y ? (py >= s1y && py <= s2y) : (py >= s2y && py <= s1y);
}
template <typename Point, typename PointOfSegment>
static inline void apply_on_boundary(Point const& point,
PointOfSegment const& s1,
PointOfSegment const& s2,
place_on_ring_type place_on_ring,
counter& the_state)
{
if (place_on_ring == place_on_ring_offsetted)
{
the_state.count_on_offsetted++;
}
else if (place_on_ring == place_on_ring_to_offsetted
|| place_on_ring == place_on_ring_from_offsetted)
{
the_state.count_on_edge++;
auto const line1 = detail::make::make_perpendicular_line<CalculationType>(s1, s2, s1);
auto const line2 = detail::make::make_perpendicular_line<CalculationType>(s2, s1, s2);
auto const value1 = arithmetic::side_value(line1, point);
auto const value2 = arithmetic::side_value(line2, point);
if (value1 >= 0 && value2 >= 0)
{
auto const length_value = value1 + value2;
if (length_value > 0)
{
// If it is to the utmost point s1 or s2, it is "outside"
auto const fraction = (place_on_ring == place_on_ring_to_offsetted ? value2 : value1) / length_value;
if (fraction < the_state.edge_min_fraction)
{
the_state.edge_min_fraction = fraction;
}
}
}
}
else
{
the_state.count_on_origin++;
}
}
template <typename Point, typename PointOfSegment>
static inline bool apply(Point const& point,
PointOfSegment const& s1,
PointOfSegment const& s2,
place_on_ring_type place_on_ring,
bool is_convex,
counter& the_state)
{
int const side = strategy::side::side_rounded_input<CalculationType>::apply(s1, s2, point);
if (is_convex && side > 0)
{
// If the point is left of this segment of a convex piece, it can never be inside.
// Stop further processing
the_state.count = 1;
return false;
}
CalculationType const px = get<0>(point);
CalculationType const s1x = get<0>(s1);
CalculationType const s2x = get<0>(s2);
bool const in_horizontal_range = s1x < s2x ? (px >= s1x && px <= s2x) : (px >= s2x && px <= s1x);
bool const vertical = s1x == s2x;
if (in_horizontal_range || (vertical && is_in_vertical_range(point, s1, s2)))
{
if (side == 0)
{
apply_on_boundary(point, s1, s2, place_on_ring, the_state);
}
#if defined(BOOST_GEOMETRY_USE_RESCALING)
else if (side == -1)
{
auto const line = detail::make::make_infinite_line<CalculationType>(s1, s2);
auto const value = -arithmetic::side_value(line, point);
if (value > 0 && value < the_state.inside_min_measure) { the_state.inside_min_measure = value; }
}
#endif
}
if (in_horizontal_range)
{
auto const on_boundary = the_state.count_on_offsetted + the_state.count_on_edge + the_state.count_on_origin;
if (on_boundary == 0)
{
// Use only absolute comparisons, because the ring is continuous -
// what was missed is there earlier or later, and turns should
// not be counted twice (which can happen if an epsilon is used).
bool const eq1 = s1x == px;
bool const eq2 = s2x == px;
// Account for 1 or 2 for left side (outside)
// and for -1 or -2 for right side (inside)
int const multiplier = eq1 || eq2 ? 1 : 2;
the_state.count += side * multiplier;
}
}
return true;
}
};
#endif // DOXYGEN_NO_DETAIL
}} // namespace strategy::buffer
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_TURN_IN_RING_WINDING_HPP