Skip to content

Commit 03489ca

Browse files
committed
[fix] support different geometry types
This fixes #1139 , and more required code changes. Including unit test.
1 parent ee83f57 commit 03489ca

File tree

10 files changed

+227
-111
lines changed

10 files changed

+227
-111
lines changed

doc/release_notes.qbk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
[*Solved issues]
3131

3232
* [@https://github.com/boostorg/geometry/issues/1100 1100] Fix for union
33+
* [@https://github.com/boostorg/geometry/issues/1139 1139] Fix for different geometry types
3334

3435
[*Breaking changes]
3536

include/boost/geometry/algorithms/detail/direction_code.hpp

Lines changed: 75 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,16 @@ struct direction_code_impl
4646
template <>
4747
struct direction_code_impl<cartesian_tag>
4848
{
49-
template <typename Point1, typename Point2>
50-
static inline int apply(Point1 const& segment_a, Point1 const& segment_b,
49+
template <typename PointSegmentA, typename PointSegmentB, typename Point2>
50+
static inline int apply(PointSegmentA const& segment_a, PointSegmentB const& segment_b,
5151
Point2 const& point)
5252
{
53-
typedef typename geometry::select_coordinate_type
53+
using calc_t = typename geometry::select_coordinate_type
5454
<
55-
Point1, Point2
56-
>::type calc_t;
55+
PointSegmentA, PointSegmentB, Point2
56+
>::type;
5757

58-
typedef model::infinite_line<calc_t> line_type;
58+
using line_type = model::infinite_line<calc_t>;
5959

6060
// Situation and construction of perpendicular line
6161
//
@@ -87,42 +87,59 @@ struct direction_code_impl<cartesian_tag>
8787
template <>
8888
struct direction_code_impl<spherical_equatorial_tag>
8989
{
90-
template <typename Point1, typename Point2>
91-
static inline int apply(Point1 const& segment_a, Point1 const& segment_b,
90+
template <typename PointSegmentA, typename PointSegmentB, typename Point2>
91+
static inline int apply(PointSegmentA const& segment_a, PointSegmentB const& segment_b,
9292
Point2 const& p)
9393
{
94-
typedef typename coordinate_type<Point1>::type coord1_t;
95-
typedef typename coordinate_type<Point2>::type coord2_t;
96-
typedef typename cs_angular_units<Point1>::type units_t;
97-
typedef typename cs_angular_units<Point2>::type units2_t;
98-
BOOST_GEOMETRY_STATIC_ASSERT(
99-
(std::is_same<units_t, units2_t>::value),
100-
"Not implemented for different units.",
101-
units_t, units2_t);
102-
103-
typedef typename geometry::select_coordinate_type <Point1, Point2>::type calc_t;
104-
typedef math::detail::constants_on_spheroid<coord1_t, units_t> constants1;
105-
typedef math::detail::constants_on_spheroid<coord2_t, units_t> constants2;
106-
static coord1_t const pi_half1 = constants1::max_latitude();
107-
static coord2_t const pi_half2 = constants2::max_latitude();
94+
{
95+
using units_sa_t = typename cs_angular_units<PointSegmentA>::type;
96+
using units_sb_t = typename cs_angular_units<PointSegmentB>::type;
97+
using units_p_t = typename cs_angular_units<Point2>::type;
98+
BOOST_GEOMETRY_STATIC_ASSERT(
99+
(std::is_same<units_sa_t, units_sb_t>::value),
100+
"Not implemented for different units.",
101+
units_sa_t, units_sb_t);
102+
BOOST_GEOMETRY_STATIC_ASSERT(
103+
(std::is_same<units_sa_t, units_p_t>::value),
104+
"Not implemented for different units.",
105+
units_sa_t, units_p_t);
106+
}
107+
108+
using coor_sa_t = typename coordinate_type<PointSegmentA>::type;
109+
using coor_sb_t = typename coordinate_type<PointSegmentB>::type;
110+
using coor_p_t = typename coordinate_type<Point2>::type;
111+
112+
// Declare unit type (equal for all types) and calc type (coerced to most precise)
113+
using units_t = typename cs_angular_units<Point2>::type;
114+
using calc_t = typename geometry::select_coordinate_type
115+
<
116+
PointSegmentA, PointSegmentB, Point2
117+
>::type;
118+
using constants_sa_t = math::detail::constants_on_spheroid<coor_sa_t, units_t>;
119+
using constants_sb_t = math::detail::constants_on_spheroid<coor_sb_t, units_t>;
120+
using constants_p_t = math::detail::constants_on_spheroid<coor_p_t, units_t>;
121+
122+
static coor_sa_t const pi_half_sa = constants_sa_t::max_latitude();
123+
static coor_sb_t const pi_half_sb = constants_sb_t::max_latitude();
124+
static coor_p_t const pi_half_p = constants_p_t::max_latitude();
108125
static calc_t const c0 = 0;
109126

110-
coord1_t const a0 = geometry::get<0>(segment_a);
111-
coord1_t const a1 = geometry::get<1>(segment_a);
112-
coord1_t const b0 = geometry::get<0>(segment_b);
113-
coord1_t const b1 = geometry::get<1>(segment_b);
114-
coord2_t const p0 = geometry::get<0>(p);
115-
coord2_t const p1 = geometry::get<1>(p);
116-
127+
coor_sa_t const a0 = geometry::get<0>(segment_a);
128+
coor_sa_t const a1 = geometry::get<1>(segment_a);
129+
coor_sb_t const b0 = geometry::get<0>(segment_b);
130+
coor_sb_t const b1 = geometry::get<1>(segment_b);
131+
coor_p_t const p0 = geometry::get<0>(p);
132+
coor_p_t const p1 = geometry::get<1>(p);
133+
117134
if ( (math::equals(b0, a0) && math::equals(b1, a1))
118135
|| (math::equals(b0, p0) && math::equals(b1, p1)) )
119136
{
120137
return 0;
121138
}
122139

123-
bool const is_a_pole = math::equals(pi_half1, math::abs(a1));
124-
bool const is_b_pole = math::equals(pi_half1, math::abs(b1));
125-
bool const is_p_pole = math::equals(pi_half2, math::abs(p1));
140+
bool const is_a_pole = math::equals(pi_half_sa, math::abs(a1));
141+
bool const is_b_pole = math::equals(pi_half_sb, math::abs(b1));
142+
bool const is_p_pole = math::equals(pi_half_p, math::abs(p1));
126143

127144
if ( is_b_pole && ((is_a_pole && math::sign(b1) == math::sign(a1))
128145
|| (is_p_pole && math::sign(b1) == math::sign(p1))) )
@@ -140,12 +157,12 @@ struct direction_code_impl<spherical_equatorial_tag>
140157
calc_t const dlat1 = latitude_distance_signed<units_t, calc_t>(b1, a1, dlon1, is_antilon1);
141158
calc_t const dlat2 = latitude_distance_signed<units_t, calc_t>(b1, p1, dlon2, is_antilon2);
142159

143-
calc_t mx = is_a_pole || is_b_pole || is_p_pole ?
144-
c0 :
145-
(std::min)(is_antilon1 ? c0 : math::abs(dlon1),
146-
is_antilon2 ? c0 : math::abs(dlon2));
147-
calc_t my = (std::min)(math::abs(dlat1),
148-
math::abs(dlat2));
160+
calc_t const mx = is_a_pole || is_b_pole || is_p_pole
161+
? c0
162+
: (std::min)(is_antilon1 ? c0 : math::abs(dlon1),
163+
is_antilon2 ? c0 : math::abs(dlon2));
164+
calc_t const my = (std::min)(math::abs(dlat1),
165+
math::abs(dlat2));
149166

150167
int s1 = 0, s2 = 0;
151168
if (mx >= my)
@@ -165,7 +182,7 @@ struct direction_code_impl<spherical_equatorial_tag>
165182
template <typename Units, typename T>
166183
static inline T latitude_distance_signed(T const& lat1, T const& lat2, T const& lon_ds, bool & is_antilon)
167184
{
168-
typedef math::detail::constants_on_spheroid<T, Units> constants;
185+
using constants = math::detail::constants_on_spheroid<T, Units>;
169186
static T const pi = constants::half_period();
170187
static T const c0 = 0;
171188

@@ -188,27 +205,27 @@ struct direction_code_impl<spherical_equatorial_tag>
188205
template <>
189206
struct direction_code_impl<spherical_polar_tag>
190207
{
191-
template <typename Point1, typename Point2>
192-
static inline int apply(Point1 segment_a, Point1 segment_b,
208+
template <typename PointSegmentA, typename PointSegmentB, typename Point2>
209+
static inline int apply(PointSegmentA segment_a, PointSegmentB segment_b,
193210
Point2 p)
194211
{
195-
typedef math::detail::constants_on_spheroid
212+
using constants_sa_t = math::detail::constants_on_spheroid
196213
<
197-
typename coordinate_type<Point1>::type,
198-
typename cs_angular_units<Point1>::type
199-
> constants1;
200-
typedef math::detail::constants_on_spheroid
214+
typename coordinate_type<PointSegmentA>::type,
215+
typename cs_angular_units<PointSegmentA>::type
216+
>;
217+
using constants_p_t = math::detail::constants_on_spheroid
201218
<
202219
typename coordinate_type<Point2>::type,
203220
typename cs_angular_units<Point2>::type
204-
> constants2;
221+
>;
205222

206223
geometry::set<1>(segment_a,
207-
constants1::max_latitude() - geometry::get<1>(segment_a));
224+
constants_sa_t::max_latitude() - geometry::get<1>(segment_a));
208225
geometry::set<1>(segment_b,
209-
constants1::max_latitude() - geometry::get<1>(segment_b));
226+
constants_sa_t::max_latitude() - geometry::get<1>(segment_b));
210227
geometry::set<1>(p,
211-
constants2::max_latitude() - geometry::get<1>(p));
228+
constants_p_t::max_latitude() - geometry::get<1>(p));
212229

213230
return direction_code_impl
214231
<
@@ -217,13 +234,13 @@ struct direction_code_impl<spherical_polar_tag>
217234
}
218235
};
219236

220-
// if spherical_tag is passed then pick cs_tag based on Point1 type
237+
// if spherical_tag is passed then pick cs_tag based on PointSegmentA type
221238
// with spherical_equatorial_tag as the default
222239
template <>
223240
struct direction_code_impl<spherical_tag>
224241
{
225-
template <typename Point1, typename Point2>
226-
static inline int apply(Point1 segment_a, Point1 segment_b,
242+
template <typename PointSegmentA, typename PointSegmentB, typename Point2>
243+
static inline int apply(PointSegmentA segment_a, PointSegmentB segment_b,
227244
Point2 p)
228245
{
229246
return direction_code_impl
@@ -232,7 +249,7 @@ struct direction_code_impl<spherical_tag>
232249
<
233250
std::is_same
234251
<
235-
typename geometry::cs_tag<Point1>::type,
252+
typename geometry::cs_tag<PointSegmentA>::type,
236253
spherical_polar_tag
237254
>::value,
238255
spherical_polar_tag,
@@ -252,8 +269,10 @@ struct direction_code_impl<geographic_tag>
252269
// Returns 1 if p goes forward, so extends (a,b)
253270
// Returns 0 if p is equal with b, or if (a,b) is degenerate
254271
// Note that it does not do any collinearity test, that should be done before
255-
template <typename CSTag, typename Point1, typename Point2>
256-
inline int direction_code(Point1 const& segment_a, Point1 const& segment_b,
272+
// In some cases the "segment" consists of different source points, and therefore
273+
// their types might differ.
274+
template <typename CSTag, typename PointSegmentA, typename PointSegmentB, typename Point2>
275+
inline int direction_code(PointSegmentA const& segment_a, PointSegmentB const& segment_b,
257276
Point2 const& p)
258277
{
259278
return direction_code_impl<CSTag>::apply(segment_a, segment_b, p);

include/boost/geometry/algorithms/detail/make/make.hpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ namespace boost { namespace geometry
1919
namespace detail { namespace make
2020
{
2121

22-
template <typename Type, typename Coordinate>
22+
template <typename Type, typename Coordinate1, typename Coordinate2>
2323
inline
24-
model::infinite_line<Type> make_infinite_line(Coordinate const& x1,
25-
Coordinate const& y1, Coordinate const& x2, Coordinate const& y2)
24+
model::infinite_line<Type> make_infinite_line(Coordinate1 const& x1,
25+
Coordinate1 const& y1, Coordinate2 const& x2, Coordinate2 const& y2)
2626
{
2727
model::infinite_line<Type> result;
2828
result.a = y1 - y2;
@@ -31,9 +31,9 @@ model::infinite_line<Type> make_infinite_line(Coordinate const& x1,
3131
return result;
3232
}
3333

34-
template <typename Type, typename Point>
34+
template <typename Type, typename PointA, typename PointB>
3535
inline
36-
model::infinite_line<Type> make_infinite_line(Point const& a, Point const& b)
36+
model::infinite_line<Type> make_infinite_line(PointA const& a, PointB const& b)
3737
{
3838
return make_infinite_line<Type>(geometry::get<0>(a), geometry::get<1>(a),
3939
geometry::get<0>(b), geometry::get<1>(b));
@@ -49,9 +49,9 @@ model::infinite_line<Type> make_infinite_line(Segment const& segment)
4949
geometry::get<1, 1>(segment));
5050
}
5151

52-
template <typename Type, typename Point>
52+
template <typename Type, typename PointA, typename PointB, typename PointC>
5353
inline
54-
model::infinite_line<Type> make_perpendicular_line(Point const& a, Point const& b, Point const& c)
54+
model::infinite_line<Type> make_perpendicular_line(PointA const& a, PointB const& b, PointC const& c)
5555
{
5656
// https://www.math-only-math.com/equation-of-a-line-perpendicular-to-a-line.html
5757
model::infinite_line<Type> const line = make_infinite_line<Type>(a, b);

include/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <boost/static_assert.hpp>
2424

2525
#include <boost/geometry/algorithms/append.hpp>
26+
#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
2627
#include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp>
2728
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
2829

@@ -99,7 +100,16 @@ inline void append_no_dups_or_spikes(Range& range, Point const& point,
99100
return;
100101
}
101102

102-
traits::push_back<Range>::apply(range, point);
103+
auto append = [](auto& r, const auto& p)
104+
{
105+
using point_t = typename boost::range_value<Range>::type;
106+
point_t rp;
107+
geometry::detail::conversion::convert_point_to_point(p, rp);
108+
traits::push_back<Range>::apply(r, std::move(rp));
109+
};
110+
111+
append(range, point);
112+
103113

104114
// If a point is equal, or forming a spike, remove the pen-ultimate point
105115
// because this one caused the spike.
@@ -115,7 +125,7 @@ inline void append_no_dups_or_spikes(Range& range, Point const& point,
115125
{
116126
// Use the Concept/traits, so resize and append again
117127
traits::resize<Range>::apply(range, boost::size(range) - 2);
118-
traits::push_back<Range>::apply(range, point);
128+
append(range, point);
119129
}
120130
}
121131

include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -192,13 +192,16 @@ template<typename VerifyPolicy>
192192
struct turn_info_verification_functions
193193
{
194194
template <typename Point1, typename Point2>
195-
static inline typename geometry::coordinate_type<Point1>::type
196-
distance_measure(Point1 const& a, Point2 const& b)
195+
static inline
196+
typename select_coordinate_type<Point1, Point2>::type
197+
distance_measure(Point1 const& a, Point2 const& b)
197198
{
198199
// TODO: revise this using comparable distance for various
199200
// coordinate systems
200-
auto const dx = get<0>(a) - get<0>(b);
201-
auto const dy = get<1>(a) - get<1>(b);
201+
using coor_t = typename select_coordinate_type<Point1, Point2>::type;
202+
203+
coor_t const dx = get<0>(a) - get<0>(b);
204+
coor_t const dy = get<1>(a) - get<1>(b);
202205
return dx * dx + dy * dy;
203206
}
204207

@@ -1032,8 +1035,9 @@ struct collinear : public base_turn_handler
10321035
return false;
10331036
}
10341037

1035-
auto const dm = fun::distance_measure(info.intersections[1],
1036-
arrival_p == 1 ? range_q.at(1) : range_p.at(1));
1038+
auto const dm = arrival_p == 1
1039+
? fun::distance_measure(info.intersections[1], range_q.at(1))
1040+
: fun::distance_measure(info.intersections[1], range_p.at(1));
10371041
decltype(dm) const zero = 0;
10381042
return math::equals(dm, zero);
10391043
}

include/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,10 @@ struct less_false
127127
}
128128
};
129129

130-
template <typename Point, typename SideStrategy, typename LessOnSame, typename Compare>
130+
template <typename PointOrigin, typename PointTurn, typename SideStrategy, typename LessOnSame, typename Compare>
131131
struct less_by_side
132132
{
133-
less_by_side(const Point& p1, const Point& p2, SideStrategy const& strategy)
133+
less_by_side(const PointOrigin& p1, const PointTurn& p2, SideStrategy const& strategy)
134134
: m_origin(p1)
135135
, m_turn_point(p2)
136136
, m_strategy(strategy)
@@ -209,8 +209,8 @@ struct less_by_side
209209
}
210210

211211
private :
212-
Point const& m_origin;
213-
Point const& m_turn_point;
212+
PointOrigin const& m_origin;
213+
PointTurn const& m_turn_point;
214214
SideStrategy const& m_strategy;
215215
};
216216

@@ -379,7 +379,8 @@ public :
379379
}
380380
}
381381

382-
void apply(Point const& turn_point)
382+
template <typename PointTurn>
383+
void apply(PointTurn const& turn_point)
383384
{
384385
// We need three compare functors:
385386
// 1) to order clockwise (union) or counter clockwise (intersection)
@@ -388,8 +389,8 @@ public :
388389
// to give colinear points
389390

390391
// Sort by side and assign rank
391-
less_by_side<Point, SideStrategy, less_by_index, Compare> less_unique(m_origin, turn_point, m_strategy);
392-
less_by_side<Point, SideStrategy, less_false, Compare> less_non_unique(m_origin, turn_point, m_strategy);
392+
less_by_side<Point, PointTurn, SideStrategy, less_by_index, Compare> less_unique(m_origin, turn_point, m_strategy);
393+
less_by_side<Point, PointTurn, SideStrategy, less_false, Compare> less_non_unique(m_origin, turn_point, m_strategy);
393394

394395
std::sort(m_ranked_points.begin(), m_ranked_points.end(), less_unique);
395396

0 commit comments

Comments
 (0)