PGROUTING  3.2
alphaShape_driver.cpp
Go to the documentation of this file.
1 /*PGR-GNU*****************************************************************
2 FILE: alphaShape_driver.cpp
3 
4 Copyright (c) 2018 Vicky Vergara
6 
7 ------
8 
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 
23  ********************************************************************PGR-GNU*/
24 
29 
30 #include <cmath>
31 #include <vector>
32 #include <string>
33 #include <utility>
34 #include <algorithm>
35 
36 #include "cpp_common/pgr_assert.h"
38 
39 #include "cpp_common/pgr_alloc.hpp"
40 
42 #include "cpp_common/bpoint.hpp"
43 #include "cpp_common/bline.hpp"
44 #include <boost/geometry/io/wkt/write.hpp>
45 
46 
47 namespace {
48 bool
49 data_eq(const Pgr_edge_xy_t &lhs, const Pgr_edge_xy_t &rhs, int64_t round) {
50  return
51  std::floor(lhs.x1 * static_cast<double>(round)) == std::floor(rhs.x1 * static_cast<double>(round))
52  &&
53  std::floor(lhs.y1 * static_cast<double>(round)) == std::floor(rhs.y1 * static_cast<double>(round));
54 }
55 
56 }
57 
58 void
60  Pgr_edge_xy_t *edgesArr,
61  size_t edgesSize,
62 
63  double alpha,
64 
65  GeomText_t **return_tuples,
66  size_t *return_count,
67 
68  char **log_msg,
69  char **notice_msg,
70  char **err_msg) {
71  std::ostringstream log;
72  std::ostringstream err;
73  std::ostringstream notice;
74  try {
75  pgassert(edgesArr);
76  pgassert(edgesSize > 2);
77  pgassert(*return_count == 0);
78  const int64_t round = 100000000000000;
79 
80  std::vector<Pgr_edge_xy_t> edges(edgesArr, edgesArr + edgesSize);
81  /*
82  id | source | target | cost | x1 | y1 | x2 | y2
83  -------+--------+--------+------+------------+------------+----+----
84  1 | 1 | -1 | 1 | 29.1296668 | 40.9434941 | 0 | 0
85  1 | 2 | -1 | 1 | 29.1267903 | 40.9343215 | 0 | 0
86  1 | 3 | -1 | 1 | 29.1296615 | 40.943359 | 0 | 0
87  sort based on y1
88  stable sort on x1
89  */
90 
91  std::sort(edges.begin(), edges.end(),
92  [&](const Pgr_edge_xy_t &lhs, const Pgr_edge_xy_t &rhs) {
93  return
94  std::floor(lhs.y1 * static_cast<double>(round)) < std::floor(rhs.y1 * static_cast<double>(round));
95  });
96  std::stable_sort(edges.begin(), edges.end(),
97  [&](const Pgr_edge_xy_t &lhs, const Pgr_edge_xy_t &rhs) {
98  return
99  std::floor(lhs.x1 * static_cast<double>(round)) < std::floor(rhs.x1 * static_cast<double>(round));
100  });
101  log << "ending sort";
102 
103 
104 
105  int64_t source_id(0);
106  auto prev = edges.front();
107  for (auto &e : edges) {
108  if (data_eq(e, prev, round)) {
109  e.source = source_id;
110  } else {
111  e.source = ++source_id;
112  prev = e;
113  }
114  }
115  std::stable_sort(edges.begin(), edges.end(),
116  [](const Pgr_edge_xy_t &lhs, const Pgr_edge_xy_t &rhs) {
117  return
118  lhs.id < rhs.id;
119  });
120 
121  /*
122  * Vertices of triangle a, b, c
123  */
124  Pgr_edge_xy_t *a(nullptr);
125  Pgr_edge_xy_t *b(nullptr);
126  size_t count(0);
127  for (auto &c : edges) {
128  if (count == 0) {
129  a = &c;
130  ++count;
131  continue;
132  }
133  if (count == 1) {
134  b = &c;
135  pgassert(a->id == b->id);
136  ++count;
137  continue;
138  }
139  pgassert(a->id == b->id);
140  pgassert(a->id == c.id);
141 
142  a->target = b->source;
143  a->x2 = b->x1;
144  a->y2 = b->y1;
145 
146  b->target = c.source;
147  b->x2 = c.x1;
148  b->y2 = c.y1;
149 
150  c.target = a->source;
151  c.x2 = a->x1;
152  c.y2 = a->y1;
153  count = 0;
154  }
155 
156  using Pgr_alphaShape = pgrouting::alphashape::Pgr_alphaShape;
157  Pgr_alphaShape alphaShape(edges);
158 
159  auto results = alphaShape(alpha);
160  log << alphaShape.get_log();
161 
162  /*
163  * returning a sequence of text
164  */
165  if (results.empty()) {
166  *return_count = 1;
167  *return_tuples = pgr_alloc(*return_count, (*return_tuples));
168  std::stringstream ss;
169  ss << "MULTIPOLYGON EMPTY";
170  (*return_tuples)[0].geom = pgr_msg(ss.str().c_str());
171  } else {
172  *return_count = results.size();
173  *return_tuples = pgr_alloc(*return_count, (*return_tuples));
174  size_t row = 0;
175  for (const auto &r : results) {
176  std::stringstream ss;
177  ss << bg::wkt(r);
178  (*return_tuples)[row].geom = pgr_msg(ss.str().c_str());
179  ++row;
180  }
181  }
182 
183 
184  *log_msg = log.str().empty()?
185  *log_msg :
186  pgr_msg(log.str().c_str());
187  *notice_msg = notice.str().empty()?
188  *notice_msg :
189  pgr_msg(notice.str().c_str());
190  } catch (AssertFailedException &except) {
191  (*return_tuples) = pgr_free(*return_tuples);
192  (*return_count) = 0;
193  err << except.what();
194  *err_msg = pgr_msg(err.str().c_str());
195  } catch (std::exception &except) {
196  (*return_tuples) = pgr_free(*return_tuples);
197  (*return_count) = 0;
198  err << except.what();
199  *err_msg = pgr_msg(err.str().c_str());
200  } catch(...) {
201  (*return_tuples) = pgr_free(*return_tuples);
202  (*return_count) = 0;
203  err << "Caught unknown exception!";
204  *err_msg = pgr_msg(err.str().c_str());
205  }
206 }
Pgr_edge_xy_t::target
int64_t target
Definition: pgr_edge_xy_t.h:41
pgr_alloc
T * pgr_alloc(std::size_t size, T *ptr)
allocates memory
Definition: pgr_alloc.hpp:66
pgr_base_graph.hpp
Pgr_edge_xy_t::source
int64_t source
Definition: pgr_edge_xy_t.h:40
pgr_msg
char * pgr_msg(const std::string &msg)
Definition: pgr_alloc.cpp:30
AssertFailedException::what
virtual const char * what() const
Definition: pgr_assert.cpp:67
anonymous_namespace{alphaShape_driver.cpp}::data_eq
bool data_eq(const Pgr_edge_xy_t &lhs, const Pgr_edge_xy_t &rhs, int64_t round)
Definition: alphaShape_driver.cpp:49
bline.hpp
pgassert
#define pgassert(expr)
Uses the standard assert syntax.
Definition: pgr_assert.h:94
Pgr_edge_xy_t::y1
double y1
Definition: pgr_edge_xy_t.h:45
Pgr_edge_xy_t::y2
double y2
Definition: pgr_edge_xy_t.h:47
pgr_alloc.hpp
pgr_assert.h
An assert functionality that uses C++ throw().
Pgr_edge_xy_t::x2
double x2
Definition: pgr_edge_xy_t.h:46
bpoint.hpp
alphaShape_driver.h
Pgr_edge_xy_t::id
int64_t id
Definition: pgr_edge_xy_t.h:39
pgr_free
T * pgr_free(T *ptr)
Definition: pgr_alloc.hpp:77
pgr_alphaShape.h
do_alphaShape
void do_alphaShape(Pgr_edge_xy_t *edgesArr, size_t edgesSize, double alpha, GeomText_t **return_tuples, size_t *return_count, char **log_msg, char **notice_msg, char **err_msg)
Definition: alphaShape_driver.cpp:59
pgrouting::alphashape::Pgr_alphaShape
Definition: pgr_alphaShape.h:63
GeomText_t
Definition: geom_text_rt.h:30
Pgr_edge_xy_t
Definition: pgr_edge_xy_t.h:38
Pgr_edge_xy_t::x1
double x1
Definition: pgr_edge_xy_t.h:44
AssertFailedException
Extends std::exception and is the exception that we throw if an assert fails.
Definition: pgr_assert.h:139