World Builder  0.1.0-pre
A geodyanmic initial conditions generator
utilities.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2018 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 <boost/lexical_cast.hpp>
21 
23 #include <world_builder/assert.h>
25 
26 
27 namespace WorldBuilder
28 {
29  namespace Utilities
30  {
31  bool
32  polygon_contains_point(const std::vector<Point<2> > &point_list,
33  const Point<2> &point)
34  {
35 
54  int pointNo = point_list.size();
55  int wn = 0; // the winding number counter
56  int j=pointNo-1;
57 
58  // loop through all edges of the polygon
59  for (int i=0; i<pointNo; i++)
60  {
61  // edge from V[i] to V[i+1]
62  if (point_list[j][1] <= point[1])
63  {
64  // start y <= P.y
65  if (point_list[i][1] >= point[1]) // an upward crossing
66  {
67  const double is_left = (point_list[i][0] - point_list[j][0]) * (point[1] - point_list[j][1])
68  - (point[0] - point_list[j][0]) * (point_list[i][1] - point_list[j][1]);
69 
70  if ( is_left > 0 && point_list[i][1] > point[1])
71  {
72  // P left of edge
73  ++wn; // have a valid up intersect
74  }
75  else if ( is_left == 0)
76  {
77  // The point is exactly on the infinite line.
78  // determine if it is on the segment
79  const double dot_product = (point - point_list[j])*(point_list[i] - point_list[j]);
80 
81  if (dot_product >= 0)
82  {
83  const double squaredlength = (point_list[i] - point_list[j]).norm_square();
84 
85  if (dot_product <= squaredlength)
86  {
87  return true;
88  }
89  }
90  }
91  }
92  }
93  else
94  {
95  // start y > P.y (no test needed)
96  if (point_list[i][1] <= point[1]) // a downward crossing
97  {
98  const double is_left = (point_list[i][0] - point_list[j][0]) * (point[1] - point_list[j][1])
99  - (point[0] - point_list[j][0]) * (point_list[i][1] - point_list[j][1]);
100 
101  if ( is_left < 0)
102  {
103  // P right of edge
104  --wn; // have a valid down intersect
105  }
106  else if ( is_left == 0)
107  {
108  // This code is to make sure that the boundaries are included in the polygon.
109  // The point is exactly on the infinite line.
110  // determine if it is on the segment
111  const double dot_product = (point - point_list[j])*(point_list[i] - point_list[j]);
112 
113  if (dot_product >= 0)
114  {
115  const double squaredlength = (point_list[i] - point_list[j]).norm_square();
116 
117  if (dot_product <= squaredlength)
118  {
119  return true;
120  }
121  }
122  }
123  }
124  }
125  j=i;
126  }
127 
128  return (wn != 0);
129  }
130 
131  double
132  signed_distance_to_polygon(const std::vector<Point<2> > &point_list,
133  const Point<2> &point)
134  {
135  // If the point lies outside polygon, we give it a negative sign,
136  // inside a positive sign.
137  const double sign = polygon_contains_point(point_list, point) ? 1.0 : -1.0;
138 
152  const unsigned int n_poly_points = point_list.size();
153  WBAssertThrow(n_poly_points >= 3, "Not enough polygon points were specified.");
154 
155  // Initialize a vector of distances for each point of the polygon with a very large distance
156  std::vector<double> distances(n_poly_points, 1e23);
157 
158  // Create another polygon but with all points shifted 1 position to the right
159  std::vector<Point<2> > shifted_point_list(n_poly_points);
160  shifted_point_list[0] = point_list[n_poly_points-1];
161 
162  for (unsigned int i = 0; i < n_poly_points-1; ++i)
163  shifted_point_list[i+1] = point_list[i];
164 
165  for (unsigned int i = 0; i < n_poly_points; ++i)
166  {
167  // Create vector along the polygon line segment
168  Point<2> vector_segment = shifted_point_list[i] - point_list[i];
169  // Create vector from point to the second segment point
170  Point<2> vector_point_segment = point - point_list[i];
171 
172  // Compute dot products to get angles
173  const double c1 = vector_point_segment * vector_segment;
174  const double c2 = vector_segment * vector_segment;
175 
176  // point lies closer to not-shifted polygon point, but perpendicular base line lies outside segment
177  if (c1 <= 0.0)
178  distances[i] = (Point<2> (point_list[i] - point)).norm();
179  // point lies closer to shifted polygon point, but perpendicular base line lies outside segment
180  else if (c2 <= c1)
181  distances[i] = (Point<2> (shifted_point_list[i] - point)).norm();
182  // perpendicular base line lies on segment
183  else
184  {
185  const Point<2> point_on_segment = point_list[i] + (c1/c2) * vector_segment;
186  distances[i] = (Point<2> (point - point_on_segment)).norm();
187  }
188  }
189 
190  // Return the minimum of the distances of the point to all polygon segments
191  return *std::min_element(distances.begin(),distances.end()) * sign;
192  }
193 
194 
195  NaturalCoordinate::NaturalCoordinate(const std::array<double,3> &position,
196  const CoordinateSystems::Interface &coordinate_system_)
197  {
198  coordinate_system = coordinate_system_.natural_coordinate_system();
199  coordinates = coordinate_system_.cartesian_to_natural_coordinates(position);
200  }
201 
202  // todo, should be possible to make this without the interface, since the Point knows the coord system.
204  const CoordinateSystems::Interface &coordinate_system_)
205  {
206  coordinate_system = coordinate_system_.natural_coordinate_system();
207  coordinates = coordinate_system_.cartesian_to_natural_coordinates(position.get_array());
208  }
209 
210  const std::array<double,3> &NaturalCoordinate::get_coordinates()
211  {
212  return coordinates;
213  }
214 
215 
216  /*std::array<double,1> NaturalCoordinate::get_surface_coordinates() const
217  {
218  std::array<double,1> coordinate;
219 
220  switch (coordinate_system)
221  {
222  case Coordinates::CoordinateSystem::cartesian:
223  coordinate[0] = coordinates[0];
224  break;
225 
226  case Coordinates::CoordinateSystem::spherical:
227  coordinate[0] = coordinates[1];
228  break;
229 
230  default:
231  coordinate[0] = 0;
232  WBAssert (false, ExcNotImplemented());
233  break;
234  }
235 
236  return coordinate;
237  }*/
238 
239 
240  const std::array<double,2> NaturalCoordinate::get_surface_coordinates() const
241  {
242  std::array<double,2> coordinate;
243 
244  switch (coordinate_system)
245  {
247  coordinate[0] = coordinates[0];
248  coordinate[1] = coordinates[1];
249  break;
250 
252  coordinate[0] = coordinates[1];
253  coordinate[1] = coordinates[2];
254  break;
255 
256  default:
257  WBAssert (false, "Coordinate system not implemented.");
258  }
259 
260  return coordinate;
261  }
262 
263 
265  {
266  switch (coordinate_system)
267  {
269  return coordinates[2];
270 
272  return coordinates[0];
273 
274  default:
275  WBAssert (false, "Coordinate system not implemented.");
276  }
277 
278  return 0;
279  }
280 
281 
282  std::array<double,3>
284  {
285  std::array<double,3> scoord;
286 
287  scoord[0] = position.norm(); // R
288  scoord[1] = std::atan2(position[1],position[0]); // Phi
289  if (scoord[1] < 0.0)
290  scoord[1] += 2.0*M_PI; // correct phi to [0,2*pi]
291 
292  if (scoord[0] > std::numeric_limits<double>::min())
293  scoord[2] = std::acos(position[2]/scoord[0]);
294  else
295  scoord[2] = 0.0;
296 
297  return scoord;
298  }
299 
300  Point<3>
301  spherical_to_cartesian_coordinates(const std::array<double,3> &scoord)
302  {
303  Point<3> ccoord;
304 
305  ccoord[0] = scoord[0] * std::sin(scoord[2]) * std::cos(scoord[1]); // X
306  ccoord[1] = scoord[0] * std::sin(scoord[2]) * std::sin(scoord[1]); // Y
307  ccoord[2] = scoord[0] * std::cos(scoord[2]); // Z
308 
309 
310  return ccoord;
311  }
312 
313 
314 
316  string_to_coordinate_system(const std::string &coordinate_system)
317  {
318  if (coordinate_system == "cartesian")
320  else if (coordinate_system == "spherical")
322  else
323  WBAssertThrow(false, "Coordinate system not implemented.");
324 
325  return invalid;
326  }
327 
328 
329  template<int dim>
330  const std::array<double,dim>
332  {
333  std::array<double,dim> array;
334  for (unsigned int i = 0; i < dim; ++i)
335  array[i] = point_[i];
336  return array;
337  }
338 
339  double
340  string_to_double(const std::string &string)
341  {
342  // trim whitespace on either side of the text if necessary
343  std::string s = string;
344  while ((s.size() > 0) && (s[0] == ' '))
345  s.erase(s.begin());
346  while ((s.size() > 0) && (s[s.size() - 1] == ' '))
347  s.erase(s.end() - 1);
348 
349  double d = 0;
350  try
351  {
352  d = boost::lexical_cast<double>(s);
353  }
354  catch (const boost::bad_lexical_cast &e)
355  {
356  WBAssertThrow(false, "Conversion of \"" << string << "\" to double failed (bad cast): " << e.what() << std::endl);
357  }
358 
359  return d;
360  }
361 
362  double
363  string_to_int(const std::string &string)
364  {
365  // trim whitespace on either side of the text if necessary
366  std::string s = string;
367  while ((s.size() > 0) && (s[0] == ' '))
368  s.erase(s.begin());
369  while ((s.size() > 0) && (s[s.size() - 1] == ' '))
370  s.erase(s.end() - 1);
371 
372  double d = 0;
373  try
374  {
375  d = boost::lexical_cast<int>(s);
376  }
377  catch (const boost::bad_lexical_cast &e)
378  {
379  WBAssertThrow(false, "Conversion of \"" << string << "\" to int failed (bad cast): " << e.what() << std::endl);
380  }
381 
382  return d;
383  }
384 
385 
386  double
387  string_to_unsigned_int(const std::string &string)
388  {
389  // trim whitespace on either side of the text if necessary
390  std::string s = string;
391  while ((s.size() > 0) && (s[0] == ' '))
392  s.erase(s.begin());
393  while ((s.size() > 0) && (s[s.size() - 1] == ' '))
394  s.erase(s.end() - 1);
395 
396  double d = 0;
397  try
398  {
399  d = boost::lexical_cast<unsigned int>(s);
400  }
401  catch (const boost::bad_lexical_cast &e)
402  {
403  WBAssertThrow(false, "Conversion of \"" << string << "\" to unsigned int failed (bad cast): " << e.what() << std::endl);
404  }
405 
406  return d;
407  }
408 
409  boost::optional<std::string>
410  get_from_ptree(const ptree &tree,
411  const std::string &path,
412  const std::string &key,
413  const bool required,
414  const std::string &path_separator)
415  {
416  boost::optional<std::string> value = tree.get_optional<std::string> (key);
417  WBAssertThrow ((value && required == true) || required == false, "Entry undeclared: " + path + path_separator + key +
418  ". Tree: " << std::endl << print_tree(tree,0).str() << std::endl);
419  return value;
420  }
421 
422  boost::optional<std::string>
423  get_from_ptree_abs(const ptree &tree,
424  const std::string &path,
425  const std::string &key,
426  const bool required,
427  const std::string &path_separator)
428  {
429  std::string use_path = path == "" ? key : path + path_separator + key;
430  boost::optional<std::string> value = tree.get_optional<std::string> (use_path);
431  WBAssertThrow ((value && required == true) || required == false, "Entry undeclared: " + use_path +
432  ". Tree: " << std::endl << print_tree(tree,0).str() << std::endl);
433  return value;
434  }
435 
436  /*std::string
437  escape_string(std::string &original)
438  {
439  // first escape the escape character. Lets say we start with "abc &amp;[ ]"
440  //std::replace( s.begin(), s.end(), '&', '&amp');
441  // This now became "abc &ampamp[ ]". Escape the other characters:
442  //std::replace( s.begin(), s.end(), ' ', '&spa');
443  // This now became "abc&spa&ampamp[&spa]"
444  //std::replace( s.begin(), s.end(), '[', 'lsqb');
445  }*/
446 
447  std::string indent(int level)
448  {
449  std::string s;
450  for (int i=0; i<level; i++) s += " ";
451  return s;
452  }
453 
454  std::stringstream print_tree (const ptree &pt, int level)
455  {
456  std::stringstream ss;
457  if (pt.empty())
458  {
459  ss << "\""<< pt.data()<< "\"";
460  }
461 
462  else
463  {
464  if (level) ss << std::endl;
465 
466  ss << indent(level) << "{" << std::endl;
467 
468  for (ptree::const_iterator pos = pt.begin(); pos != pt.end();)
469  {
470  ss << indent(level+1) << "\"" << pos->first << "\": ";
471 
472  ss << print_tree(pos->second, level + 1).str();
473  ++pos;
474  if (pos != pt.end())
475  {
476  ss << ",";
477  }
478  ss << std::endl;
479  }
480  ss << indent(level) << " }";
481  }
482 
483  return ss;
484  }
485 
486  template const std::array<double,2> convert_point_to_array<2>(const Point<2> &point_);
487  template const std::array<double,3> convert_point_to_array<3>(const Point<3> &point_);
488  }
489 }
490 
491 
492 
boost::optional< std::string > get_from_ptree(const ptree &tree, const std::string &path, const std::string &key, const bool required, const std::string &path_separator)
Definition: utilities.cc:410
std::array< double, 3 > cartesian_to_spherical_coordinates(const Point< 3 > &position)
Definition: utilities.cc:283
const std::array< double, 2 > get_surface_coordinates() const
Definition: utilities.cc:240
virtual CoordinateSystem natural_coordinate_system() const =0
std::stringstream print_tree(const ptree &pt, int level)
Definition: utilities.cc:454
Point< 3 > spherical_to_cartesian_coordinates(const std::array< double, 3 > &scoord)
Definition: utilities.cc:301
double string_to_unsigned_int(const std::string &string)
Definition: utilities.cc:387
const std::array< double, dim > & get_array() const
Definition: point.cc:201
#define WBAssert(condition, message)
Definition: assert.h:28
double norm() const
Definition: point.cc:217
const std::array< double, dim > convert_point_to_array(const Point< dim > &point_)
Definition: utilities.cc:331
std::string indent(int level)
Definition: utilities.cc:447
boost::optional< std::string > get_from_ptree_abs(const ptree &tree, const std::string &path, const std::string &key, const bool required, const std::string &path_separator)
Definition: utilities.cc:423
virtual std::array< double, 3 > cartesian_to_natural_coordinates(const std::array< double, 3 > &position) const =0
const std::array< double, 3 > & get_coordinates()
Definition: utilities.cc:210
#define WBAssertThrow(condition, message)
Definition: assert.h:41
double string_to_double(const std::string &string)
Definition: utilities.cc:340
NaturalCoordinate(const std::array< double, 3 > &position, const ::WorldBuilder::CoordinateSystems::Interface &coordinate_system)
bool polygon_contains_point(const std::vector< Point< 2 > > &point_list, const Point< 2 > &point)
Definition: utilities.cc:32
double string_to_int(const std::string &string)
Definition: utilities.cc:363
CoordinateSystem string_to_coordinate_system(const std::string &coordinate_system)
Definition: utilities.cc:316
template const std::array< double, 2 > convert_point_to_array< 2 >(const Point< 2 > &point_)
template const std::array< double, 3 > convert_point_to_array< 3 >(const Point< 3 > &point_)
double signed_distance_to_polygon(const std::vector< Point< 2 > > &point_list, const Point< 2 > &point)
Definition: utilities.cc:132