Libosmium  2.8.0
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 <iomanip>
40 #include <iosfwd>
41 #include <locale>
42 #include <sstream>
43 #include <stdexcept>
44 #include <string>
45 
46 #include <iostream>
47 
49 #include <osmium/util/double.hpp>
50 
51 namespace osmium {
52 
57  struct invalid_location : public std::range_error {
58 
59  explicit invalid_location(const std::string& what) :
60  std::range_error(what) {
61  }
62 
63  explicit invalid_location(const char* what) :
64  std::range_error(what) {
65  }
66 
67  }; // struct invalid_location
68 
69  namespace detail {
70 
71  constexpr const int coordinate_precision = 10000000;
72 
73  // Fallback function used when a coordinate is written in scientific
74  // notation. This function uses stringstream and is much more expensive
75  // than the handcrafted one. But coordinates in scientific notations
76  // shouldn't be used anyway.
77  inline int32_t string_to_location_coordinate_fallback(const char* str) {
78  double value;
79  std::istringstream ss{str};
80  ss.imbue(std::locale("C"));
81  ss >> std::noskipws >> value;
82 
83  if (ss.fail() || !ss.eof() || ss.bad() || value > 215.0 || value < -215.0) {
84  throw invalid_location{std::string{"wrong format for coordinate: '"} + str + "'"};
85  }
86 
87  return std::round(value * coordinate_precision);
88  }
89 
90  // Convert string with a floating point number into integer suitable
91  // for use as coordinate in a Location.
92  inline int32_t string_to_location_coordinate(const char* str) {
93  const char* full = str;
94 
95  // call fallback if scientific notation is used
96  while (*str) {
97  if (*str == 'e' || *str == 'E') {
98  return string_to_location_coordinate_fallback(full);
99  }
100  ++str;
101  }
102 
103  str = full;
104 
105  int32_t result = 0;
106  int sign = 1;
107  int scale = 7;
108 
109  // optional minus sign
110  if (*str == '-') {
111  sign = -1;
112  ++str;
113  }
114 
115  // first digit before decimal point
116  if (*str >= '0' && *str <= '9') {
117  result = *str - '0';
118  ++str;
119  } else {
120  goto error;
121  }
122 
123  // optional second digit before decimal point
124  if (*str >= '0' && *str <= '9') {
125  result = result * 10 + *str - '0';
126  ++str;
127 
128  // optional third digit before decimal point
129  if (*str >= '0' && *str <= '9') {
130  result = result * 10 + *str - '0';
131  ++str;
132  }
133  }
134 
135  if (*str != '\0') {
136 
137  // decimal point
138  if (*str != '.') {
139  goto error;
140  }
141 
142  ++str;
143 
144  // read significant digits
145  for (; scale > 0 && *str >= '0' && *str <= '9'; --scale, ++str) {
146  result = result * 10 + (*str - '0');
147  }
148 
149  // use 8th digit after decimal point for rounding
150  if (scale == 0 && *str >= '5' && *str <= '9') {
151  ++result;
152  ++str;
153  }
154 
155  // ignore further digits
156  while (*str >= '0' && *str <= '9') {
157  ++str;
158  }
159 
160  // should be at the end now
161  if (*str != '\0') {
162  goto error;
163  }
164 
165  }
166 
167  for (; scale > 0; --scale) {
168  result *= 10;
169  }
170 
171  return result * sign;
172 
173  error:
174 
175  throw invalid_location{std::string{"wrong format for coordinate: '"} + full + "'"};
176  }
177 
178  // Convert integer as used by location for coordinates into a string.
179  template <typename T>
180  inline T append_location_coordinate_to_string(T iterator, int32_t value) {
181  // handle negative values
182  if (value < 0) {
183  *iterator++ = '-';
184  value = -value;
185  }
186 
187  // write digits into temporary buffer
188  int32_t v = value;
189  char temp[10];
190  char* t = temp;
191  do {
192  *t++ = char(v % 10) + '0';
193  v /= 10;
194  } while (v != 0);
195 
196  while (t-temp < 7) {
197  *t++ = '0';
198  }
199 
200  // write out digits before decimal point
201  if (value >= coordinate_precision) {
202  if (value >= 10 * coordinate_precision) {
203  if (value >= 100 * coordinate_precision) {
204  *iterator++ = *--t;
205  }
206  *iterator++ = *--t;
207  }
208  *iterator++ = *--t;
209  } else {
210  *iterator++ = '0';
211  }
212 
213  // remove trailing zeros
214  const char* tn = temp;
215  while (tn < t && *tn == '0') {
216  ++tn;
217  }
218 
219  // decimal point
220  if (t != tn) {
221  *iterator++ = '.';
222  while (t != tn) {
223  *iterator++ = *--t;
224  }
225  }
226 
227  return iterator;
228  }
229 
230  } // namespace detail
231 
246  class Location {
247 
248  int32_t m_x;
249  int32_t m_y;
250 
251  public:
252 
253  // this value is used for a coordinate to mark it as undefined
254  // MSVC doesn't declare std::numeric_limits<int32_t>::max() as
255  // constexpr, so we hard code this for the time being.
256  // static constexpr int32_t undefined_coordinate = std::numeric_limits<int32_t>::max();
257  static constexpr int32_t undefined_coordinate = 2147483647;
258 
259  static int32_t double_to_fix(const double c) noexcept {
260  return static_cast<int32_t>(std::round(c * detail::coordinate_precision));
261  }
262 
263  static constexpr double fix_to_double(const int32_t c) noexcept {
264  return static_cast<double>(c) / detail::coordinate_precision;
265  }
266 
270  explicit constexpr Location() noexcept :
271  m_x(undefined_coordinate),
272  m_y(undefined_coordinate) {
273  }
274 
280  constexpr Location(const int32_t x, const int32_t y) noexcept :
281  m_x(x),
282  m_y(y) {
283  }
284 
290  constexpr Location(const int64_t x, const int64_t y) noexcept :
291  m_x(static_cast<int32_t>(x)),
292  m_y(static_cast<int32_t>(y)) {
293  }
294 
298  Location(const double lon, const double lat) :
299  m_x(double_to_fix(lon)),
300  m_y(double_to_fix(lat)) {
301  }
302 
303  Location(const Location&) = default;
304  Location(Location&&) = default;
305  Location& operator=(const Location&) = default;
306  Location& operator=(Location&&) = default;
307  ~Location() = default;
308 
313  explicit constexpr operator bool() const noexcept {
314  return m_x != undefined_coordinate && m_y != undefined_coordinate;
315  }
316 
321  constexpr bool valid() const noexcept {
322  return m_x >= -180 * detail::coordinate_precision
323  && m_x <= 180 * detail::coordinate_precision
324  && m_y >= -90 * detail::coordinate_precision
325  && m_y <= 90 * detail::coordinate_precision;
326  }
327 
328  constexpr int32_t x() const noexcept {
329  return m_x;
330  }
331 
332  constexpr int32_t y() const noexcept {
333  return m_y;
334  }
335 
336  Location& set_x(const int32_t x) noexcept {
337  m_x = x;
338  return *this;
339  }
340 
341  Location& set_y(const int32_t y) noexcept {
342  m_y = y;
343  return *this;
344  }
345 
351  double lon() const {
352  if (!valid()) {
353  throw osmium::invalid_location("invalid location");
354  }
355  return fix_to_double(m_x);
356  }
357 
361  double lon_without_check() const {
362  return fix_to_double(m_x);
363  }
364 
370  double lat() const {
371  if (!valid()) {
372  throw osmium::invalid_location("invalid location");
373  }
374  return fix_to_double(m_y);
375  }
376 
380  double lat_without_check() const {
381  return fix_to_double(m_y);
382  }
383 
384  Location& set_lon(double lon) noexcept {
385  m_x = double_to_fix(lon);
386  return *this;
387  }
388 
389  Location& set_lat(double lat) noexcept {
390  m_y = double_to_fix(lat);
391  return *this;
392  }
393 
394  Location& set_lon(const char* str) noexcept {
395  m_x = detail::string_to_location_coordinate(str);
396  return *this;
397  }
398 
399  Location& set_lat(const char* str) noexcept {
400  m_y = detail::string_to_location_coordinate(str);
401  return *this;
402  }
403 
404  template <typename T>
405  T as_string_without_check(T iterator, const char separator = ',') const {
406  iterator = detail::append_location_coordinate_to_string(iterator, x());
407  *iterator++ = separator;
408  return detail::append_location_coordinate_to_string(iterator, y());
409  }
410 
411  template <typename T>
412  T as_string(T iterator, const char separator = ',') const {
413  if (!valid()) {
414  throw osmium::invalid_location("invalid location");
415  }
416  return as_string_without_check(iterator, separator);
417  }
418 
419  }; // class Location
420 
424  inline constexpr bool operator==(const Location& lhs, const Location& rhs) noexcept {
425  return lhs.x() == rhs.x() && lhs.y() == rhs.y();
426  }
427 
428  inline constexpr bool operator!=(const Location& lhs, const Location& rhs) noexcept {
429  return ! (lhs == rhs);
430  }
431 
437  inline constexpr bool operator<(const Location& lhs, const Location& rhs) noexcept {
438  return (lhs.x() == rhs.x() && lhs.y() < rhs.y()) || lhs.x() < rhs.x();
439  }
440 
441  inline constexpr bool operator>(const Location& lhs, const Location& rhs) noexcept {
442  return rhs < lhs;
443  }
444 
445  inline constexpr bool operator<=(const Location& lhs, const Location& rhs) noexcept {
446  return ! (rhs < lhs);
447  }
448 
449  inline constexpr bool operator>=(const Location& lhs, const Location& rhs) noexcept {
450  return ! (lhs < rhs);
451  }
452 
456  template <typename TChar, typename TTraits>
457  inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const osmium::Location& location) {
458  if (location) {
459  out << '(';
460  location.as_string(std::ostream_iterator<char>(out), ',');
461  out << ')';
462  } else {
463  out << "(undefined,undefined)";
464  }
465  return out;
466  }
467 
468  namespace detail {
469 
470  template <int N>
471  inline size_t hash(const osmium::Location& location) noexcept {
472  return location.x() ^ location.y();
473  }
474 
475  template <>
476  inline size_t hash<8>(const osmium::Location& location) noexcept {
477  size_t h = location.x();
478  h <<= 32;
479  return h ^ location.y();
480  }
481 
482  } // namespace detail
483 
484 } // namespace osmium
485 
486 namespace std {
487 
488 // This pragma is a workaround for a bug in an old libc implementation
489 #ifdef __clang__
490 #pragma clang diagnostic push
491 #pragma clang diagnostic ignored "-Wmismatched-tags"
492 #endif
493  template <>
494  struct hash<osmium::Location> {
496  using result_type = size_t;
497  size_t operator()(const osmium::Location& location) const noexcept {
498  return osmium::detail::hash<sizeof(size_t)>(location);
499  }
500  };
501 #ifdef __clang__
502 #pragma clang diagnostic pop
503 #endif
504 
505 } // namespace std
506 
507 #endif // OSMIUM_OSM_LOCATION_HPP
double lat_without_check() const
Definition: location.hpp:380
static int32_t double_to_fix(const double c) noexcept
Definition: location.hpp:259
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:384
Definition: reader_iterator.hpp:39
constexpr Location(const int64_t x, const int64_t y) noexcept
Definition: location.hpp:290
constexpr Location(const int32_t x, const int32_t y) noexcept
Definition: location.hpp:280
double lat() const
Definition: location.hpp:370
T as_string(T iterator, const char separator= ',') const
Definition: location.hpp:412
bool operator<(const Changeset &lhs, const Changeset &rhs)
Definition: changeset.hpp:438
double lon_without_check() const
Definition: location.hpp:361
Namespace for everything in the Osmium library.
Definition: assembler.hpp:66
Definition: attr.hpp:298
Definition: location.hpp:57
int32_t m_y
Definition: location.hpp:249
invalid_location(const std::string &what)
Definition: location.hpp:59
Location & set_lat(double lat) noexcept
Definition: location.hpp:389
Location & set_y(const int32_t y) noexcept
Definition: location.hpp:341
constexpr bool valid() const noexcept
Definition: location.hpp:321
Location & set_lat(const char *str) noexcept
Definition: location.hpp:399
Definition: location.hpp:246
int32_t m_x
Definition: location.hpp:248
Location & set_x(const int32_t x) noexcept
Definition: location.hpp:336
bool operator>=(const Changeset &lhs, const Changeset &rhs)
Definition: changeset.hpp:450
T as_string_without_check(T iterator, const char separator= ',') const
Definition: location.hpp:405
double lon() const
Definition: location.hpp:351
Location & set_lon(const char *str) noexcept
Definition: location.hpp:394
bool operator>(const Changeset &lhs, const Changeset &rhs)
Definition: changeset.hpp:442
invalid_location(const char *what)
Definition: location.hpp:63
size_t operator()(const osmium::Location &location) const noexcept
Definition: location.hpp:497
constexpr int32_t x() const noexcept
Definition: location.hpp:328
static constexpr double fix_to_double(const int32_t c) noexcept
Definition: location.hpp:263
Location(const double lon, const double lat)
Definition: location.hpp:298
bool operator!=(const Changeset &lhs, const Changeset &rhs)
Definition: changeset.hpp:431
constexpr int32_t y() const noexcept
Definition: location.hpp:332
size_t result_type
Definition: location.hpp:496
constexpr Location() noexcept
Definition: location.hpp:270