Libosmium  2.7.2
Fast and flexible C++ library for working with OpenStreetMap data
location.hpp
Go to the documentation of this file.
1 #ifndef OSMIUM_OSM_LOCATION_HPP
2 #define OSMIUM_OSM_LOCATION_HPP
3 
4 /*
5 
6 This file is part of Osmium (http://osmcode.org/libosmium).
7 
8 Copyright 2013-2016 Jochen Topf <jochen@topf.org> and others (see README).
9 
10 Boost Software License - Version 1.0 - August 17th, 2003
11 
12 Permission is hereby granted, free of charge, to any person or organization
13 obtaining a copy of the software and accompanying documentation covered by
14 this license (the "Software") to use, reproduce, display, distribute,
15 execute, and transmit the Software, and to prepare derivative works of the
16 Software, and to permit third-parties to whom the Software is furnished to
17 do so, all subject to the following:
18 
19 The copyright notices in the Software and this entire statement, including
20 the above license grant, this restriction and the following disclaimer,
21 must be included in all copies of the Software, in whole or in part, and
22 all derivative works of the Software, unless such copies or derivative
23 works are solely in the form of machine-executable object code generated by
24 a source language processor.
25 
26 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
29 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
30 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
31 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
32 DEALINGS IN THE SOFTWARE.
33 
34 */
35 
36 #include <cmath>
37 #include <cstdint>
38 #include <functional>
39 #include <iosfwd>
40 #include <stdexcept>
41 #include <string>
42 
43 #include <iostream>
44 
46 #include <osmium/util/double.hpp>
47 
48 namespace osmium {
49 
54  struct invalid_location : public std::range_error {
55 
56  explicit invalid_location(const std::string& what) :
57  std::range_error(what) {
58  }
59 
60  explicit invalid_location(const char* what) :
61  std::range_error(what) {
62  }
63 
64  }; // struct invalid_location
65 
66  namespace detail {
67 
68  constexpr const int coordinate_precision = 10000000;
69 
70  // Convert string with a floating point number into integer suitable
71  // for use as coordinate in a Location.
72  inline int32_t string_to_location_coordinate(const char* str) {
73  const char* full = str;
74 
75  int32_t result = 0;
76  int sign = 1;
77  int scale = 7;
78 
79  // optional minus sign
80  if (*str == '-') {
81  sign = -1;
82  ++str;
83  }
84 
85  // first digit before decimal point
86  if (*str >= '0' && *str <= '9') {
87  result = *str - '0';
88  ++str;
89  } else {
90  goto error;
91  }
92 
93  // optional second digit before decimal point
94  if (*str >= '0' && *str <= '9') {
95  result = result * 10 + *str - '0';
96  ++str;
97 
98  // optional third digit before decimal point
99  if (*str >= '0' && *str <= '9') {
100  result = result * 10 + *str - '0';
101  ++str;
102  }
103  }
104 
105  if (*str != '\0') {
106 
107  // decimal point
108  if (*str != '.') {
109  goto error;
110  }
111 
112  ++str;
113 
114  // read significant digits
115  for (; scale > 0 && *str >= '0' && *str <= '9'; --scale, ++str) {
116  result = result * 10 + (*str - '0');
117  }
118 
119  // use 8th digit after decimal point for rounding
120  if (scale == 0 && *str >= '5' && *str <= '9') {
121  ++result;
122  ++str;
123  }
124 
125  // ignore further digits
126  while (*str >= '0' && *str <= '9') {
127  ++str;
128  }
129 
130  // should be at the end now
131  if (*str != '\0') {
132  goto error;
133  }
134 
135  }
136 
137  for (; scale > 0; --scale) {
138  result *= 10;
139  }
140 
141  return result * sign;
142 
143  error:
144 
145  throw invalid_location{std::string{"wrong format for coordinate: '"} + full + "'"};
146  }
147 
148  // Convert integer as used by location for coordinates into a string.
149  template <typename T>
150  inline T append_location_coordinate_to_string(T iterator, int32_t value) {
151  // handle negative values
152  if (value < 0) {
153  *iterator++ = '-';
154  value = -value;
155  }
156 
157  // write digits into temporary buffer
158  int32_t v = value;
159  char temp[10];
160  char* t = temp;
161  do {
162  *t++ = char(v % 10) + '0';
163  v /= 10;
164  } while (v != 0);
165 
166  while (t-temp < 7) {
167  *t++ = '0';
168  }
169 
170  // write out digits before decimal point
171  if (value >= coordinate_precision) {
172  if (value >= 10 * coordinate_precision) {
173  if (value >= 100 * coordinate_precision) {
174  *iterator++ = *--t;
175  }
176  *iterator++ = *--t;
177  }
178  *iterator++ = *--t;
179  } else {
180  *iterator++ = '0';
181  }
182 
183  // remove trailing zeros
184  const char* tn = temp;
185  while (tn < t && *tn == '0') {
186  ++tn;
187  }
188 
189  // decimal point
190  if (t != tn) {
191  *iterator++ = '.';
192  while (t != tn) {
193  *iterator++ = *--t;
194  }
195  }
196 
197  return iterator;
198  }
199 
200  } // namespace detail
201 
216  class Location {
217 
218  int32_t m_x;
219  int32_t m_y;
220 
221  public:
222 
223  // this value is used for a coordinate to mark it as undefined
224  // MSVC doesn't declare std::numeric_limits<int32_t>::max() as
225  // constexpr, so we hard code this for the time being.
226  // static constexpr int32_t undefined_coordinate = std::numeric_limits<int32_t>::max();
227  static constexpr int32_t undefined_coordinate = 2147483647;
228 
229  static int32_t double_to_fix(const double c) noexcept {
230  return static_cast<int32_t>(std::round(c * detail::coordinate_precision));
231  }
232 
233  static constexpr double fix_to_double(const int32_t c) noexcept {
234  return static_cast<double>(c) / detail::coordinate_precision;
235  }
236 
240  explicit constexpr Location() noexcept :
241  m_x(undefined_coordinate),
242  m_y(undefined_coordinate) {
243  }
244 
250  constexpr Location(const int32_t x, const int32_t y) noexcept :
251  m_x(x),
252  m_y(y) {
253  }
254 
260  constexpr Location(const int64_t x, const int64_t y) noexcept :
261  m_x(static_cast<int32_t>(x)),
262  m_y(static_cast<int32_t>(y)) {
263  }
264 
268  Location(const double lon, const double lat) :
269  m_x(double_to_fix(lon)),
270  m_y(double_to_fix(lat)) {
271  }
272 
273  Location(const Location&) = default;
274  Location(Location&&) = default;
275  Location& operator=(const Location&) = default;
276  Location& operator=(Location&&) = default;
277  ~Location() = default;
278 
283  explicit constexpr operator bool() const noexcept {
284  return m_x != undefined_coordinate && m_y != undefined_coordinate;
285  }
286 
291  constexpr bool valid() const noexcept {
292  return m_x >= -180 * detail::coordinate_precision
293  && m_x <= 180 * detail::coordinate_precision
294  && m_y >= -90 * detail::coordinate_precision
295  && m_y <= 90 * detail::coordinate_precision;
296  }
297 
298  constexpr int32_t x() const noexcept {
299  return m_x;
300  }
301 
302  constexpr int32_t y() const noexcept {
303  return m_y;
304  }
305 
306  Location& set_x(const int32_t x) noexcept {
307  m_x = x;
308  return *this;
309  }
310 
311  Location& set_y(const int32_t y) noexcept {
312  m_y = y;
313  return *this;
314  }
315 
321  double lon() const {
322  if (!valid()) {
323  throw osmium::invalid_location("invalid location");
324  }
325  return fix_to_double(m_x);
326  }
327 
331  double lon_without_check() const {
332  return fix_to_double(m_x);
333  }
334 
340  double lat() const {
341  if (!valid()) {
342  throw osmium::invalid_location("invalid location");
343  }
344  return fix_to_double(m_y);
345  }
346 
350  double lat_without_check() const {
351  return fix_to_double(m_y);
352  }
353 
354  Location& set_lon(double lon) noexcept {
355  m_x = double_to_fix(lon);
356  return *this;
357  }
358 
359  Location& set_lat(double lat) noexcept {
360  m_y = double_to_fix(lat);
361  return *this;
362  }
363 
364  Location& set_lon(const char* str) noexcept {
365  m_x = detail::string_to_location_coordinate(str);
366  return *this;
367  }
368 
369  Location& set_lat(const char* str) noexcept {
370  m_y = detail::string_to_location_coordinate(str);
371  return *this;
372  }
373 
374  template <typename T>
375  T as_string(T iterator, const char separator = ',') const {
376  if (!valid()) {
377  throw osmium::invalid_location("invalid location");
378  }
379  iterator = detail::append_location_coordinate_to_string(iterator, x());
380  *iterator++ = separator;
381  return detail::append_location_coordinate_to_string(iterator, y());
382  }
383 
384  }; // class Location
385 
389  inline constexpr bool operator==(const Location& lhs, const Location& rhs) noexcept {
390  return lhs.x() == rhs.x() && lhs.y() == rhs.y();
391  }
392 
393  inline constexpr bool operator!=(const Location& lhs, const Location& rhs) noexcept {
394  return ! (lhs == rhs);
395  }
396 
402  inline constexpr bool operator<(const Location& lhs, const Location& rhs) noexcept {
403  return (lhs.x() == rhs.x() && lhs.y() < rhs.y()) || lhs.x() < rhs.x();
404  }
405 
406  inline constexpr bool operator>(const Location& lhs, const Location& rhs) noexcept {
407  return rhs < lhs;
408  }
409 
410  inline constexpr bool operator<=(const Location& lhs, const Location& rhs) noexcept {
411  return ! (rhs < lhs);
412  }
413 
414  inline constexpr bool operator>=(const Location& lhs, const Location& rhs) noexcept {
415  return ! (lhs < rhs);
416  }
417 
421  template <typename TChar, typename TTraits>
422  inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const osmium::Location& location) {
423  if (location) {
424  out << '(';
425  location.as_string(std::ostream_iterator<char>(out), ',');
426  out << ')';
427  } else {
428  out << "(undefined,undefined)";
429  }
430  return out;
431  }
432 
433  namespace detail {
434 
435  template <int N>
436  inline size_t hash(const osmium::Location& location) noexcept {
437  return location.x() ^ location.y();
438  }
439 
440  template <>
441  inline size_t hash<8>(const osmium::Location& location) noexcept {
442  size_t h = location.x();
443  h <<= 32;
444  return h ^ location.y();
445  }
446 
447  } // namespace detail
448 
449 } // namespace osmium
450 
451 namespace std {
452 
453 // This pragma is a workaround for a bug in an old libc implementation
454 #ifdef __clang__
455 #pragma clang diagnostic push
456 #pragma clang diagnostic ignored "-Wmismatched-tags"
457 #endif
458  template <>
459  struct hash<osmium::Location> {
461  using result_type = size_t;
462  size_t operator()(const osmium::Location& location) const noexcept {
463  return osmium::detail::hash<sizeof(size_t)>(location);
464  }
465  };
466 #ifdef __clang__
467 #pragma clang diagnostic pop
468 #endif
469 
470 } // namespace std
471 
472 #endif // OSMIUM_OSM_LOCATION_HPP
double lat_without_check() const
Definition: location.hpp:350
static int32_t double_to_fix(const double c) noexcept
Definition: location.hpp:229
bool operator<=(const Changeset &lhs, const Changeset &rhs)
Definition: changeset.hpp:446
constexpr bool operator==(const Box &lhs, const Box &rhs) noexcept
Definition: box.hpp:222
Location & set_lon(double lon) noexcept
Definition: location.hpp:354
Definition: reader_iterator.hpp:39
constexpr Location(const int64_t x, const int64_t y) noexcept
Definition: location.hpp:260
constexpr Location(const int32_t x, const int32_t y) noexcept
Definition: location.hpp:250
constexpr bool valid() const noexcept
Definition: location.hpp:291
double lat() const
Definition: location.hpp:340
T as_string(T iterator, const char separator= ',') const
Definition: location.hpp:375
size_t operator()(const osmium::Location &location) const noexcept
Definition: location.hpp:462
bool operator<(const Changeset &lhs, const Changeset &rhs)
Definition: changeset.hpp:438
double lon_without_check() const
Definition: location.hpp:331
Namespace for everything in the Osmium library.
Definition: assembler.hpp:66
Definition: attr.hpp:298
Definition: location.hpp:54
int32_t m_y
Definition: location.hpp:219
constexpr int32_t y() const noexcept
Definition: location.hpp:302
invalid_location(const std::string &what)
Definition: location.hpp:56
Location & set_lat(double lat) noexcept
Definition: location.hpp:359
Location & set_y(const int32_t y) noexcept
Definition: location.hpp:311
Location & set_lat(const char *str) noexcept
Definition: location.hpp:369
Definition: location.hpp:216
int32_t m_x
Definition: location.hpp:218
Location & set_x(const int32_t x) noexcept
Definition: location.hpp:306
bool operator>=(const Changeset &lhs, const Changeset &rhs)
Definition: changeset.hpp:450
double lon() const
Definition: location.hpp:321
Location & set_lon(const char *str) noexcept
Definition: location.hpp:364
bool operator>(const Changeset &lhs, const Changeset &rhs)
Definition: changeset.hpp:442
invalid_location(const char *what)
Definition: location.hpp:60
constexpr int32_t x() const noexcept
Definition: location.hpp:298
static constexpr double fix_to_double(const int32_t c) noexcept
Definition: location.hpp:233
Location(const double lon, const double lat)
Definition: location.hpp:268
bool operator!=(const Changeset &lhs, const Changeset &rhs)
Definition: changeset.hpp:431
size_t result_type
Definition: location.hpp:461
constexpr Location() noexcept
Definition: location.hpp:240