PGROUTING  2.6
alpha.c File Reference
#include <float.h>
#include <stdint.h>
#include "c_common/postgres_connection.h"
#include "catalog/pg_type.h"
#include "c_common/e_report.h"
#include "drivers/alpha_shape/alpha_driver.h"
#include "c_common/debug_macro.h"
Include dependency graph for alpha.c:

Go to the source code of this file.

Classes

struct  vertex_columns
 

Macros

#define TUPLIMIT   1000
 

Typedefs

typedef struct vertex_columns vertex_columns_t
 

Functions

PGDLLEXPORT Datum alphashape (PG_FUNCTION_ARGS)
 
static void compute_alpha_shape (char *sql, float8 alpha, vertex_t **res, size_t *res_count)
 
static void fetch_vertex (HeapTuple *tuple, TupleDesc *tupdesc, vertex_columns_t *vertex_columns, vertex_t *target_vertex)
 
static int fetch_vertices_columns (SPITupleTable *tuptable, vertex_columns_t *vertex_columns)
 
 PG_FUNCTION_INFO_V1 (alphashape)
 

Macro Definition Documentation

#define TUPLIMIT   1000

Definition at line 50 of file alpha.c.

Referenced by compute_alpha_shape(), and compute_trsp().

Typedef Documentation

Function Documentation

PGDLLEXPORT Datum alphashape ( PG_FUNCTION_ARGS  )

Definition at line 254 of file alpha.c.

References compute_alpha_shape(), PGR_DBG, vertex::x, vertex_columns::x, vertex::y, and vertex_columns::y.

Referenced by compute_alpha_shape().

254  {
255  FuncCallContext *funcctx;
256  TupleDesc tuple_desc;
257  vertex_t *res = NULL;
258 
259  /* stuff done only on the first call of the function */
260  if (SRF_IS_FIRSTCALL()) {
261  MemoryContext oldcontext;
262  size_t res_count;
263 
264 
265  /* create a function context for cross-call persistence */
266  funcctx = SRF_FIRSTCALL_INIT();
267 
268  /* switch to memory context appropriate for multiple function calls */
269  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
270 
271  compute_alpha_shape(text_to_cstring(PG_GETARG_TEXT_P(0)),
272  PG_GETARG_FLOAT8(1), &res, &res_count);
273 
274  /* total number of tuples to be returned */
275  PGR_DBG("Conting tuples number\n");
276 #if PGSQL_VERSION > 95
277  funcctx->max_calls = res_count;
278 #else
279  funcctx->max_calls = (uint32_t)res_count;
280 #endif
281  funcctx->user_fctx = res;
282 
283  PGR_DBG("Total count %lu", res_count);
284 
285  if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE)
286  ereport(ERROR,
287  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
288  errmsg("function returning record called in context "
289  "that cannot accept type record")));
290 
291  funcctx->tuple_desc = BlessTupleDesc(tuple_desc);
292 
293  MemoryContextSwitchTo(oldcontext);
294  }
295 
296  /* stuff done on every call of the function */
297  PGR_DBG("Strange stuff doing\n");
298  funcctx = SRF_PERCALL_SETUP();
299 
300  tuple_desc = funcctx->tuple_desc;
301  res = (vertex_t*)funcctx->user_fctx;
302 
303  PGR_DBG("Trying to allocate some memory\n");
304 
305  if (funcctx->call_cntr < funcctx->max_calls) {
306  /* do when there is more left to send */
307  HeapTuple tuple;
308  Datum result;
309  Datum *values;
310  bool* nulls;
311  double x;
312  double y;
313 
314  values = palloc(2 * sizeof(Datum));
315  nulls = palloc(2 * sizeof(bool));
316 
317  x = res[funcctx->call_cntr].x;
318  y = res[funcctx->call_cntr].y;
319  if (x == DBL_MAX && y == DBL_MAX) {
320  values[0] = 0;
321  values[1] = 0;
322  nulls[0] = true;
323  nulls[1] = true;
324  } else {
325  values[0] = Float8GetDatum(x);
326  values[1] = Float8GetDatum(y);
327  nulls[0] = false;
328  nulls[1] = false;
329  }
330 
331  PGR_DBG("Heap making\n");
332 
333  tuple = heap_form_tuple(tuple_desc, values, nulls);
334 
335  PGR_DBG("Datum making\n");
336 
337  /* make the tuple into a datum */
338  result = HeapTupleGetDatum(tuple);
339 
340  PGR_DBG("Trying to free some memory\n");
341 
342  /* clean up (this is not really necessary) */
343  pfree(values);
344  pfree(nulls);
345 
346  SRF_RETURN_NEXT(funcctx, result);
347  } else {
348  SRF_RETURN_DONE(funcctx);
349  }
350 }
double y
Definition: alpha_driver.h:33
#define PGR_DBG(...)
Definition: debug_macro.h:34
static void compute_alpha_shape(char *sql, float8 alpha, vertex_t **res, size_t *res_count)
Definition: alpha.c:118
double x
Definition: alpha_driver.h:32

Here is the call graph for this function:

Here is the caller graph for this function:

static void compute_alpha_shape ( char *  sql,
float8  alpha,
vertex_t **  res,
size_t *  res_count 
)
static

Definition at line 118 of file alpha.c.

References alpha_shape(), alphashape(), fetch_vertex(), fetch_vertices_columns(), vertex_columns::id, PG_FUNCTION_INFO_V1(), PGR_DBG, pgr_global_report(), pgr_SPI_finish(), and TUPLIMIT.

Referenced by alphashape().

121  {
122  int SPIcode;
123  void *SPIplan;
124  Portal SPIportal;
125  bool moredata = true;
126  size_t ntuples;
127  vertex_t *vertices = NULL;
128  size_t total_tuples = 0;
129 #ifndef _MSC_VER
130  vertex_columns_t vertex_columns = {.id = -1, .x = -1, .y = -1};
131 #else // _MSC_VER
132  vertex_columns_t vertex_columns = {-1, -1, -1};
133 #endif // _MSC_VER
134 #if 0
135  int ret = -1;
136 #endif
137  PGR_DBG("start alpha_shape\n");
138 
139  SPIcode = SPI_connect();
140  if (SPIcode != SPI_OK_CONNECT) {
141  elog(ERROR, "alpha_shape: couldn't open a connection to SPI");
142  return;
143  }
144 
145  SPIplan = SPI_prepare(sql, 0, NULL);
146  if (SPIplan == NULL) {
147  elog(ERROR, "alpha_shape: couldn't create query plan via SPI");
148  return;
149  }
150 
151  if ((SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true)) == NULL) {
152  elog(ERROR, "alpha_shape: SPI_cursor_open('%s') returns NULL", sql);
153  return;
154  }
155 
156  while (moredata == true) {
157  SPI_cursor_fetch(SPIportal, true, TUPLIMIT);
158 
159  if (vertex_columns.id == -1) {
160  if (fetch_vertices_columns(SPI_tuptable, &vertex_columns) == -1)
161  return;
162  }
163 
164  ntuples = SPI_processed;
165  total_tuples += ntuples;
166  if (!vertices)
167  vertices = palloc(total_tuples * sizeof(vertex_t));
168  else
169  vertices = repalloc(vertices, total_tuples * sizeof(vertex_t));
170 
171  if (vertices == NULL) {
172  elog(ERROR, "Out of memory");
173  return;
174  }
175 
176  if (ntuples > 0) {
177  uint32_t t;
178  SPITupleTable *tuptable = SPI_tuptable;
179  TupleDesc tupdesc = SPI_tuptable->tupdesc;
180 
181  for (t = 0; t < ntuples; t++) {
182  HeapTuple tuple = tuptable->vals[t];
183  fetch_vertex(&tuple, &tupdesc, &vertex_columns,
184  &vertices[total_tuples - ntuples + t]);
185  }
186  SPI_freetuptable(tuptable);
187  } else {
188  moredata = false;
189  }
190  }
191 
192 
193  // if (total_tuples < 2) //this was the buggy code of the pgrouting project.
194  // TODO(someone): report this as a bug to the pgrouting project
195  // the CGAL alpha-shape function crashes
196  // if called with less than three points!!!
197 
198  if (total_tuples < 3) {
199  if (vertices) pfree(vertices);
200  pgr_SPI_finish();
201  elog(ERROR, "Less than 3 vertices."
202  " Alpha shape calculation needs at least 3 vertices.");
203  return;
204  }
205  if (total_tuples == 1) {
206  if (vertices) pfree(vertices);
207  pgr_SPI_finish();
208  elog(ERROR, "Distance is too short."
209  " only 1 vertex for alpha shape calculation."
210  " alpha shape calculation needs at least 3 vertices.");
211  return;
212  }
213  if (total_tuples == 2) {
214  if (vertices) pfree(vertices);
215  pgr_SPI_finish();
216  elog(ERROR, "Distance is too short."
217  " only 2 vertices for alpha shape calculation."
218  " alpha shape calculation needs at least 3 vertices.");
219  return;
220  }
221  if (total_tuples < 3) {
222  // elog(ERROR, "Distance is too short ....");
223  if (vertices) pfree(vertices);
224  pgr_SPI_finish();
225  return;
226  }
227 
228  PGR_DBG("Calling CGAL alpha-shape\n");
229 
230  char *err_msg = NULL;
231  char* log_msg = NULL;
232  char* notice_msg = NULL;
233 
234  alpha_shape(vertices, total_tuples, alpha, res, res_count, &err_msg);
235 
236  if (err_msg && (*res)) {
237  pfree(*res);
238  (*res) = NULL;
239  (*res_count) = 0;
240  }
241 
242  pgr_global_report(log_msg, notice_msg, err_msg);
243 
244  if (log_msg) pfree(log_msg);
245  if (notice_msg) pfree(notice_msg);
246  if (err_msg) pfree(err_msg);
247  if (vertices) pfree(vertices);
248  pgr_SPI_finish();
249 }
#define PGR_DBG(...)
Definition: debug_macro.h:34
int alpha_shape(vertex_t *vertices, size_t count, double alpha, vertex_t **return_tuples, size_t *res_count, char **err_msg)
static int fetch_vertices_columns(SPITupleTable *tuptable, vertex_columns_t *vertex_columns)
Definition: alpha.c:74
static void fetch_vertex(HeapTuple *tuple, TupleDesc *tupdesc, vertex_columns_t *vertex_columns, vertex_t *target_vertex)
Definition: alpha.c:102
void pgr_global_report(char *log, char *notice, char *err)
notice & error
Definition: e_report.c:93
void pgr_SPI_finish(void)
#define TUPLIMIT
Definition: alpha.c:50

Here is the call graph for this function:

Here is the caller graph for this function:

static void fetch_vertex ( HeapTuple *  tuple,
TupleDesc *  tupdesc,
vertex_columns_t vertex_columns,
vertex_t target_vertex 
)
static

Definition at line 102 of file alpha.c.

References vertex::x, vertex_columns::x, vertex::y, and vertex_columns::y.

Referenced by compute_alpha_shape().

103  {
104  Datum binval;
105  bool isnull;
106 
107  binval = SPI_getbinval(*tuple, *tupdesc, vertex_columns->x, &isnull);
108  if (isnull)
109  elog(ERROR, "x contains a null value");
110  target_vertex->x = DatumGetFloat8(binval);
111 
112  binval = SPI_getbinval(*tuple, *tupdesc, vertex_columns->y, &isnull);
113  if (isnull)
114  elog(ERROR, "y contains a null value");
115  target_vertex->y = DatumGetFloat8(binval);
116 }
double y
Definition: alpha_driver.h:33
double x
Definition: alpha_driver.h:32

Here is the caller graph for this function:

static int fetch_vertices_columns ( SPITupleTable *  tuptable,
vertex_columns_t vertex_columns 
)
static

Definition at line 74 of file alpha.c.

References vertex_columns::id, vertex_columns::x, and vertex_columns::y.

Referenced by compute_alpha_shape().

75  {
76  if (tuptable) {} // TODO(vicky) this is unused parameter
77  vertex_columns->id = SPI_fnumber(SPI_tuptable->tupdesc, "id");
78  vertex_columns->x = SPI_fnumber(SPI_tuptable->tupdesc, "x");
79  vertex_columns->y = SPI_fnumber(SPI_tuptable->tupdesc, "y");
80 
81  if (vertex_columns->id == SPI_ERROR_NOATTRIBUTE ||
82  vertex_columns->x == SPI_ERROR_NOATTRIBUTE ||
83  vertex_columns->y == SPI_ERROR_NOATTRIBUTE) {
84  elog(ERROR, "Error, query must return columns "
85  "'id', 'x' and 'y'");
86  return -1;
87  }
88 
89  if (SPI_gettypeid(SPI_tuptable->tupdesc, vertex_columns->id) != INT4OID ||
90  SPI_gettypeid(SPI_tuptable->tupdesc, vertex_columns->x) != FLOAT8OID ||
91  SPI_gettypeid(SPI_tuptable->tupdesc, vertex_columns->y) != FLOAT8OID) {
92  elog(ERROR,
93  "Error, column 'id' must be of type int4,"
94  "'x' and 'y' must be of type float8");
95  return -1;
96  }
97 
98  return 0;
99 }

Here is the caller graph for this function:

PG_FUNCTION_INFO_V1 ( alphashape  )

Referenced by compute_alpha_shape().

Here is the caller graph for this function: