World Builder  1.1.0-pre
A geodynamic initial conditions generator
point.h
Go to the documentation of this file.
1 /*
2  Copyright (C) 2018-2024 by the authors of the World Builder code.
3 
4  This file is part of the World Builder.
5 
6  This program is free software: you can redistribute it and/or modify
7  it under the terms of the GNU Lesser General Public License as published
8  by the Free Software Foundation, either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19 
20 #ifndef WORLD_BUILDER_POINT_H
21 #define WORLD_BUILDER_POINT_H
22 #include "nan.h"
23 #define _USE_MATH_DEFINES
24 #include <array>
25 #include <cmath>
26 #include <limits>
27 #include <iostream>
28 
29 #include "world_builder/assert.h"
30 #include "world_builder/consts.h"
32 
33 namespace WorldBuilder
34 {
35 
40  namespace FT
41  {
45  inline double fmod(const double x, const double y)
46  {
47  if (y < 0.0 || y > 0.0)
48  {
49  const double x_div_y = x/y;
50  return (x_div_y-static_cast<int>(x_div_y))*y;
51  }
52  return NaN::DQNAN;
53  }
54 
66  inline double fast_sin_d(const double angle)
67  {
68  constexpr double A = 4.0/(Consts::PI * Consts::PI);
69  constexpr double oneminPmin = 1.-0.1952403377008734-0.01915214119105392;
70 
71  const double y = A* angle * ( Consts::PI - angle );
72  return y*( oneminPmin + y*( 0.1952403377008734 + y * 0.01915214119105392 ) ) ;
73  }
74 
81  inline double sin(const double raw_angle)
82  {
83  const double angle = (raw_angle > -Consts::PI && raw_angle < Consts::PI)
84  ?
85  raw_angle
86  :
87  FT::fmod(raw_angle + std::copysign(Consts::PI,raw_angle), Consts::PI * 2.0) - std::copysign(Consts::PI,raw_angle);
88 
89  if (angle >= 0)
90  return fast_sin_d(angle);
91  return -fast_sin_d(-angle);
92  }
93 
97  inline double cos(const double angle)
98  {
99  return FT::sin((Consts::PI*0.5)-angle);
100  }
101  } // namespace FT
102 
103 
110  template<unsigned int dim>
111  class Point
112  {
113  public:
118  inline
119  Point(CoordinateSystem coordinate_system_)
120  :
121  point(std::array<double,dim>()),
122  coordinate_system(coordinate_system_)
123  {}
124 
129  inline
130  Point(const std::array<double,dim> &location, CoordinateSystem coordinate_system_)
131  :
132  point(location),
133  coordinate_system(coordinate_system_)
134  {}
135 
140  inline
141  Point(const Point<dim> &location, CoordinateSystem coordinate_system_)
142  :
143  point(location.get_array()),
144  coordinate_system(coordinate_system_)
145  {}
146 
150  inline
151  Point(const Point<dim> &location)
152  :
153  point(location.get_array()),
154  coordinate_system(location.get_coordinate_system())
155  {}
156 
161  Point(const double x, const double y, CoordinateSystem coordinate_system);
162 
167  Point(const double x, const double y, const double z, CoordinateSystem coordinate_system);
168 
172  inline
173  ~Point() = default;
174 
175  inline
176  Point<dim> &operator=(const Point<dim> &point_right)
177  {
178  point = point_right.point;
179  coordinate_system = point_right.coordinate_system;
180  return *this;
181  }
182 
186  inline
187  double operator*(const Point<dim> &point_right) const
188  {
189  WBAssert(coordinate_system == point_right.get_coordinate_system(),
190  "Cannot take the dot product of two points which represent different coordinate systems.");
191  const std::array<double,dim> &array = point_right.get_array();
192  double dot_product = 0;
193  for (unsigned int i = 0; i < dim; ++i)
194  dot_product += point[i] * array[i];
195  return dot_product;
196  }
197 
198 
202  inline
203  Point<dim> operator*(const double scalar) const
204  {
205  // initialize the array to zero.
206  std::array<double,dim> array;
207  for (unsigned int i = 0; i < dim; ++i)
208  array[i] = point[i] * scalar;
209  return Point<dim>(array,coordinate_system);
210  }
211 
215  inline
216  Point<dim> operator/(const double scalar) const
217  {
218  // initialize the array to zero.
219  std::array<double,dim> array;
220  const double one_over_scalar = 1/scalar;
221  for (unsigned int i = 0; i < dim; ++i)
222  array[i] = point[i] * one_over_scalar;
223  return Point<dim>(array,coordinate_system);
224  }
225 
229  inline
230  Point<dim> operator+(const Point<dim> &point_right) const
231  {
232  WBAssert(coordinate_system == point_right.get_coordinate_system(),
233  "Cannot add two points which represent different coordinate systems.");
234  Point<dim> point_tmp(point,coordinate_system);
235  for (unsigned int i = 0; i < dim; ++i)
236  point_tmp[i] += point_right[i];
237 
238  return point_tmp;
239  }
240 
241 
245  inline
246  Point<dim> operator-(const Point<dim> &point_right) const
247  {
248  WBAssert(coordinate_system == point_right.get_coordinate_system(),
249  "Cannot subtract two points which represent different coordinate systems. Internal has type " << static_cast<int>(coordinate_system)
250  << ", other point has type " << static_cast<int>(point_right.get_coordinate_system()));
251  Point<dim> point_tmp(point,coordinate_system);
252  for (unsigned int i = 0; i < dim; ++i)
253  point_tmp[i] -= point_right[i];
254 
255  return point_tmp;
256  }
257 
258 
262  inline
263  Point<dim> &operator*=(const double scalar)
264  {
265  for (unsigned int i = 0; i < dim; ++i)
266  point[i] *= scalar;
267  return *this;
268  }
272  inline
273  Point<dim> &operator/=(const double scalar)
274  {
275  for (unsigned int i = 0; i < dim; ++i)
276  point[i] /= scalar;
277  return *this;
278  }
279 
283  inline
284  Point<dim> &operator+=(const Point<dim> &point_right)
285  {
286  WBAssert(coordinate_system == point_right.get_coordinate_system(),
287  "Cannot add two points which represent different coordinate systems.");
288  for (unsigned int i = 0; i < dim; ++i)
289  point[i] += point_right[i];
290  return *this;
291  }
292 
298  inline
299  bool operator==(const Point<dim> &point_) const
300  {
301  if (coordinate_system != point_.coordinate_system)
302  return false;
303  WorldBuilder::Point<dim> point_tmp(point,coordinate_system);
304  point_tmp -= point_;
305  if (std::fabs(point_tmp[0]) > std::numeric_limits<double>::epsilon())
306  return false;
307  if (std::fabs(point_tmp[1]) > std::numeric_limits<double>::epsilon())
308  return false;
309  if (dim == 3 && std::fabs(point_tmp[2]) > std::numeric_limits<double>::epsilon())
310  return false;
311 
312  return true;
313  }
314 
318  inline
319  Point<dim> &operator-=(const Point<dim> &point_right)
320  {
321  WBAssert(coordinate_system == point_right.get_coordinate_system(),
322  "Cannot subtract two points which represent different coordinate systems.");
323  for (unsigned int i = 0; i < dim; ++i)
324  point[i] -= point_right[i];
325  return *this;
326  }
327 
331  inline
332  const double &operator[](const size_t index) const
333  {
334  WBAssert(index <= dim, "Can't ask for element " << index << " in an point with dimension " << dim << '.');
335  return point[index];
336  }
337 
338 
342  inline double &operator[](const size_t index)
343  {
344  WBAssert(index <= dim, "Can't ask for element " << index << " in an point with dimension " << dim << '.');
345  return point[index];
346  }
347 
352  double
353  distance(const Point<2> &two) const;
354 
363  double
365  {
366  const double d_longitude = two[0] - this->point[0];
367  const double d_latitude = two[1] - this->point[1];
368  const double sin_d_lat = FT::sin(d_latitude * 0.5);
369  const double sin_d_long = FT::sin(d_longitude * 0.5);
370  return (sin_d_lat * sin_d_lat) + (sin_d_long*sin_d_long) * FT::cos(this->point[1]) * FT::cos(two[1]);
371  }
372 
381  double
383  {
384  const double x_distance_to_reference_point = point[0]-two[0];
385  const double y_distance_to_reference_point = point[1]-two[1];
386  return (x_distance_to_reference_point*x_distance_to_reference_point) + (y_distance_to_reference_point*y_distance_to_reference_point);
387  }
388 
392  inline
393  const std::array<double,dim> &get_array() const
394  {
395  return point;
396  }
397 
398 
402  inline
404  {
405  return coordinate_system;
406  }
407 
408 
412  inline
413  double norm() const
414  {
415  return std::sqrt(this->norm_square());
416  }
417 
418 
423  inline
424  double norm_square() const
425  {
426  WBAssertThrow(false,"This function is only available in 2d or 3d.");
427  return 0;
428  }
429 
434  friend std::ostream &operator<<( std::ostream &output, const Point<dim> &stream_point )
435  {
436  for (size_t i = 0; i < dim-1; i++)
437  {
438  output << stream_point[i] << ' ';
439  }
440  output << stream_point[dim-1];
441 
442  return output;
443  }
444 
445 
446  private:
447  std::array<double,dim> point;
449 
450  };
451 
452  template <>
453  inline
454  double Point<2>::norm_square() const
455  {
456  return (point[0] * point[0]) + (point[1] * point[1]);
457  }
458 
459  template <>
460  inline
461  double Point<3>::norm_square() const
462  {
463  return (point[0] * point[0]) + (point[1] * point[1]) + (point[2] * point[2]);
464  }
465 
466  template<unsigned int dim>
467  inline
468  Point<dim> operator*(const double scalar, const Point<dim> &point)
469  {
470  return point*scalar;
471  }
472 } // namespace WorldBuilder
473 #endif
std::array< double, dim > point
Definition: point.h:447
double & operator[](const size_t index)
Definition: point.h:342
Point< dim > & operator+=(const Point< dim > &point_right)
Definition: point.h:284
Point< dim > & operator/=(const double scalar)
Definition: point.h:273
double fmod(const double x, const double y)
Definition: point.h:45
Point< dim > operator+(const Point< dim > &point_right) const
Definition: point.h:230
Point< dim > & operator=(const Point< dim > &point_right)
Definition: point.h:176
CoordinateSystem coordinate_system
Definition: point.h:448
double norm_square() const
Definition: point.h:424
Point< dim > operator-(const Point< dim > &point_right) const
Definition: point.h:246
double operator*(const Point< dim > &point_right) const
Definition: point.h:187
bool operator==(const Point< dim > &point_) const
Definition: point.h:299
Point< dim > operator*(const double scalar) const
Definition: point.h:203
template Point< 2 > operator*(const double scalar, const Point< 2 > &point)
CoordinateSystem get_coordinate_system() const
Definition: point.h:403
Point(const Point< dim > &location)
Definition: point.h:151
const std::array< double, dim > & get_array() const
Definition: point.h:393
const double DQNAN
Definition: nan.h:32
#define WBAssert(condition, message)
Definition: assert.h:27
double norm() const
Definition: point.h:413
double cheap_relative_distance_cartesian(const Point< 2 > &two) const
Definition: point.h:382
double cheap_relative_distance_spherical(const Point< 2 > &two) const
Definition: point.h:364
double cos(const double angle)
Definition: point.h:97
Point< dim > operator/(const double scalar) const
Definition: point.h:216
Point(const std::array< double, dim > &location, CoordinateSystem coordinate_system_)
Definition: point.h:130
Point< dim > & operator-=(const Point< dim > &point_right)
Definition: point.h:319
#define WBAssertThrow(condition, message)
Definition: assert.h:40
Point(const Point< dim > &location, CoordinateSystem coordinate_system_)
Definition: point.h:141
double fast_sin_d(const double angle)
Definition: point.h:66
double sin(const double raw_angle)
Definition: point.h:81
constexpr double PI
Definition: consts.h:30
Point(CoordinateSystem coordinate_system_)
Definition: point.h:119
const double & operator[](const size_t index) const
Definition: point.h:332
Point< dim > & operator*=(const double scalar)
Definition: point.h:263