World Builder  1.1.0-pre
A geodynamic initial conditions generator
utilities.cc
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 #include "world_builder/assert.h"
21 #include <algorithm>
22 #include <cmath>
23 #include <fstream>
24 #include <iomanip>
25 #include <iostream>
26 #include <limits>
27 #include <sstream>
28 
29 #ifdef WB_WITH_MPI
30 // we don't need the c++ MPI wrappers
31 #define OMPI_SKIP_MPICXX 1
32 #define MPICH_SKIP_MPICXX
33 #include <mpi.h>
34 #endif
35 
36 #include "world_builder/nan.h"
39 
40 
41 namespace WorldBuilder
42 {
43  namespace Utilities
44  {
45  bool
46  polygon_contains_point(const std::vector<Point<2> > &point_list,
47  const Point<2> &point)
48  {
50  {
51  Point<2> other_point = point;
52  other_point[0] += point[0] < 0 ? 2.0 * Consts::PI : -2.0 * Consts::PI;
53 
54  return (polygon_contains_point_implementation(point_list, point) ||
55  polygon_contains_point_implementation(point_list, other_point));
56  }
57 
58  return polygon_contains_point_implementation(point_list, point);
59 
60  }
61 
62  bool
63  polygon_contains_point_implementation(const std::vector<Point<2> > &point_list,
64  const Point<2> &point)
65  {
84  const size_t pointNo = point_list.size();
85  size_t wn = 0; // the winding number counter
86  size_t j=pointNo-1;
87 
88  // loop through all edges of the polygon
89  for (size_t i=0; i<pointNo; i++)
90  {
91  // edge from V[i] to V[i+1]
92  if (point_list[j][1] <= point[1])
93  {
94  // first check if a point is directly on a line (within epsilon)
95  if (approx(point_list[i][0],point[0]) && approx(point_list[i][1],point[1]))
96  return true;
97  // start y <= P.y
98  if (point_list[i][1] >= point[1]) // an upward crossing
99  {
100  const double is_left = (point_list[i][0] - point_list[j][0]) * (point[1] - point_list[j][1])
101  - (point[0] - point_list[j][0]) * (point_list[i][1] - point_list[j][1]);
102 
103  if ( is_left > 0 && point_list[i][1] > point[1])
104  {
105  // P left of edge
106  ++wn; // have a valid up intersect
107  }
108  else if ( std::abs(is_left) < std::numeric_limits<double>::epsilon())
109  {
110  // The point is exactly on the infinite line.
111  // determine if it is on the segment
112  const double dot_product = (point - point_list[j])*(point_list[i] - point_list[j]);
113 
114  if (dot_product >= 0)
115  {
116  const double squaredlength = (point_list[i] - point_list[j]).norm_square();
117 
118  if (dot_product <= squaredlength)
119  {
120  return true;
121  }
122  }
123  }
124  }
125  }
126  else
127  {
128  // start y > P.y (no test needed)
129  if (point_list[i][1] <= point[1]) // a downward crossing
130  {
131  const double is_left = (point_list[i][0] - point_list[j][0]) * (point[1] - point_list[j][1])
132  - (point[0] - point_list[j][0]) * (point_list[i][1] - point_list[j][1]);
133 
134  if ( is_left < 0)
135  {
136  // P right of edge
137  --wn; // have a valid down intersect
138  }
139  else if (std::abs(is_left) < std::numeric_limits<double>::epsilon())
140  {
141  // This code is to make sure that the boundaries are included in the polygon.
142  // The point is exactly on the infinite line.
143  // determine if it is on the segment
144  const double dot_product = (point - point_list[j])*(point_list[i] - point_list[j]);
145 
146  if (dot_product >= 0)
147  {
148  const double squaredlength = (point_list[i] - point_list[j]).norm_square();
149 
150  if (dot_product <= squaredlength)
151  {
152  return true;
153  }
154  }
155  }
156  }
157  }
158  j=i;
159  }
160 
161  return (wn != 0);
162  }
163 
164 
165 
166  double
167  fraction_from_ellipse_center(const Point<2> &ellipse_center,
168  const double semi_major_axis,
169  const double eccentricity,
170  const double theta,
171  const Point<2> &point)
172  {
173  const double x_rotated = (point[0] - ellipse_center[0]) * std::cos(theta) + (point[1] - ellipse_center[1])* std::sin(theta);
174  const double y_rotated = -(point[0] - ellipse_center[0]) * std::sin(theta) + (point[1] - ellipse_center[1])* std::cos(theta);
175 
176  const double semi_minor_axis = semi_major_axis * std::sqrt(1 - std::pow(eccentricity, 2));
177 
178  if (semi_major_axis < 10 * std::numeric_limits<double>::min()
179  || semi_minor_axis < 10 * std::numeric_limits<double>::min())
180  return false;
181 
182  const double ellipse = std::pow((x_rotated), 2) / std::pow(semi_major_axis, 2)
183  + std::pow((y_rotated), 2) / std::pow(semi_minor_axis, 2);
184 
185  return ellipse;
186  }
187 
188 
189 
190  double
191  signed_distance_to_polygon(const std::vector<Point<2> > &point_list,
192  const Point<2> &point)
193  {
194  // If the point lies outside polygon, we give it a negative sign,
195  // inside a positive sign.
196  const double sign = polygon_contains_point(point_list, point) ? 1.0 : -1.0;
197 
211  const size_t n_poly_points = point_list.size();
212  WBAssertThrow(n_poly_points >= 3, "Not enough polygon points were specified.");
213 
214  // Initialize a vector of distances for each point of the polygon with a very large distance
215  std::vector<double> distances(n_poly_points, 1e23);
216 
217  // Create another polygon but with all points shifted 1 position to the right
218  std::vector<Point<2> > shifted_point_list(n_poly_points, Point<2>(point.get_coordinate_system()));
219  shifted_point_list[0] = point_list[n_poly_points-1];
220 
221  for (size_t i = 0; i < n_poly_points-1; ++i)
222  shifted_point_list[i+1] = point_list[i];
223 
224  for (size_t i = 0; i < n_poly_points; ++i)
225  {
226  // Create vector along the polygon line segment
227  const Point<2> vector_segment = shifted_point_list[i] - point_list[i];
228  // Create vector from point to the second segment point
229  const Point<2> vector_point_segment = point - point_list[i];
230 
231  // Compute dot products to get angles
232  const double c1 = vector_point_segment * vector_segment;
233  const double c2 = vector_segment * vector_segment;
234 
235  // point lies closer to not-shifted polygon point, but perpendicular base line lies outside segment
236  if (c1 <= 0.0)
237  distances[i] = (Point<2> (point_list[i] - point)).norm();
238  // point lies closer to shifted polygon point, but perpendicular base line lies outside segment
239  else if (c2 <= c1)
240  distances[i] = (Point<2> (shifted_point_list[i] - point)).norm();
241  // perpendicular base line lies on segment
242  else
243  {
244  const Point<2> point_on_segment = point_list[i] + (c1/c2) * vector_segment;
245  distances[i] = (Point<2> (point - point_on_segment)).norm();
246  }
247  }
248 
249  // Return the minimum of the distances of the point to all polygon segments
250  return *std::min_element(distances.begin(),distances.end()) * sign;
251  }
252 
253 
254  std::array<double,3>
256  {
257  std::array<double,3> scoord;
258 
259  scoord[0] = position.norm(); // R
260  scoord[1] = std::atan2(position[1],position[0]); // Phi/long -> The result is always between -180 and 180 degrees: [-pi,pi]
261  //if (scoord[1] < 0.0)
262  //scoord[1] += 2.0*Consts::PI; // correct phi to [0,2*pi]
263 
264  //lat
265  if (scoord[0] > std::numeric_limits<double>::min())
266  scoord[2] = 0.5 * Consts::PI - std::acos(position[2]/scoord[0]);
267  else
268  scoord[2] = 0.0;
269 
270  return scoord;
271  }
272 
273  Point<3>
274  spherical_to_cartesian_coordinates(const std::array<double,3> &scoord)
275  {
276  const double cos_lat = scoord[0] * std::sin(0.5 * Consts::PI - scoord[2]);
277 
278  return Point<3>(cos_lat * std::cos(scoord[1]), // X
279  cos_lat * std::sin(scoord[1]), // Y
280  scoord[0] * std::cos(0.5 * Consts::PI - scoord[2]), // Z
281  cartesian);;
282  }
283 
284 
285 
287  string_to_coordinate_system(const std::string &coordinate_system)
288  {
289  if (coordinate_system == "cartesian")
291  if (coordinate_system == "spherical")
293  WBAssertThrow(false, "Coordinate system not implemented.");
294 
295  return invalid;
296  }
297 
298 
299  template<unsigned int dim>
300  std::array<double,dim>
302  {
303  std::array<double,dim> array;
304  for (size_t i = 0; i < dim; ++i)
305  array[i] = point_[i];
306  return array;
307  }
308 
309  double
310  string_to_double(const std::string &string)
311  {
312  // trim whitespace on either side of the text if necessary
313  std::string s = string;
314  while ((!s.empty()) && (s[0] == ' '))
315  s.erase(s.begin());
316  while ((!s.empty()) && (s[s.size() - 1] == ' '))
317  s.erase(s.end() - 1);
318 
319  std::istringstream i(s);
320  double d;
321  char c;
322  if (!(i >> d) || i.get(c))
323  WBAssertThrow(false, "Could not convert \"" + s + "\" to a double.");
324 
325  return d;
326  }
327 
328  int
329  string_to_int(const std::string &string)
330  {
331  // trim whitespace on either side of the text if necessary
332  std::string s = string;
333  while ((!s.empty()) && (s[0] == ' '))
334  s.erase(s.begin());
335  while ((!s.empty()) && (s[s.size() - 1] == ' '))
336  s.erase(s.end() - 1);
337 
338  std::istringstream i(s);
339  int d;
340  char c;
341  if (!(i >> d) || i.get(c))
342  WBAssertThrow(false, "Could not convert \"" + s + "\" to an int.");
343 
344  return d;
345  }
346 
347 
348  unsigned int
349  string_to_unsigned_int(const std::string &string)
350  {
351  // trim whitespace on either side of the text if necessary
352  std::string s = string;
353  while ((!s.empty()) && (s[0] == ' '))
354  s.erase(s.begin());
355  while ((!s.empty()) && (s[s.size() - 1] == ' '))
356  s.erase(s.end() - 1);
357 
358 
359  std::istringstream i(s);
360  unsigned int d;
361  char c;
362  if (!(i >> d) || i.get(c))
363  WBAssertThrow(false, "Could not convert \"" + s + "\" to an unsigned int.");
364 
365  return d;
366  }
367 
368 
369  Point<3>
370  cross_product(const Point<3> &a, const Point<3> &b)
371  {
372  WBAssert(a.get_coordinate_system() == b.get_coordinate_system(), "Trying to do a cross product of points of a different coordinate system.");
373  const double x = a[1] * b[2] - b[1] * a[2];
374  const double y = a[2] * b[0] - b[2] * a[0];
375  const double z = a[0] * b[1] - b[0] * a[1];
376  return Point<3>(x,y,z,a.get_coordinate_system());
377  }
378 
380  distance_point_from_curved_planes(const Point<3> &check_point, // cartesian point in cartesian and spherical system
381  const Objects::NaturalCoordinate &natural_coordinate, // cartesian point cartesian system, spherical point in spherical system
382  const Point<2> &reference_point, // in (rad) spherical coordinates in spherical system
383  const std::vector<Point<2> > &point_list, // in (rad) spherical coordinates in spherical system
384  const std::vector<std::vector<double> > &plane_segment_lengths,
385  const std::vector<std::vector<Point<2> > > &plane_segment_angles,
386  const double start_radius,
387  const std::unique_ptr<CoordinateSystems::Interface> &coordinate_system,
388  const bool only_positive,
389  const Objects::BezierCurve &bezier_curve)
390  {
391  double distance = std::numeric_limits<double>::infinity();
392  double new_distance = std::numeric_limits<double>::infinity();
393  double along_plane_distance = std::numeric_limits<double>::infinity();
394  double new_along_plane_distance = std::numeric_limits<double>::infinity();
395  double new_depth_reference_surface = std::numeric_limits<double>::infinity();
396 
397  const CoordinateSystem natural_coordinate_system = coordinate_system->natural_coordinate_system();
398  const bool bool_cartesian = natural_coordinate_system == cartesian;
399 
400  const std::array<double,3> &check_point_surface_2d_array = natural_coordinate.get_coordinates();
401  const Point<3> check_point_surface(bool_cartesian ? check_point_surface_2d_array[0] : start_radius,
402  check_point_surface_2d_array[1],
403  bool_cartesian ? start_radius : check_point_surface_2d_array[2],
404  natural_coordinate_system);
405  const Point<2> check_point_surface_2d(natural_coordinate.get_surface_coordinates(),
406  natural_coordinate_system);
407 
408  // The section which is checked.
409  size_t section = 0;
410 
411  // The 'horizontal' fraction between the points at the surface.
412  double section_fraction = 0.0;
413 
414  // What segment the point on the line is in.
415  size_t segment = 0;
416 
417  // The 'vertical' fraction, indicates how far in the current segment the
418  // point on the line is.
419  double segment_fraction = 0.0;
420  double total_average_angle = 0.0;
421  double depth_reference_surface = 0.0;
422 
423  const DepthMethod depth_method = coordinate_system->depth_method();
424 
425  size_t i_section_min_distance = 0;
426  double fraction_CPL_P1P2 = std::numeric_limits<double>::infinity();
427 
428  // get an estimate for the closest point between P1 and P2.
429  //constexpr double parts = 1;
430  //constexpr double one_div_parts = 1./parts;
431  //double minimum_distance_to_reference_point = std::numeric_limits<double>::infinity();
432  //const size_t number_of_points = point_list.size();
433 
434  const Objects::ClosestPointOnCurve closest_point_on_curve = bezier_curve.closest_point_on_curve_segment(check_point_surface_2d);
435  Point<2> closest_point_on_line_2d = closest_point_on_curve.point;
436 
437  // We now need 3d points from this point on, so make them.
438  // The order of a Cartesian coordinate is x,y,z and the order of
439  // a spherical coordinate it radius, long, lat (in rad).
440  const Point<3> closest_point_on_line_surface(bool_cartesian ? closest_point_on_line_2d[0] : start_radius,
441  bool_cartesian ? closest_point_on_line_2d[1] : closest_point_on_line_2d[0],
442  bool_cartesian ? start_radius : closest_point_on_line_2d[1],
443  natural_coordinate_system);
444 
445  const Point<3> closest_point_on_line_cartesian(coordinate_system->natural_to_cartesian_coordinates(closest_point_on_line_surface.get_array()),cartesian);
446 
447  if (!std::isnan(closest_point_on_line_2d[0]))
448  {
449  i_section_min_distance = closest_point_on_curve.index;
450  fraction_CPL_P1P2 = closest_point_on_curve.parametric_fraction;
451 
452  Point<3> closest_point_on_line_bottom = closest_point_on_line_surface;
453  closest_point_on_line_bottom[bool_cartesian ? 2 : 0] = 0;
454 
455  WBAssert(!std::isnan(closest_point_on_line_bottom[0])
456  &&
457  !std::isnan(closest_point_on_line_bottom[1])
458  &&
459  !std::isnan(closest_point_on_line_bottom[2]),
460  "Internal error: The closest_point_on_line_bottom variables variable contains not a number: " << closest_point_on_line_bottom);
461 
462  // Now that we have both the check point and the
463  // closest_point_on_line, we need to push them to cartesian.
464  const Point<3> closest_point_on_line_bottom_cartesian(coordinate_system->natural_to_cartesian_coordinates(closest_point_on_line_bottom.get_array()),cartesian);
465  const Point<3> check_point_surface_cartesian(coordinate_system->natural_to_cartesian_coordinates(check_point_surface.get_array()),cartesian);
466 
467 
468  WBAssert(!std::isnan(closest_point_on_line_bottom_cartesian[0]),
469  "Internal error: The closest_point_on_line_bottom_cartesian[0] variable is not a number: " << closest_point_on_line_bottom_cartesian[0]);
470  WBAssert(!std::isnan(closest_point_on_line_bottom_cartesian[1]),
471  "Internal error: The closest_point_on_line_bottom_cartesian[1] variable is not a number: " << closest_point_on_line_bottom_cartesian[1]);
472  WBAssert(!std::isnan(closest_point_on_line_bottom_cartesian[2]),
473  "Internal error: The closest_point_on_line_bottom_cartesian[2] variable is not a number: " << closest_point_on_line_bottom_cartesian[2]);
474 
475 
476  // translate to original coordinates current and next section
477  const size_t original_current_section = i_section_min_distance;
478  const size_t original_next_section = original_current_section + 1;
479 
480 
481  // These are the mostly likely cases for the x and y axis, so initialize them to these values. They will be checked
482  // in the else statement or replaced in the if statement.
483  Point<3> y_axis = closest_point_on_line_cartesian - closest_point_on_line_bottom_cartesian;
484  Point<3> x_axis = closest_point_on_line_cartesian - check_point_surface_cartesian;
485 
486  // This are accounting for corner cases.
487  // If the point to check is exactly on or below the line, we can not compute the x-axis with this method.
488  // We could use an other method where we use the two point before and after it, but we can also
489  // just nudge it into a direction, which seems to work very well.
490  if (std::fabs((check_point_surface - closest_point_on_line_surface).norm()) < 2e-14)
491  {
492  // If the point to check is on the line, we don't need to search any further, because we know the distance is zero.
493  if (std::fabs((check_point - closest_point_on_line_cartesian).norm()) > 2e-14)
494  {
495  const Point<2> &P1(point_list[i_section_min_distance]);
496  const Point<2> &P2(point_list[i_section_min_distance+1]);
497 
498  const Point<2> P1P2 = P2 - P1;
499  const Point<2> unit_normal_to_plane_spherical = P1P2 / P1P2.norm();
500  const Point<2> closest_point_on_line_plus_normal_to_plane_spherical = closest_point_on_line_2d + 1e-8 * (closest_point_on_line_2d.norm() > 1.0 ? closest_point_on_line_2d.norm() : 1.0) * unit_normal_to_plane_spherical;
501 
502  WBAssert(std::fabs(closest_point_on_line_plus_normal_to_plane_spherical.norm()) > std::numeric_limits<double>::epsilon(),
503  "Internal error: The norm of variable 'closest_point_on_line_plus_normal_to_plane_spherical' "
504  "is zero, while this may not happen.");
505 
506  const Point<3> closest_point_on_line_plus_normal_to_plane_surface_spherical(bool_cartesian ? closest_point_on_line_plus_normal_to_plane_spherical[0] : start_radius,
507  bool_cartesian ? closest_point_on_line_plus_normal_to_plane_spherical[1] : closest_point_on_line_plus_normal_to_plane_spherical[0],
508  bool_cartesian ? start_radius : closest_point_on_line_plus_normal_to_plane_spherical[1],
509  natural_coordinate_system);
510  const Point<3> closest_point_on_line_plus_normal_to_plane_cartesian(coordinate_system->natural_to_cartesian_coordinates(closest_point_on_line_plus_normal_to_plane_surface_spherical.get_array()),cartesian);
511  Point<3> normal_to_plane = closest_point_on_line_plus_normal_to_plane_cartesian - closest_point_on_line_cartesian;
512  normal_to_plane = normal_to_plane / normal_to_plane.norm();
513 
514  // The y-axis is from the bottom/center to the closest_point_on_line,
515  // the x-axis is 90 degrees rotated from that, so we rotate around
516  // the line P1P2.
517  // Todo: Assert that the norm of the axis are not equal to zero.
518  y_axis = closest_point_on_line_cartesian - closest_point_on_line_bottom_cartesian;
519 
520  WBAssert(std::abs(y_axis.norm()) > std::numeric_limits<double>::epsilon(),
521  "World Builder error: Cannot determine the up direction in the model. This is most likely due to the provided start radius being zero."
522  << " Technical details: The y_axis.norm() is zero. Y_axis is " << y_axis[0] << ':' << y_axis[1] << ':' << y_axis[2]
523  << ". closest_point_on_line_cartesian = " << closest_point_on_line_cartesian[0] << ':' << closest_point_on_line_cartesian[1] << ':' << closest_point_on_line_cartesian[2]
524  << ", closest_point_on_line_bottom_cartesian = " << closest_point_on_line_bottom_cartesian[0] << ':' << closest_point_on_line_bottom_cartesian[1] << ':' << closest_point_on_line_bottom_cartesian[2]);
525 
526  WBAssert(!std::isnan(y_axis[0]),
527  "Internal error: The y_axis variable is not a number: " << y_axis[0]);
528  WBAssert(!std::isnan(y_axis[1]),
529  "Internal error: The y_axis variable is not a number: " << y_axis[1]);
530  WBAssert(!std::isnan(y_axis[2]),
531  "Internal error: The y_axis variable is not a number: " << y_axis[2]);
532 
533  y_axis = y_axis / y_axis.norm();
534 
535  WBAssert(!std::isnan(y_axis[0]),
536  "Internal error: The y_axis variable is not a number: " << y_axis[0]);
537  WBAssert(!std::isnan(y_axis[1]),
538  "Internal error: The y_axis variable is not a number: " << y_axis[1]);
539  WBAssert(!std::isnan(y_axis[2]),
540  "Internal error: The y_axis variable is not a number: " << y_axis[2]);
541 
542 
543  // shorthand notation for computing the x_axis
544  const double vx = y_axis[0];
545  const double vy = y_axis[1];
546  const double vz = y_axis[2];
547  const double ux = normal_to_plane[0];
548  const double uy = normal_to_plane[1];
549  const double uz = normal_to_plane[2];
550 
551  x_axis = Point<3>(ux*ux*vx + ux*uy*vy - uz*vy + uy*uz*vz + uy*vz,
552  uy*ux*vx + uz*vx + uy*uy*vy + uy*uz*vz - ux*vz,
553  uz*ux*vx - uy*vx + uz*uy*vy + ux*vy + uz*uz*vz,
554  cartesian);
555 
556  // see on what side the line P1P2 reference point is. This is based on the determinant
557  const Point<2> reference_p = ((closest_point_on_curve.normal-closest_point_on_line_2d)*1e2)+closest_point_on_line_2d;
558  const double reference_on_side_of_line = (closest_point_on_line_2d-reference_p).norm_square() < (check_point_surface_2d-reference_p).norm_square() ? -1 : 1;
559 
560  WBAssert(!std::isnan(x_axis[0]),
561  "Internal error: The x_axis variable is not a number: " << x_axis[0]);
562  WBAssert(!std::isnan(x_axis[1]),
563  "Internal error: The x_axis variable is not a number: " << x_axis[1]);
564  WBAssert(!std::isnan(x_axis[2]),
565  "Internal error: The x_axis variable is not a number: " << x_axis[2]);
566 
567  x_axis = x_axis *(reference_on_side_of_line / x_axis.norm());
568 
569  WBAssert(!std::isnan(x_axis[0]),
570  "Internal error: The x_axis variable is not a number: " << x_axis[0]);
571  WBAssert(!std::isnan(x_axis[1]),
572  "Internal error: The x_axis variable is not a number: " << x_axis[1]);
573  WBAssert(!std::isnan(x_axis[2]),
574  "Internal error: The x_axis variable is not a number: " << x_axis[2]);
575  }
576  else
577  {
578  total_average_angle = plane_segment_angles[original_current_section][0][0]
579  + fraction_CPL_P1P2 * (plane_segment_angles[original_next_section][0][0]
580  - plane_segment_angles[original_current_section][0][0]);
581 
582  PointDistanceFromCurvedPlanes return_values(natural_coordinate.get_coordinate_system());
583  return_values.distance_from_plane = 0.0;
584  return_values.distance_along_plane = 0.0;
585  return_values.fraction_of_section = fraction_CPL_P1P2;
586  return_values.fraction_of_segment = 0.0;
587  return_values.section = i_section_min_distance;
588  return_values.segment = 0;
589  return_values.average_angle = total_average_angle;
590  return_values.depth_reference_surface = 0.0;
591  return_values.closest_trench_point = closest_point_on_line_cartesian;
592  return return_values;
593  }
594  }
595  else
596  {
597  WBAssert(std::abs(y_axis.norm()) > std::numeric_limits<double>::epsilon(),
598  "World Builder error: Cannot determine the up direction in the model. This is most likely due to the provided start radius being zero."
599  << " Technical details: The y_axis.norm() is zero. Y_axis is " << y_axis
600  << ". closest_point_on_line_cartesian = " << closest_point_on_line_cartesian
601  << ", closest_point_on_line_bottom_cartesian = " << closest_point_on_line_bottom_cartesian);
602 
603  WBAssert(!std::isnan(y_axis[0]),
604  "Internal error: The y_axis variable is not a number: " << y_axis[0]);
605  WBAssert(!std::isnan(y_axis[1]),
606  "Internal error: The y_axis variable is not a number: " << y_axis[1]);
607  WBAssert(!std::isnan(y_axis[2]),
608  "Internal error: The y_axis variable is not a number: " << y_axis[2]);
609 
610  y_axis = y_axis / y_axis.norm();
611 
612  WBAssert(!std::isnan(y_axis[0]),
613  "Internal error: The y_axis variable is not a number: " << y_axis[0]);
614  WBAssert(!std::isnan(y_axis[1]),
615  "Internal error: The y_axis variable is not a number: " << y_axis[1]);
616  WBAssert(!std::isnan(y_axis[2]),
617  "Internal error: The y_axis variable is not a number: " << y_axis[2]);
618 
619 
620  Point<2> check_point_surface_2d_temp = check_point_surface_2d;
621 
622  if (!bool_cartesian)
623  {
624  const double normal = std::fabs(point_list[i_section_min_distance+static_cast<size_t>(std::round(fraction_CPL_P1P2))][0]-check_point_surface_2d[0]);
625  const double plus = std::fabs(point_list[i_section_min_distance+static_cast<size_t>(std::round(fraction_CPL_P1P2))][0]-(check_point_surface_2d[0]+2*Consts::PI));
626  const double min = std::fabs(point_list[i_section_min_distance+static_cast<size_t>(std::round(fraction_CPL_P1P2))][0]-(check_point_surface_2d[0]-2*Consts::PI));
627 
628  // find out whether the check point, checkpoint + 2pi or check point -2 pi is closest to the point list.
629  if (plus < normal)
630  {
631  check_point_surface_2d_temp[0]+= 2*Consts::PI;
632  }
633  else if (min < normal)
634  {
635  check_point_surface_2d_temp[0]-= 2*Consts::PI;
636  }
637  }
638 
639  // check whether the check point and the reference point are on the same side, if not, change the side.
640  const Point<2> AB_normal = closest_point_on_curve.normal*closest_point_on_line_2d.distance(reference_point);//*AB.norm();
641  const Point<2> local_reference_point = AB_normal*1.+closest_point_on_line_2d;
642  const bool reference_normal_on_side_of_line = (closest_point_on_line_2d-local_reference_point).norm_square() < (check_point_surface_2d_temp-local_reference_point).norm_square();
643  const bool reference_point_on_side_of_line = (point_list[point_list.size()-1][0] - point_list[0][0])*(reference_point[1] - point_list[0][1]) - (reference_point[0] - point_list[0][0])*(point_list[point_list.size()-1][1] - point_list[0][1]) < 0.;
644  const double reference_on_side_of_line = reference_normal_on_side_of_line == reference_point_on_side_of_line ? 1 : -1;
645 
646  WBAssert(!std::isnan(x_axis[0]),
647  "Internal error: The x_axis variable is not a number: " << x_axis[0]);
648  WBAssert(!std::isnan(x_axis[1]),
649  "Internal error: The x_axis variable is not a number: " << x_axis[1]);
650  WBAssert(!std::isnan(x_axis[2]),
651  "Internal error: The x_axis variable is not a number: " << x_axis[2]);
652 
653  WBAssert(x_axis.norm() > 0.0, "x_axis norm is zero");
654 
655  x_axis = x_axis *(reference_on_side_of_line / x_axis.norm());
656 
657  WBAssert(!std::isnan(x_axis[0]),
658  "Internal error: The x_axis variable is not a number: " << x_axis[0]);
659  WBAssert(!std::isnan(x_axis[1]),
660  "Internal error: The x_axis variable is not a number: " << x_axis[1]);
661  WBAssert(!std::isnan(x_axis[2]),
662  "Internal error: The x_axis variable is not a number: " << x_axis[2]);
663 
664  }
665 
666  WBAssert(!std::isnan(x_axis[0]),
667  "Internal error: The x_axis[0] variable is not a number: " << x_axis[0] << ". Relevant values: check_point = " << check_point << '.');
668  WBAssert(!std::isnan(x_axis[1]),
669  "Internal error: The x_axis[1] variable is not a number: " << x_axis[1]);
670  WBAssert(!std::isnan(x_axis[2]),
671  "Internal error: The x_axis[2] variable is not a number: " << x_axis[2]);
672 
673  // now that we have the x and y axes computed, convert the 3d check point into a 2d one.
674  Point<2> check_point_2d(x_axis * (check_point - closest_point_on_line_bottom_cartesian),
675  y_axis * (check_point - closest_point_on_line_bottom_cartesian),
676  cartesian);
677 
678  Point<2> begin_segment(x_axis * (closest_point_on_line_cartesian - closest_point_on_line_bottom_cartesian),
679  y_axis * (closest_point_on_line_cartesian - closest_point_on_line_bottom_cartesian),
680  cartesian);
681 
682  WBAssert(!std::isnan(check_point_2d[0]),
683  "Internal error: The check_point_2d variable is not a number: " << check_point_2d[0]);
684  WBAssert(!std::isnan(check_point_2d[1]),
685  "Internal error: The check_point_2d variable is not a number: " << check_point_2d[1]);
686 
687 
688  WBAssert(!std::isnan(begin_segment[0]),
689  "Internal error: The begin_segment variable is not a number: " << begin_segment[0]);
690  WBAssert(!std::isnan(begin_segment[1]),
691  "Internal error: The begin_segment variable is not a number: " << begin_segment[1]);
692 
693  Point<2> end_segment = begin_segment;
694 
695  double total_length = 0.0;
696  double add_angle = 0.0;
697  double add_angle_correction = 0.0;
698  double average_angle = 0.0;
699  for (size_t i_segment = 0; i_segment < plane_segment_lengths[original_current_section].size(); i_segment++)
700  {
701  const size_t current_segment = i_segment;
702 
703  // compute the angle between the previous begin and end if
704  // the depth method is angle_at_begin_segment_with_surface.
705  if (i_segment != 0
706  &&
708  ||
710  {
711  double add_angle_inner = (begin_segment * end_segment) / (begin_segment.norm() * end_segment.norm());
712 
713  WBAssert(!std::isnan(add_angle_inner),
714  "Internal error: The add_angle_inner variable is not a number: " << add_angle_inner
715  << ". Variables: begin_segment = " << begin_segment
716  << ", end_segment = " << end_segment
717  << ", begin_segment * end_segment / (begin_segment.norm() * end_segment.norm()) = "
718  << std::setprecision(32) << begin_segment * end_segment / (begin_segment.norm() * end_segment.norm())
719  << '.');
720 
721  // there could be round of error problems here is the inner part is close to one
722  if (add_angle_inner < 0. && add_angle_inner >= -1e-14)
723  add_angle_inner = 0.;
724  if (add_angle_inner > 1. && add_angle_inner <= 1.+1e-14)
725  add_angle_inner = 1.;
726 
727  WBAssert(add_angle_inner >= 0 && add_angle_inner <= 1,
728  "Internal error: The variable add_angle_inner is smaller than zero or larger then one,"
729  "which causes the std::acos to return nan. If it is only a little bit larger then one, "
730  "this is probably caused by that begin and end segment are the same and round off error. "
731  "The value of add_angle_inner = " << add_angle_inner);
732 
733  add_angle_correction = std::acos(add_angle_inner);
734  add_angle += add_angle_correction;
735 
736  WBAssert(!std::isnan(add_angle),
737  "Internal error: The add_angle variable is not a number: " << add_angle
738  << ". Variables: begin_segment = " << begin_segment
739  << ", end_segment = " << end_segment
740  << ", begin_segment * end_segment / (begin_segment.norm() * end_segment.norm()) = "
741  << std::setprecision(32) << begin_segment * end_segment / (begin_segment.norm() * end_segment.norm())
742  << ", std::acos(begin_segment * end_segment / (begin_segment.norm() * end_segment.norm())) = "
743  << std::acos(begin_segment * end_segment / (begin_segment.norm() * end_segment.norm())));
744  }
745 
746 
747 
748 
749  begin_segment = end_segment;
750 
751  WBAssert(!std::isnan(begin_segment[0]),
752  "Internal error: The begin_segment variable is not a number: " << begin_segment[0]);
753  WBAssert(!std::isnan(begin_segment[1]),
754  "Internal error: The begin_segment variable is not a number: " << begin_segment[1]);
755 
756 
757  // This interpolates different properties between P1 and P2 (the
758  // points of the plane at the surface)
759  const double degree_90_to_rad = 0.5 * Consts::PI;
760 
761  WBAssert(plane_segment_angles.size() > original_next_section,
762  "Error: original_next_section = " << original_next_section
763  << ", and plane_segment_angles.size() = " << plane_segment_angles.size());
764 
765 
766  WBAssert(plane_segment_angles[original_next_section].size() > current_segment,
767  "Error: current_segment = " << current_segment
768  << ", and current_segment.size() = " << plane_segment_angles[original_next_section].size());
769 
770  const double interpolated_angle_top = plane_segment_angles[original_current_section][current_segment][0]
771  + fraction_CPL_P1P2 * (plane_segment_angles[original_next_section][current_segment][0]
772  - plane_segment_angles[original_current_section][current_segment][0])
773  + add_angle
775  && i_segment != 0 ? -add_angle_correction: 0);
776 
777  const double interpolated_angle_bottom = plane_segment_angles[original_current_section][current_segment][1]
778  + fraction_CPL_P1P2 * (plane_segment_angles[original_next_section][current_segment][1]
779  - plane_segment_angles[original_current_section][current_segment][1])
780  + add_angle;
781 
782 
783  const double interpolated_segment_length = plane_segment_lengths[original_current_section][current_segment]
784  + fraction_CPL_P1P2 * (plane_segment_lengths[original_next_section][current_segment]
785  - plane_segment_lengths[original_current_section][current_segment]);
786 
787  if (interpolated_segment_length < 1e-14)
788  continue;
789 
790  WBAssert(!std::isnan(interpolated_angle_top),
791  "Internal error: The interpolated_angle_top variable is not a number: " << interpolated_angle_top);
792 
793  // We want to know where the end point of this segment is (and
794  // the start of the next segment). There are two cases which we
795  // will deal with separately. The first one is if the angle is
796  // constant. The second one is if the angle changes.
797  const double difference_in_angle_along_segment = interpolated_angle_top - interpolated_angle_bottom;
798 
799  if (std::fabs(difference_in_angle_along_segment) < 1e-8)
800  {
801  // The angle is constant. It is easy find find the end of
802  // this segment and the distance.
803  if (std::fabs(interpolated_segment_length) > std::numeric_limits<double>::epsilon())
804  {
805  end_segment[0] += interpolated_segment_length * std::sin(degree_90_to_rad - interpolated_angle_top);
806  end_segment[1] -= interpolated_segment_length * std::cos(degree_90_to_rad - interpolated_angle_top);
807 
808  Point<2> begin_end_segment = end_segment - begin_segment;
809  Point<2> normal_2d_plane(-begin_end_segment[0],begin_end_segment[1], cartesian);
810  WBAssert(std::fabs(normal_2d_plane.norm()) > std::numeric_limits<double>::epsilon(), "Internal Error: normal_2d_plane.norm() is zero, which should not happen. "
811  << "Extra info: begin_end_segment[0] = " << begin_end_segment[0]
812  << ", begin_end_segment[1] = " << begin_end_segment[1]
813  << ", end_segment: [" << end_segment[0] << ',' << end_segment[1] << ']'
814  << ", begin_segment: [" << begin_segment[0] << ',' << begin_segment[1] << ']'
815  );
816  normal_2d_plane /= normal_2d_plane.norm();
817 
818  // Now find the distance of a point to this line.
819  // Based on http://geomalgorithms.com/a02-_lines.html.
820  const Point<2> BSP_ESP = end_segment - begin_segment;
821  const Point<2> BSP_CP = check_point_2d - begin_segment;
822 
823  const double c1 = BSP_ESP * BSP_CP;
824  const double c2 = BSP_ESP * BSP_ESP;
825 
826  if (c1 < 0 || c2 < c1)
827  {
828  new_distance = std::numeric_limits<double>::infinity();
829  new_along_plane_distance = std::numeric_limits<double>::infinity();
830  new_depth_reference_surface = std::numeric_limits<double>::infinity();
831  }
832  else
833  {
834  const Point<2> Pb = begin_segment + (c1/c2) * BSP_ESP;
835  const double side_of_line = (begin_segment[0] - end_segment[0]) * (check_point_2d[1] - begin_segment[1])
836  - (begin_segment[1] - end_segment[1]) * (check_point_2d[0] - begin_segment[0])
837  < 0 ? -1.0 : 1.0;
838 
839  new_distance = side_of_line * (check_point_2d - Pb).norm();
840  new_along_plane_distance = (begin_segment - Pb).norm();
841  new_depth_reference_surface = start_radius - Pb[1];
842 
843  WBAssert(!std::isnan(new_depth_reference_surface),
844  "new_depth_reference_surface is not a number: " << new_depth_reference_surface << ". "
845  << "start_radius = " << start_radius << ",Pb[1] = " << Pb[1] << ".");
846  }
847  }
848  }
849  else
850  {
851  // The angle is not constant. This means that we need to
852  // define a circle. First find the center of the circle.
853  const double radius_angle_circle = std::fabs(interpolated_segment_length/difference_in_angle_along_segment);
854 
855  WBAssert(!std::isnan(radius_angle_circle),
856  "Internal error: The radius_angle_circle variable is not a number: " << radius_angle_circle
857  << ". interpolated_segment_length = " << interpolated_segment_length
858  << ", difference_in_angle_along_segment = " << difference_in_angle_along_segment);
859 
860  const double cos_angle_top = std::cos(interpolated_angle_top);
861 
862  WBAssert(!std::isnan(cos_angle_top),
863  "Internal error: The radius_angle_circle variable is not a number: " << cos_angle_top
864  << ". interpolated_angle_top = " << interpolated_angle_top);
865 
866  Point<2> center_circle(cartesian);
867  if (std::fabs(interpolated_angle_top - 0.5 * Consts::PI) < 1e-8)
868  {
869  // if interpolated_angle_top is 90 degrees, the tan function
870  // is undefined (1/0). What we really want in this case is
871  // set the center to the correct location which is x = the x
872  //begin point + radius and y = the y begin point.
873  center_circle[0] = difference_in_angle_along_segment > 0 ? begin_segment[0] + radius_angle_circle : begin_segment[0] - radius_angle_circle;
874  center_circle[1] = begin_segment[1];
875  }
876  else if (std::fabs(interpolated_angle_top - 1.5 * Consts::PI) < 1e-8)
877  {
878  // if interpolated_angle_top is 270 degrees, the tan function
879  // is undefined (-1/0). What we really want in this case is
880  // set the center to the correct location which is x = the x
881  //begin point - radius and y = the y begin point.
882  center_circle[0] = difference_in_angle_along_segment > 0 ? begin_segment[0] - radius_angle_circle : begin_segment[0] + radius_angle_circle;
883  center_circle[1] = begin_segment[1];
884  }
885  else
886  {
887  const double tan_angle_top = std::tan(interpolated_angle_top);
888 
889  WBAssert(!std::isnan(tan_angle_top),
890  "Internal error: The tan_angle_top variable is not a number: " << tan_angle_top);
891  const double center_circle_y = difference_in_angle_along_segment < 0 ?
892  begin_segment[1] - radius_angle_circle * cos_angle_top
893  : begin_segment[1] + radius_angle_circle * cos_angle_top;
894 
895  WBAssert(!std::isnan(center_circle_y),
896  "Internal error: The center_circle_y variable is not a number: " << center_circle_y
897  << ". begin_segment[1] = " << begin_segment[1]
898  << ", radius_angle_circle = " << radius_angle_circle
899  << ", cos_angle_top = " << cos_angle_top);
900 
901  // to prevent round off errors becoming dominant, we check
902  // whether center_circle_y - begin_segment[1] should be zero.
903  // TODO: improve this to some kind of relative difference.
904  const double CCYBS = center_circle_y - begin_segment[1];
905 
906  WBAssert(!std::isnan(CCYBS),
907  "Internal error: The CCYBS variable is not a number: " << CCYBS);
908 
909 
910 
911  center_circle[0] = begin_segment[0] + tan_angle_top * (CCYBS);
912  center_circle[1] = center_circle_y;
913  }
914 
915  WBAssert(!std::isnan(center_circle[0]) || !std::isnan(center_circle[1]),
916  "Internal error: The center variable contains not a number: " << center_circle[0] << ':' << center_circle[0]);
917  WBAssert(std::fabs((begin_segment-center_circle).norm() - std::fabs(radius_angle_circle))
918  < 1e-8 * std::fabs((begin_segment-center_circle).norm() + std::fabs(radius_angle_circle)),
919  "Internal error: The center of the circle is not a radius away from the begin point. " << std::endl
920  << "The center is located at " << center_circle[0] << ':' << center_circle[1] << std::endl
921  << "The begin point is located at " << begin_segment[0] << ':' << begin_segment[1] << std::endl
922  << "The computed radius is " << std::fabs((begin_segment-center_circle).norm())
923  << ", and it should be " << radius_angle_circle << '.');
924 
925 
926  // Now compute the location of the end of the segment by
927  // rotating P1 around the center_circle
928  Point<2> BSPC = begin_segment - center_circle;
929  const double sin_angle_diff = sin(difference_in_angle_along_segment);
930  const double cos_angle_diff = cos(difference_in_angle_along_segment);
931  end_segment[0] = cos_angle_diff * BSPC[0] - sin_angle_diff * BSPC[1] + center_circle[0];
932  end_segment[1] = sin_angle_diff * BSPC[0] + cos_angle_diff * BSPC[1] + center_circle[1];
933 
934 
935 
936  WBAssert(std::fabs((end_segment-center_circle).norm() - std::fabs(radius_angle_circle))
937  < 1e-8 * std::fabs((end_segment-center_circle).norm() + std::fabs(radius_angle_circle)) ,
938  "Internal error: The center of the circle is not a radius away from the end point. " << std::endl
939  << "The center is located at " << center_circle[0] << ':' << center_circle[1] << std::endl
940  << "The end point is located at " << end_segment[0] << ':' << end_segment[1] << std::endl
941  << "The computed radius is " << std::fabs((end_segment-center_circle).norm())
942  << ", and it should be " << radius_angle_circle << '.');
943 
944  // Now check if the angle of the check point in this circle
945  // is larger then the angle of P1 and smaller then P1 + angle
946  // difference. If that is the case then the distance from the
947  // plane is radius - (center - check_point).norm(). Otherwise
948  // it is infinity.
949  // The angle of the check point is computed with the help of
950  // dot product. But before that we need to adjust the check
951  // point 2d.
952  const Point<2> CPCR = check_point_2d - center_circle;
953  const double CPCR_norm = CPCR.norm();
954 
955  const double dot_product = CPCR * Point<2>(0, radius_angle_circle, cartesian);
956  // If the x of the check point is larger then the x of center
957  // the circle, the angle is more than 180 degree, but the dot
958  // product will decrease instead of increase from 180 degrees.
959  // To fix this we make a special case for this.
960  // Furthermore, when the check point is at the same location as
961  // the center of the circle, we count that point as belonging
962  // to the top of the top segment (0 degree).
963  double check_point_angle = std::fabs(CPCR_norm) < std::numeric_limits<double>::epsilon() ? 2.0 * Consts::PI : (check_point_2d[0] <= center_circle[0]
964  ? std::acos(dot_product/(CPCR_norm * radius_angle_circle))
965  : 2.0 * Consts::PI - std::acos(dot_product/(CPCR_norm * radius_angle_circle)));
966  check_point_angle = difference_in_angle_along_segment >= 0 ? Consts::PI - check_point_angle : 2.0 * Consts::PI - check_point_angle;
967 
968  // In the case that it is exactly 2 * pi, bring it back to zero
969  check_point_angle = (std::fabs(check_point_angle - 2 * Consts::PI) < 1e-14 ? 0 : check_point_angle);
970 
971  if ((difference_in_angle_along_segment > 0 && (check_point_angle <= interpolated_angle_top || std::fabs(check_point_angle - interpolated_angle_top) < 1e-12)
972  && (check_point_angle >= interpolated_angle_bottom || std::fabs(check_point_angle - interpolated_angle_bottom) < 1e-12))
973  || (difference_in_angle_along_segment < 0 && (check_point_angle >= interpolated_angle_top || std::fabs(check_point_angle - interpolated_angle_top) < 1e-12)
974  && (check_point_angle <= interpolated_angle_bottom || std::fabs(check_point_angle - interpolated_angle_bottom) < 1e-12)))
975  {
976  new_distance = (radius_angle_circle - CPCR_norm) * (difference_in_angle_along_segment < 0 ? 1 : -1);
977  new_along_plane_distance = (radius_angle_circle * check_point_angle - radius_angle_circle * interpolated_angle_top) * (difference_in_angle_along_segment < 0 ? 1 : -1);
978  // compute the new depth by rotating the begin point to the check point location.
979  new_depth_reference_surface = start_radius-(sin(check_point_angle + interpolated_angle_top) * BSPC[0] + cos(check_point_angle + interpolated_angle_top) * BSPC[1] + center_circle[1]);
980 
981  WBAssert(!std::isnan(new_depth_reference_surface),
982  "new_depth_reference_surface is not a number: " << new_depth_reference_surface << ". "
983  << "start_radius = " << start_radius << ", check_point_angle = " << check_point_angle << ", interpolated_angle_top = " << interpolated_angle_top
984  << ", BSPC[0] = " << BSPC[0] << ".");
985  }
986 
987  }
988 
989  // Now we need to see whether we need to update the information
990  // based on whether this segment is the closest one to the point
991  // up to now. To do this we first look whether the point falls
992  // within the bound of the segment and if it is actually closer.
993  // TODO: find out whether the fabs() are needed.
994  if (new_along_plane_distance >= -1e-10 &&
995  new_along_plane_distance <= std::fabs(interpolated_segment_length) &&
996  std::fabs(new_distance) < std::fabs(distance))
997  {
998  // There are two specific cases we are concerned with. The
999  // first case is that we want to have both the positive and
1000  // negative distances (above and below the line). The second
1001  // case is that we only want positive distances.
1002  distance = only_positive ? std::fabs(new_distance) : new_distance;
1003  along_plane_distance = new_along_plane_distance + total_length;
1004  section = i_section_min_distance;
1005  section_fraction = fraction_CPL_P1P2;
1006  segment = i_segment;
1007  segment_fraction = new_along_plane_distance / interpolated_segment_length;
1008  total_average_angle = (average_angle * total_length
1009  + 0.5 * (interpolated_angle_top + interpolated_angle_bottom - 2 * add_angle) * new_along_plane_distance);
1010  total_average_angle = (std::fabs(total_average_angle) < std::numeric_limits<double>::epsilon() ? 0 : total_average_angle /
1011  (total_length + new_along_plane_distance));
1012  depth_reference_surface = new_depth_reference_surface;
1013  }
1014 
1015  // increase average angle
1016  average_angle = (average_angle * total_length +
1017  0.5 * (interpolated_angle_top + interpolated_angle_bottom - 2 * add_angle) * interpolated_segment_length);
1018  average_angle = (std::fabs(average_angle) < std::numeric_limits<double>::epsilon() ? 0 : average_angle /
1019  (total_length + interpolated_segment_length));
1020  // increase the total length for the next segment.
1021  total_length += interpolated_segment_length;
1022  }
1023  }
1024 
1025  WBAssert(!std::isnan(depth_reference_surface), "depth_reference_surface is not a number: " << depth_reference_surface << ".");
1026 
1027  PointDistanceFromCurvedPlanes return_values(natural_coordinate.get_coordinate_system());
1028  return_values.distance_from_plane = distance;
1029  return_values.distance_along_plane = along_plane_distance;
1030  return_values.fraction_of_section = section_fraction;
1031  return_values.fraction_of_segment = segment_fraction;
1032  return_values.section = section;
1033  return_values.segment = segment;
1034  return_values.average_angle = total_average_angle;
1035  return_values.depth_reference_surface = depth_reference_surface;
1036  return_values.closest_trench_point = closest_point_on_line_cartesian;
1037  return return_values;
1038  }
1039 
1040  void interpolation::set_points(const std::vector<double> &y)
1041  {
1042  const size_t n = y.size();
1043  mx_size_min = n;
1044  m.resize(n);
1045  for (unsigned int i = 0; i < n; ++i)
1046  {
1047  m[i][3] = y[i];
1048  }
1049 
1057  // get m_a parameter
1058  m[0][2] = 0;
1059 
1060  for (size_t i = 0; i < n-2; i++)
1061  {
1062  const double m0 = y[i+1]-y[i];
1063  const double m1 = y[i+2]-y[i+1];
1064 
1065  if (m0 * m1 <= 0)
1066  {
1067  m[i+1][2] = 0;
1068  }
1069  else
1070  {
1071  m[i+1][2] = 2*m0*m1/(m0+m1);
1072  }
1073  }
1074  m[n-1][2] = y[n-1]-y[n-2];
1075 
1076  // Get b and c coefficients
1077  //m_a.resize(n);
1078  //m_b.resize(n);
1079  for (size_t i = 0; i < n-1; i++)
1080  {
1081  const double c1 = m[i][2];
1082  const double m0 = y[i+1]-y[i];
1083 
1084  const double common0 = c1 + m[i+1][2] - m0 - m0;
1085  m[i][1] = (m0 - c1 - common0);
1086  m[i][0] = common0;
1087  }
1088  }
1089 
1090  double wrap_angle(const double angle)
1091  {
1092  return angle - 360.0*std::floor(angle/360.0);
1093  }
1094 
1095  double interpolate_angle_across_zero(const double angle_1,
1096  const double angle_2,
1097  const double fraction)
1098  {
1099  double theta_1 = angle_1;
1100  double theta_2 = angle_2;
1101  double rotation_angle;
1102 
1103  if (std::abs(theta_2 - theta_1) > Consts::PI)
1104  {
1105  if (theta_2 > theta_1)
1106  theta_1 += 2.*Consts::PI;
1107  else
1108  theta_2 += 2.*Consts::PI;
1109  }
1110  rotation_angle = (1-fraction) * theta_1 + fraction * theta_2;
1111 
1112  // make sure angle is between 0 and 360 degrees
1113  rotation_angle = rotation_angle - 2*Consts::PI*std::floor(rotation_angle/(2 * Consts::PI));
1114 
1115  return rotation_angle;
1116  }
1117 
1118  std::array<double,3>
1119  euler_angles_from_rotation_matrix(const std::array<std::array<double,3>,3> &rotation_matrix)
1120  {
1121  const double rad_to_degree = 180.0/Consts::PI;
1122  std::array<double,3> euler_angles;
1123  //const double s2 = std::sqrt(rotation_matrix[2][1] * rotation_matrix[2][1] + rotation_matrix[2][0] * rotation_matrix[2][0]);
1124  const std::ostringstream os;
1125  for (size_t i = 0; i < 3; i++)
1126  for (size_t j = 0; j < 3; j++)
1127  WBAssert(std::fabs(rotation_matrix[i][j]) <= 1.0,
1128  "rotation_matrix[" + std::to_string(i) + "][" + std::to_string(j) +
1129  "] is larger than one: " + std::to_string(rotation_matrix[i][j]) + ". rotation_matrix = \n"
1130  + std::to_string(rotation_matrix[0][0]) + " " + std::to_string(rotation_matrix[0][1]) + " " + std::to_string(rotation_matrix[0][2]) + "\n"
1131  + std::to_string(rotation_matrix[1][0]) + " " + std::to_string(rotation_matrix[1][1]) + " " + std::to_string(rotation_matrix[1][2]) + "\n"
1132  + std::to_string(rotation_matrix[2][0]) + " " + std::to_string(rotation_matrix[2][1]) + " " + std::to_string(rotation_matrix[2][2]));
1133 
1134 
1135  const double theta = std::acos(rotation_matrix[2][2]);
1136  const double phi1 = std::atan2(rotation_matrix[2][0]/-sin(theta),rotation_matrix[2][1]/-sin(theta));
1137  const double phi2 = std::atan2(rotation_matrix[0][2]/-sin(theta),rotation_matrix[1][2]/sin(theta));
1138 
1139  euler_angles[0] = wrap_angle(phi1 * rad_to_degree);
1140  euler_angles[1] = wrap_angle(theta * rad_to_degree);
1141  euler_angles[2] = wrap_angle(phi2 * rad_to_degree);
1142 
1143  return euler_angles;
1144  }
1145 
1146  std::array<std::array<double,3>,3>
1147  euler_angles_to_rotation_matrix(double phi1_d, double theta_d, double phi2_d)
1148  {
1149 
1150  const double degree_to_rad = Consts::PI/180.0;
1151  const double phi1 = phi1_d * degree_to_rad;
1152  const double theta = theta_d * degree_to_rad;
1153  const double phi2 = phi2_d * degree_to_rad;
1154  std::array<std::array<double,3>,3> rot_matrix;
1155 
1156 
1157  rot_matrix[0][0] = cos(phi2)*cos(phi1) - cos(theta)*sin(phi1)*sin(phi2);
1158  rot_matrix[0][1] = -cos(phi2)*sin(phi1) - cos(theta)*cos(phi1)*sin(phi2);
1159  rot_matrix[0][2] = -sin(phi2)*sin(theta);
1160 
1161  rot_matrix[1][0] = sin(phi2)*cos(phi1) + cos(theta)*sin(phi1)*cos(phi2);
1162  rot_matrix[1][1] = -sin(phi2)*sin(phi1) + cos(theta)*cos(phi1)*cos(phi2);
1163  rot_matrix[1][2] = cos(phi2)*sin(theta);
1164 
1165  rot_matrix[2][0] = -sin(theta)*sin(phi1);
1166  rot_matrix[2][1] = -sin(theta)*cos(phi1);
1167  rot_matrix[2][2] = cos(theta);
1168  return rot_matrix;
1169  }
1170 
1171  std::string
1172  read_and_distribute_file_content(const std::string &filename)
1173  {
1174  std::string data_string;
1175 
1176 #ifdef WB_WITH_MPI
1177  int mpi_initialized;
1178  MPI_Initialized(&mpi_initialized);
1179  if (mpi_initialized != 0)
1180  {
1181  const MPI_Comm comm = MPI_COMM_WORLD;
1182  int my_rank = 0;
1183  MPI_Comm_rank(comm, &my_rank);
1184  if (my_rank == 0)
1185  {
1186  int filesize;
1187  std::ifstream filestream;
1188  filestream.open(filename.c_str());
1189  WBAssertThrow (filestream.is_open(), std::string("Could not open file <") + filename + ">.");
1190 
1191  // Need to convert to unsigned int, because MPI_Bcast does not support
1192  // size_t or const unsigned int
1193  int invalid_file_size = -1;
1194 
1195  if (!filestream)
1196  {
1197  // broadcast failure state, then throw
1198  const int ierr = MPI_Bcast(&invalid_file_size, 1, MPI_INT, 0, comm);
1199  WBAssertThrow (ierr,
1200  std::string("Could not open file <") + filename + ">.");
1201  }
1202 
1203  // Read data from disk
1204  std::stringstream datastream;
1205 
1206  try
1207  {
1208  datastream << filestream.rdbuf();
1209  }
1210  catch (const std::ios::failure &)
1211  {
1212  // broadcast failure state, then throw
1213  const int ierr = MPI_Bcast(&invalid_file_size, 1, MPI_INT, 0, comm);
1214  WBAssertThrow(ierr == 0, "MPI_Bcast failed.");
1215  WBAssertThrow (false,
1216  std::string("Could not read file content from <") + filename + ">.");
1217  }
1218 
1219  data_string = datastream.str();
1220  WBAssertThrow(static_cast<long int>(data_string.size()) < std::numeric_limits<int>::max(),
1221  "File is too large to be send with MPI.");
1222  filesize = static_cast<int>(data_string.size());
1223 
1224  // Distribute data_size and data across processes
1225  int ierr = MPI_Bcast(&filesize, 1, MPI_INT, 0, comm);
1226  WBAssertThrow(ierr == 0, "MPI_Bcast failed.");
1227 
1228  // Receive and store data
1229  ierr = MPI_Bcast(&data_string[0],
1230  filesize,
1231  MPI_CHAR,
1232  0,
1233  comm);
1234  WBAssertThrow(ierr == 0, "MPI_Bcast failed.");
1235  }
1236  else
1237  {
1238  // Prepare for receiving data
1239  int filesize = 0;
1240  int ierr = MPI_Bcast(&filesize, 1, MPI_INT, 0, comm);
1241  WBAssertThrow(ierr == 0, "MPI_Bcast failed.");
1242  WBAssertThrow(filesize != -1,
1243  std::string("Could not open file <") + filename + ">.");
1244 
1245  data_string.resize(static_cast<size_t>(filesize));
1246 
1247  // Receive and store data
1248  ierr = MPI_Bcast(&data_string[0],
1249  filesize,
1250  MPI_CHAR,
1251  0,
1252  comm);
1253  WBAssertThrow(ierr == 0, "MPI_Bcast failed.");
1254  }
1255  }
1256  else
1257  {
1258  std::ifstream filestream;
1259  filestream.open(filename.c_str());
1260  if (!filestream)
1261  {
1262  WBAssertThrow (false,
1263  std::string("Could not open file <") + filename + ">.");
1264  }
1265  std::stringstream datastream;
1266  datastream << filestream.rdbuf();
1267  data_string = datastream.str();
1268  }
1269 #else
1270  std::ifstream filestream;
1271  filestream.open(filename.c_str());
1272  if (!filestream)
1273  {
1274  WBAssertThrow (false,
1275  std::string("Could not open file <") + filename + ">.");
1276  }
1277  std::stringstream datastream;
1278  datastream << filestream.rdbuf();
1279  data_string = datastream.str();
1280 #endif
1281 
1282  return data_string;
1283  }
1284 
1285  template std::array<double,2> convert_point_to_array<2>(const Point<2> &point_);
1286  template std::array<double,3> convert_point_to_array<3>(const Point<3> &point_);
1287 
1288 
1289  std::vector<double>
1290  calculate_ridge_distance_and_spreading(std::vector<std::vector<Point<2>>> mid_oceanic_ridges,
1291  std::vector<std::vector<double>> mid_oceanic_spreading_velocities,
1292  const std::unique_ptr<WorldBuilder::CoordinateSystems::Interface> &coordinate_system,
1293  const Objects::NaturalCoordinate &position_in_natural_coordinates_at_min_depth,
1294  const std::vector<std::vector<double>> &subducting_plate_velocities,
1295  const std::vector<double> &ridge_migration_times)
1296  {
1297  const double seconds_in_year = 60.0 * 60.0 * 24.0 * 365.25; // sec/y
1298 
1299  double distance_ridge = std::numeric_limits<double>::max();
1300  double spreading_velocity_at_ridge = 0;
1301  double subducting_velocity_at_trench = 0;
1302  double ridge_migration_time = 0;
1303 
1304  // first find if the coordinate is on this side of a ridge
1305  unsigned int relevant_ridge = 0;
1306  const Point<2> check_point(position_in_natural_coordinates_at_min_depth.get_surface_coordinates(),
1307  position_in_natural_coordinates_at_min_depth.get_coordinate_system());
1308 
1309  Point<2> other_check_point = check_point;
1310  if (check_point.get_coordinate_system() == CoordinateSystem::spherical)
1311  other_check_point[0] += check_point[0] < 0 ? 2.0 * WorldBuilder::Consts::PI : -2.0 * WorldBuilder::Consts::PI;
1312 
1313  // if there is only one ridge, there is no transform
1314  if (mid_oceanic_ridges[0].size() > 1)
1315  {
1316  // There are more than one ridge, so there are transform faults
1317  // Find the first which is on the same side
1318  for (relevant_ridge = 0; relevant_ridge < mid_oceanic_ridges.size()-1; relevant_ridge++)
1319  {
1320  const Point<2> transform_point_0 = mid_oceanic_ridges[relevant_ridge+1][0];
1321  const Point<2> transform_point_1 = mid_oceanic_ridges[relevant_ridge][mid_oceanic_ridges[relevant_ridge].size()-1];
1322  const Point<2> reference_point = mid_oceanic_ridges[relevant_ridge][0];
1323  const bool reference_on_side_of_line = (transform_point_1[0] - transform_point_0[0])
1324  * (reference_point[1] - transform_point_0[1])
1325  - (transform_point_1[1] - transform_point_0[1])
1326  * (reference_point[0] - transform_point_0[0])
1327  < 0;
1328  const bool checkpoint_on_side_of_line = (transform_point_1[0] - transform_point_0[0])
1329  * (check_point[1] - transform_point_0[1])
1330  - (transform_point_1[1] - transform_point_0[1])
1331  * (check_point[0] - transform_point_0[0])
1332  < 0;
1333 
1334 
1335  if (reference_on_side_of_line == checkpoint_on_side_of_line)
1336  {
1337  break;
1338  }
1339 
1340  }
1341  }
1342 
1343  for (unsigned int i_coordinate = 0; i_coordinate < mid_oceanic_ridges[relevant_ridge].size() - 1; i_coordinate++)
1344  {
1345  const Point<2> segment_point0 = mid_oceanic_ridges[relevant_ridge][i_coordinate];
1346  const Point<2> segment_point1 = mid_oceanic_ridges[relevant_ridge][i_coordinate + 1];
1347 
1348  const double spreading_velocity_point0 = mid_oceanic_spreading_velocities[relevant_ridge][i_coordinate];
1349  const double spreading_velocity_point1 = mid_oceanic_spreading_velocities[relevant_ridge][i_coordinate + 1];
1350 
1351  // When subducting_velocities is not input by the user, default value is 0, which
1352  // results in subducting velocity == spreading_velocity. When a single value is
1353  // input by the user, subducting velocity != spreading_velocity, but
1354  // subducting velocity is spatially constant.
1355  double subducting_velocity_point0 = subducting_plate_velocities[0][0];
1356  double subducting_velocity_point1 = subducting_plate_velocities[0][0];
1357 
1358  // When subducting_velocities is input as an array, spatial variation
1359  if (subducting_plate_velocities[0].size() > 1)
1360  {
1361  WBAssert(subducting_plate_velocities.size() == mid_oceanic_ridges.size() && \
1362  subducting_plate_velocities[relevant_ridge].size() == mid_oceanic_ridges[relevant_ridge].size(),
1363  "subducting velocity and ridge coordinates must be the same dimension");
1364  WBAssert(ridge_migration_times.size() == mid_oceanic_ridges.size(),
1365  "the times for ridge migration specified in 'spreading velocity' must be the same dimension "
1366  "as ridge coordinates.");
1367  subducting_velocity_point0 = subducting_plate_velocities[relevant_ridge][i_coordinate];
1368  subducting_velocity_point1 = subducting_plate_velocities[relevant_ridge][i_coordinate + 1];
1369  ridge_migration_time = ridge_migration_times[relevant_ridge];
1370  }
1371 
1372  {
1373  // based on http://geomalgorithms.com/a02-_lines.html
1374  const Point<2> v = segment_point1 - segment_point0;
1375  const Point<2> w1 = check_point - segment_point0;
1376  const Point<2> w2 = other_check_point - segment_point0;
1377 
1378  const double c1 = (w1[0] * v[0] + w1[1] * v[1]);
1379  const double c = (v[0] * v[0] + v[1] * v[1]);
1380  const double c2 = (w2[0] * v[0] + w2[1] * v[1]);
1381 
1382 
1383  Point<2> Pb1(coordinate_system->natural_coordinate_system());
1384  // This part is needed when we want to consider segments instead of lines
1385  // If you want to have infinite lines, use only the else statement.
1386 
1387  // First, compare the results from the two compare points
1388  double spreading_velocity_at_ridge_pt1 = 0.0;
1389  double subducting_velocity_at_trench_pt1 = 0.0;
1390  double spreading_velocity_at_ridge_pt2 = 0.0;
1391  double subducting_velocity_at_trench_pt2 = 0.0;
1392 
1393  if (c1 <= 0)
1394  {
1395  Pb1=segment_point0;
1396  spreading_velocity_at_ridge_pt1 = spreading_velocity_point0;
1397  subducting_velocity_at_trench_pt1 = subducting_velocity_point0;
1398  }
1399  else if (c <= c1)
1400  {
1401  Pb1=segment_point1;
1402  spreading_velocity_at_ridge_pt1 = spreading_velocity_point1;
1403  subducting_velocity_at_trench_pt1 = subducting_velocity_point1;
1404  }
1405  else
1406  {
1407  Pb1=segment_point0 + (c1 / c) * v;
1408  spreading_velocity_at_ridge_pt1 = spreading_velocity_point0 + (spreading_velocity_point1 - spreading_velocity_point0) * (c1 / c);
1409  subducting_velocity_at_trench_pt1 = subducting_velocity_point0 + (subducting_velocity_point1 - subducting_velocity_point0) * (c1 / c);
1410  }
1411 
1412  Point<2> Pb2(coordinate_system->natural_coordinate_system());
1413  if (c2 <= 0)
1414  {
1415  Pb2=segment_point0;
1416  spreading_velocity_at_ridge_pt2 = spreading_velocity_point0;
1417  subducting_velocity_at_trench_pt2 = subducting_velocity_point0;
1418  }
1419  else if (c <= c2)
1420  {
1421  Pb2=segment_point1;
1422  spreading_velocity_at_ridge_pt2 = spreading_velocity_point1;
1423  subducting_velocity_at_trench_pt2 = spreading_velocity_point1;
1424  }
1425  else
1426  {
1427  Pb2=segment_point0 + (c2 / c) * v;
1428  spreading_velocity_at_ridge_pt2 = spreading_velocity_point0 + (spreading_velocity_point1 - spreading_velocity_point0) * (c2 / c);
1429  subducting_velocity_at_trench_pt2 = subducting_velocity_point0 + (subducting_velocity_point1 - subducting_velocity_point0) * (c2 / c);
1430  }
1431 
1432  Point<3> compare_point1(coordinate_system->natural_coordinate_system());
1433  Point<3> compare_point2(coordinate_system->natural_coordinate_system());
1434 
1435  compare_point1[0] = coordinate_system->natural_coordinate_system() == cartesian ? Pb1[0] : position_in_natural_coordinates_at_min_depth.get_depth_coordinate();
1436  compare_point1[1] = coordinate_system->natural_coordinate_system() == cartesian ? Pb1[1] : Pb1[0];
1437  compare_point1[2] = coordinate_system->natural_coordinate_system() == cartesian ? position_in_natural_coordinates_at_min_depth.get_depth_coordinate() : Pb1[1];
1438 
1439  compare_point2[0] = coordinate_system->natural_coordinate_system() == cartesian ? Pb2[0] : position_in_natural_coordinates_at_min_depth.get_depth_coordinate();
1440  compare_point2[1] = coordinate_system->natural_coordinate_system() == cartesian ? Pb2[1] : Pb2[0];
1441  compare_point2[2] = coordinate_system->natural_coordinate_system() == cartesian ? position_in_natural_coordinates_at_min_depth.get_depth_coordinate() : Pb2[1];
1442 
1443  const double compare_distance1 = coordinate_system->distance_between_points_at_same_depth(Point<3>(position_in_natural_coordinates_at_min_depth.get_coordinates(),
1444  position_in_natural_coordinates_at_min_depth.get_coordinate_system()),
1445  compare_point1);
1446 
1447  const double compare_distance2 = coordinate_system->distance_between_points_at_same_depth(Point<3>(position_in_natural_coordinates_at_min_depth.get_coordinates(),
1448  position_in_natural_coordinates_at_min_depth.get_coordinate_system()),
1449  compare_point2);
1450 
1451  double compare_distance = compare_distance1;
1452  double spreading_velocity_at_ridge_pt = spreading_velocity_at_ridge_pt1;
1453  double subducting_velocity_at_trench_pt = subducting_velocity_at_trench_pt1;
1454 
1455  // This is required in spherical coordinates to ensure that the distance
1456  // returned is the shortest distance around the sphere.
1457  if (compare_distance2 < compare_distance1)
1458  {
1459  compare_distance = compare_distance2;
1460  spreading_velocity_at_ridge_pt = spreading_velocity_at_ridge_pt2;
1461  subducting_velocity_at_trench_pt = subducting_velocity_at_trench_pt2;
1462  }
1463 
1464  // Then, the distance and velocities are taken from the nearest point on the ridge
1465  if (i_coordinate == 0 || compare_distance < distance_ridge)
1466  {
1467  distance_ridge = compare_distance;
1468  spreading_velocity_at_ridge = spreading_velocity_at_ridge_pt;
1469  subducting_velocity_at_trench = subducting_velocity_at_trench_pt;
1470  }
1471  }
1472  }
1473  std::vector<double> result;
1474  result.push_back(spreading_velocity_at_ridge / seconds_in_year); // m/s
1475  result.push_back(distance_ridge);
1476  result.push_back(subducting_velocity_at_trench / seconds_in_year); // m/s
1477  result.push_back(ridge_migration_time);
1478  return result;
1479  }
1480 
1481  // TODO: implement method for modifying the age of the slab based on ridge/trench migration.
1482  std::vector<double>
1483  calculate_effective_trench_and_plate_ages(std::vector<double> ridge_parameters, double distance_along_plane)
1484  {
1485  WBAssert(ridge_parameters.size() == 4, "Internal error: ridge_parameters have the wrong size: " << ridge_parameters.size() << " instead of 4.");
1486  const double seconds_in_year = 60.0 * 60.0 * 24.0 * 365.25; // sec/y
1487  const double spreading_velocity = ridge_parameters[0] * seconds_in_year; // m/yr
1488  const double distance_ridge = ridge_parameters[1];
1489  const double subducting_velocity = ridge_parameters[2] * seconds_in_year; // m/yr
1490 
1491  WBAssertThrow(subducting_velocity >= 0, "The subducting velocity is less than 0. "
1492  "Subducting velocity: " << subducting_velocity);
1493 
1494  // Plate age increases with distance along the slab in the mantle
1495  double effective_plate_age = (distance_ridge + distance_along_plane) / spreading_velocity; // m/(m/y) = yr
1496 
1497  // Age of trench when the query point was at the trench
1498  const double age_at_trench = effective_plate_age - distance_along_plane / subducting_velocity; // m/(m/y) = yr
1499  WBAssertThrow(age_at_trench >= 0, "The age of trench at subducting initiation is less than 0. "
1500  "Age at trench: " << age_at_trench);
1501 
1502  std::vector<double> result;
1503  result.push_back(age_at_trench);
1504  result.push_back(effective_plate_age);
1505  return result;
1506 
1507  }
1508 
1509  std::array<std::array<double,3>,3>
1510  multiply_3x3_matrices(const std::array<std::array<double,3>,3> mat1, const std::array<std::array<double,3>,3> mat2)
1511  {
1512  std::array<std::array<double,3>,3> result;
1513  for (size_t i = 0; i < 3; i++)
1514  {
1515  for (size_t j = 0; j < 3; j++)
1516  {
1517  result[i][j] = 0;
1518  for (size_t k = 0; k < 3; k++)
1519  {
1520  result[i][j] += mat1[i][k] * mat2[k][j];
1521  }
1522  }
1523  }
1524 
1525  return result;
1526  }
1527  } // namespace Utilities
1528 } // namespace WorldBuilder
1529 
1530 
1531 
bool polygon_contains_point_implementation(const std::vector< Point< 2 > > &point_list, const Point< 2 > &point)
Definition: utilities.cc:63
std::array< double, dim > convert_point_to_array(const Point< dim > &point_)
Definition: utilities.cc:301
Class for circle line/spline, including interpolation on it.
Definition: bezier_curve.h:37
std::array< double, 3 > cartesian_to_spherical_coordinates(const Point< 3 > &position)
Definition: utilities.cc:255
std::vector< std::array< double, 4 > > m
Definition: utilities.h:265
template std::array< double, 2 > convert_point_to_array< 2 >(const Point< 2 > &point_)
std::array< double, 2 > get_surface_coordinates() const
bool approx(double a, double b, double error_factor=1e4)
Definition: utilities.h:48
std::array< std::array< double, 3 >, 3 > multiply_3x3_matrices(const std::array< std::array< double, 3 >, 3 > mat1, const std::array< std::array< double, 3 >, 3 > mat2)
Definition: utilities.cc:1510
int string_to_int(const std::string &string)
Definition: utilities.cc:329
Point< 3 > spherical_to_cartesian_coordinates(const std::array< double, 3 > &scoord)
Definition: utilities.cc:274
double distance(const Point< 2 > &two) const
Definition: point.cc:69
CoordinateSystem get_coordinate_system() const
Definition: point.h:403
const std::array< double, dim > & get_array() const
Definition: point.h:393
Point< 3 > cross_product(const Point< 3 > &a, const Point< 3 > &b)
Definition: utilities.cc:370
template std::array< double, 3 > convert_point_to_array< 3 >(const Point< 3 > &point_)
std::string read_and_distribute_file_content(const std::string &filename)
Definition: utilities.cc:1172
CoordinateSystem get_coordinate_system() const
std::vector< double > calculate_ridge_distance_and_spreading(std::vector< std::vector< Point< 2 >>> mid_oceanic_ridges, std::vector< std::vector< double >> mid_oceanic_spreading_velocities, const std::unique_ptr< WorldBuilder::CoordinateSystems::Interface > &coordinate_system, const Objects::NaturalCoordinate &position_in_natural_coordinates_at_min_depth, const std::vector< std::vector< double >> &subducting_plate_velocities, const std::vector< double > &ridge_migration_times)
Definition: utilities.cc:1290
#define WBAssert(condition, message)
Definition: assert.h:27
double norm() const
Definition: point.h:413
double cos(const double angle)
Definition: point.h:97
void set_points(const std::vector< double > &y)
Definition: utilities.cc:1040
ClosestPointOnCurve closest_point_on_curve_segment(const Point< 2 > &p, const bool verbose=false) const
Finds the closest point on the curve. If the the closest point doesn&#39;t fall on the segment...
PointDistanceFromCurvedPlanes distance_point_from_curved_planes(const Point< 3 > &check_point, const Objects::NaturalCoordinate &natural_coordinate, const Point< 2 > &reference_point, const std::vector< Point< 2 > > &point_list, const std::vector< std::vector< double > > &plane_segment_lengths, const std::vector< std::vector< Point< 2 > > > &plane_segment_angles, const double start_radius, const std::unique_ptr< CoordinateSystems::Interface > &coordinate_system, const bool only_positive, const Objects::BezierCurve &bezier_curve)
Definition: utilities.cc:380
double wrap_angle(const double angle)
Definition: utilities.cc:1090
#define WBAssertThrow(condition, message)
Definition: assert.h:40
double string_to_double(const std::string &string)
Definition: utilities.cc:310
unsigned int string_to_unsigned_int(const std::string &string)
Definition: utilities.cc:349
std::vector< double > calculate_effective_trench_and_plate_ages(std::vector< double > ridge_parameters, double distance_along_plane)
Definition: utilities.cc:1483
double fraction_from_ellipse_center(const Point< 2 > &ellipse_center, const double semi_major_axis, const double eccentricity, const double theta, const Point< 2 > &point)
Definition: utilities.cc:167
std::array< std::array< double, 3 >, 3 > euler_angles_to_rotation_matrix(double phi1_d, double theta_d, double phi2_d)
Definition: utilities.cc:1147
double sin(const double raw_angle)
Definition: point.h:81
bool polygon_contains_point(const std::vector< Point< 2 > > &point_list, const Point< 2 > &point)
Definition: utilities.cc:46
std::array< double, 3 > euler_angles_from_rotation_matrix(const std::array< std::array< double, 3 >, 3 > &rotation_matrix)
Definition: utilities.cc:1119
CoordinateSystem string_to_coordinate_system(const std::string &coordinate_system)
Definition: utilities.cc:287
constexpr double PI
Definition: consts.h:30
double signed_distance_to_polygon(const std::vector< Point< 2 > > &point_list, const Point< 2 > &point)
Definition: utilities.cc:191
double interpolate_angle_across_zero(const double angle_1, const double angle_2, const double fraction)
Definition: utilities.cc:1095
const std::array< double, 3 > & get_coordinates() const