Skip to content

Commit d9c996d

Browse files
committed
add closest_point on geometry algorithm + tests
1 parent d79b1fb commit d9c996d

File tree

9 files changed

+630
-1
lines changed

9 files changed

+630
-1
lines changed

Jamroot

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ lib spatial-algorithms
2323
src/intersection_g_g_i64.cpp
2424
src/intersection_b_pl_i64.cpp
2525
src/intersection_pl_b_i64.cpp
26+
src/closest_point_d.cpp
27+
src/closest_point_i64.cpp
2628
:
2729
<link>static
2830
<include>include
@@ -60,6 +62,7 @@ unit-test algorithms-test
6062
test/unit/predicates/test-intersects.cpp
6163
test/unit/predicates/test-disjoint.cpp
6264
test/unit/intersection/test-intersection.cpp
65+
test/unit/closest_point/test-closest-point.cpp
6366
.//spatial-algorithms
6467
:
6568
<include>include
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
// Boost.Geometry (aka GGL, Generic Geometry Library)
2+
3+
// Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands.
4+
// Copyright (c) 2008-2013 Bruno Lalande, Paris, France.
5+
// Copyright (c) 2009-2013 Mateusz Loskot, London, UK.
6+
// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
7+
// Copyright (c) 2017 Artem Pavlenko, UK
8+
9+
// Use, modification and distribution is subject to the Boost Software License,
10+
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
11+
// http://www.boost.org/LICENSE_1_0.txt)
12+
13+
#ifndef BOOST_GEOMETRY_ALGORITHMS_CLOSEST_POINT_HPP
14+
#define BOOST_GEOMETRY_ALGORITHMS_CLOSEST_POINT_HPP
15+
16+
#include <boost/mpl/if.hpp>
17+
#include <boost/range/functions.hpp>
18+
#include <boost/range/metafunctions.hpp>
19+
#include <boost/static_assert.hpp>
20+
21+
#include <boost/geometry/core/access.hpp>
22+
#include <boost/geometry/core/coordinate_dimension.hpp>
23+
#include <boost/geometry/core/reverse_dispatch.hpp>
24+
25+
#include <boost/geometry/algorithms/not_implemented.hpp>
26+
#include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp>
27+
28+
#include <boost/geometry/geometries/concepts/check.hpp>
29+
30+
#include <boost/geometry/strategies/distance.hpp>
31+
#include <boost/geometry/strategies/default_distance_result.hpp>
32+
33+
#include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp>
34+
#include <boost/geometry/extensions/strategies/cartesian/closest_point.hpp>
35+
36+
#include <boost/geometry/util/math.hpp>
37+
38+
39+
namespace boost { namespace geometry
40+
{
41+
42+
#ifndef DOXYGEN_NO_DETAIL
43+
namespace detail { namespace closest_point {
44+
45+
46+
template <typename Point1, typename Point2>
47+
struct point_point
48+
{
49+
template <typename Strategy, typename Result>
50+
static inline void apply(Point1 const& point1, Point2 const& point2, Strategy const& strategy, Result& result)
51+
{
52+
result.distance
53+
= strategy.apply_point_point(point1, point2);
54+
geometry::convert(point2, result.closest_point);
55+
}
56+
};
57+
58+
template <typename Point, typename Range>
59+
struct point_range
60+
{
61+
template <typename Strategy, typename Result>
62+
static inline void apply(Point const& point, Range const& range, Strategy const& strategy, Result& result)
63+
{
64+
// This should not occur (see exception on empty input below)
65+
if (boost::begin(range) == boost::end(range))
66+
{
67+
return;
68+
}
69+
70+
// line of one point: same case as point-point
71+
typedef typename boost::range_const_iterator<Range>::type iterator_type;
72+
iterator_type it = boost::begin(range);
73+
iterator_type prev = it++;
74+
if (it == boost::end(range))
75+
{
76+
point_point<Point, typename boost::range_value<Range const>::type>::apply(point, *prev, strategy, result);
77+
return;
78+
}
79+
80+
// Initialize with first segment
81+
strategy.apply(point, *prev, *it, result);
82+
83+
// Check other segments
84+
for(prev = it++; it != boost::end(range); prev = it++)
85+
{
86+
Result other;
87+
strategy.apply(point, *prev, *it, other);
88+
if (other.distance < result.distance)
89+
{
90+
result = other;
91+
}
92+
}
93+
}
94+
};
95+
96+
97+
98+
99+
}} // namespace detail::closest_point
100+
#endif // DOXYGEN_NO_DETAIL
101+
102+
103+
#ifndef DOXYGEN_NO_DISPATCH
104+
namespace dispatch
105+
{
106+
107+
template
108+
<
109+
typename Geometry1, typename Geometry2,
110+
typename Tag1 = typename tag<Geometry1>::type,
111+
typename Tag2 = typename tag<Geometry2>::type,
112+
bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value
113+
>
114+
struct closest_point : not_implemented<Tag1, Tag2>
115+
{
116+
};
117+
118+
119+
template
120+
<
121+
typename Geometry1, typename Geometry2,
122+
typename Tag1, typename Tag2
123+
>
124+
struct closest_point<Geometry1, Geometry2, Tag1, Tag2, true>
125+
{
126+
template <typename Strategy, typename Result>
127+
static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
128+
Strategy const& strategy, Result& result)
129+
{
130+
// Reversed version just calls dispatch with reversed arguments
131+
closest_point
132+
<
133+
Geometry2, Geometry1, Tag2, Tag1, false
134+
>::apply(geometry2, geometry1, strategy, result);
135+
}
136+
137+
};
138+
139+
140+
template<typename Point1, typename Point2>
141+
struct closest_point
142+
<
143+
Point1, Point2,
144+
point_tag, point_tag, false
145+
> : public detail::closest_point::point_point<Point1, Point2>
146+
{};
147+
148+
149+
template<typename Point, typename Segment>
150+
struct closest_point
151+
<
152+
Point, Segment,
153+
point_tag, segment_tag,
154+
false
155+
>
156+
{
157+
template <typename Strategy, typename Result>
158+
static inline void apply(Point const& point, Segment const& segment,
159+
Strategy const& strategy, Result& result)
160+
{
161+
162+
typename point_type<Segment>::type p[2];
163+
geometry::detail::assign_point_from_index<0>(segment, p[0]);
164+
geometry::detail::assign_point_from_index<1>(segment, p[1]);
165+
166+
strategy.apply(point, p[0], p[1], result);
167+
}
168+
};
169+
170+
171+
template <typename Point, typename Ring>
172+
struct closest_point<Point, Ring, point_tag, ring_tag, false>
173+
: detail::closest_point::point_range<Point, Ring>
174+
{};
175+
176+
//
177+
template<typename Point, typename Linestring>
178+
struct closest_point
179+
<
180+
Point, Linestring,
181+
point_tag, linestring_tag,
182+
false
183+
>
184+
: detail::closest_point::point_range<Point, Linestring>
185+
{};
186+
187+
188+
} // namespace dispatch
189+
#endif // DOXYGEN_NO_DISPATCH
190+
191+
192+
193+
template <typename Geometry1, typename Geometry2, typename Result>
194+
inline void closest_point(Geometry1 const& geometry1, Geometry2 const& geometry2, Result& result)
195+
{
196+
concepts::check<Geometry1 const>();
197+
concepts::check<Geometry2 const>();
198+
concepts::check<typename Result::point_type>();
199+
200+
assert_dimension_equal<Geometry1, Geometry2>();
201+
assert_dimension_equal<Geometry1, typename Result::point_type>();
202+
203+
detail::throw_on_empty_input(geometry1);
204+
detail::throw_on_empty_input(geometry2);
205+
206+
strategy::distance::calculate_closest_point<> info_strategy;
207+
208+
209+
dispatch::closest_point
210+
<
211+
Geometry1,
212+
Geometry2
213+
>::apply(geometry1, geometry2, info_strategy, result);
214+
}
215+
216+
217+
}} // namespace boost::geometry
218+
219+
#endif // BOOST_GEOMETRY_ALGORITHMS_CLOSEST_POINT_HPP

0 commit comments

Comments
 (0)