PGROUTING  2.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
alpha.c File Reference
#include "c_common/postgres_connection.h"
#include <float.h>
#include "catalog/pg_type.h"
#include <stdint.h>
#include "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 int 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)
 
static int finish (int code, int ret)
 
 PG_FUNCTION_INFO_V1 (alphashape)
 

Macro Definition Documentation

#define TUPLIMIT   1000

Definition at line 48 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 220 of file alpha.c.

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

220  {
221  FuncCallContext *funcctx;
222  TupleDesc tuple_desc;
223  vertex_t *res = NULL;
224 
225  /* stuff done only on the first call of the function */
226  if (SRF_IS_FIRSTCALL()) {
227  MemoryContext oldcontext;
228  size_t res_count;
229 
230 
231  /* create a function context for cross-call persistence */
232  funcctx = SRF_FIRSTCALL_INIT();
233 
234  /* switch to memory context appropriate for multiple function calls */
235  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
236 
237  compute_alpha_shape(text_to_cstring(PG_GETARG_TEXT_P(0)),
238  PG_GETARG_FLOAT8(1), &res, &res_count);
239 
240  /* total number of tuples to be returned */
241  PGR_DBG("Conting tuples number\n");
242 #if PGSQL_VERSION > 95
243  funcctx->max_calls = res_count;
244 #else
245  funcctx->max_calls = (uint32_t)res_count;
246 #endif
247  funcctx->user_fctx = res;
248 
249  PGR_DBG("Total count %lu", res_count);
250 
251  if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE)
252  ereport(ERROR,
253  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
254  errmsg("function returning record called in context "
255  "that cannot accept type record")));
256 
257  funcctx->tuple_desc = BlessTupleDesc(tuple_desc);
258 
259  MemoryContextSwitchTo(oldcontext);
260  }
261 
262  /* stuff done on every call of the function */
263  PGR_DBG("Strange stuff doing\n");
264  funcctx = SRF_PERCALL_SETUP();
265 
266  tuple_desc = funcctx->tuple_desc;
267  res = (vertex_t*)funcctx->user_fctx;
268 
269  PGR_DBG("Trying to allocate some memory\n");
270 
271  if (funcctx->call_cntr < funcctx->max_calls) {
272  /* do when there is more left to send */
273  HeapTuple tuple;
274  Datum result;
275  Datum *values;
276  bool* nulls;
277  double x;
278  double y;
279 
280  values = palloc(2 * sizeof(Datum));
281  nulls = palloc(2 * sizeof(bool));
282 
283  x = res[funcctx->call_cntr].x;
284  y = res[funcctx->call_cntr].y;
285  if (x == DBL_MAX && y == DBL_MAX) {
286  values[0] = 0;
287  values[1] = 0;
288  nulls[0] = true;
289  nulls[1] = true;
290  } else {
291  values[0] = Float8GetDatum(x);
292  values[1] = Float8GetDatum(y);
293  nulls[0] = false;
294  nulls[1] = false;
295  }
296 
297  PGR_DBG("Heap making\n");
298 
299  tuple = heap_form_tuple(tuple_desc, values, nulls);
300 
301  PGR_DBG("Datum making\n");
302 
303  /* make the tuple into a datum */
304  result = HeapTupleGetDatum(tuple);
305 
306  PGR_DBG("Trying to free some memory\n");
307 
308  /* clean up (this is not really necessary) */
309  pfree(values);
310  pfree(nulls);
311 
312  SRF_RETURN_NEXT(funcctx, result);
313  } else {
314  SRF_RETURN_DONE(funcctx);
315  }
316 }
double y
Definition: alpha_driver.h:33
#define PGR_DBG(...)
Definition: debug_macro.h:34
static int compute_alpha_shape(char *sql, float8 alpha, vertex_t **res, size_t *res_count)
Definition: alpha.c:114
double x
Definition: alpha_driver.h:32

Here is the call graph for this function:

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

Definition at line 114 of file alpha.c.

References alpha_shape(), fetch_vertex(), fetch_vertices_columns(), finish(), vertex_columns::id, PGR_DBG, and TUPLIMIT.

Referenced by alphashape().

114  {
115  int SPIcode;
116  void *SPIplan;
117  Portal SPIportal;
118  bool moredata = TRUE;
119  size_t ntuples;
120  vertex_t *vertices = NULL;
121  size_t total_tuples = 0;
122 #ifndef _MSC_VER
123  vertex_columns_t vertex_columns = {.id = -1, .x = -1, .y = -1};
124 #else // _MSC_VER
125  vertex_columns_t vertex_columns = {-1, -1, -1};
126 #endif // _MSC_VER
127  char *err_msg;
128  int ret = -1;
129 
130  PGR_DBG("start alpha_shape\n");
131 
132  SPIcode = SPI_connect();
133  if (SPIcode != SPI_OK_CONNECT) {
134  elog(ERROR, "alpha_shape: couldn't open a connection to SPI");
135  return -1;
136  }
137 
138  SPIplan = SPI_prepare(sql, 0, NULL);
139  if (SPIplan == NULL) {
140  elog(ERROR, "alpha_shape: couldn't create query plan via SPI");
141  return -1;
142  }
143 
144  if ((SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true)) == NULL) {
145  elog(ERROR, "alpha_shape: SPI_cursor_open('%s') returns NULL", sql);
146  return -1;
147  }
148 
149  while (moredata == TRUE) {
150  SPI_cursor_fetch(SPIportal, TRUE, TUPLIMIT);
151 
152  if (vertex_columns.id == -1) {
153  if (fetch_vertices_columns(SPI_tuptable, &vertex_columns) == -1)
154  return finish(SPIcode, ret);
155  }
156 
157  ntuples = SPI_processed;
158  total_tuples += ntuples;
159  if (!vertices)
160  vertices = palloc(total_tuples * sizeof(vertex_t));
161  else
162  vertices = repalloc(vertices, total_tuples * sizeof(vertex_t));
163 
164  if (vertices == NULL) {
165  elog(ERROR, "Out of memory");
166  return finish(SPIcode, ret);
167  }
168 
169  if (ntuples > 0) {
170  uint32_t t;
171  SPITupleTable *tuptable = SPI_tuptable;
172  TupleDesc tupdesc = SPI_tuptable->tupdesc;
173 
174  for (t = 0; t < ntuples; t++) {
175  HeapTuple tuple = tuptable->vals[t];
176  fetch_vertex(&tuple, &tupdesc, &vertex_columns,
177  &vertices[total_tuples - ntuples + t]);
178  }
179  SPI_freetuptable(tuptable);
180  } else {
181  moredata = FALSE;
182  }
183  }
184 
185 
186  // if (total_tuples < 2) //this was the buggy code of the pgrouting project.
187  // TODO(someone): report this as a bug to the pgrouting project
188  // the CGAL alpha-shape function crashes if called with less than three points!!!
189 
190  if (total_tuples < 3) {
191  elog(ERROR, "Less than 3 vertices. Alpha shape calculation needs at least 3 vertices.");
192  return finish(SPIcode, ret);
193  }
194  if (total_tuples == 1) {
195  elog(ERROR, "Distance is too short. only 1 vertex for alpha shape calculation. alpha shape calculation needs at least 3 vertices.");
196  }
197  if (total_tuples == 2) {
198  elog(ERROR, "Distance is too short. only 2 vertices for alpha shape calculation. alpha shape calculation needs at least 3 vertices.");
199  }
200  if (total_tuples < 3) {
201  // elog(ERROR, "Distance is too short ....");
202  return finish(SPIcode, ret);
203  }
204 
205  PGR_DBG("Calling CGAL alpha-shape\n");
206 
207  ret = alpha_shape(vertices, total_tuples, alpha, res, res_count, &err_msg);
208 
209  if (ret < 0) {
210  // elog(ERROR, "Error computing shape: %s", err_msg);
211  ereport(ERROR, (errcode(ERRCODE_E_R_E_CONTAINING_SQL_NOT_PERMITTED), errmsg("%s", err_msg)));
212  }
213 
214  return finish(SPIcode, ret);
215 }
static int finish(int code, int ret)
Definition: alpha.c:52
#define PGR_DBG(...)
Definition: debug_macro.h:34
static int fetch_vertices_columns(SPITupleTable *tuptable, vertex_columns_t *vertex_columns)
Definition: alpha.c:71
static void fetch_vertex(HeapTuple *tuple, TupleDesc *tupdesc, vertex_columns_t *vertex_columns, vertex_t *target_vertex)
Definition: alpha.c:98
#define TUPLIMIT
Definition: alpha.c:48
int alpha_shape(vertex_t *vertices, size_t count, double alpha, vertex_t **res, size_t *res_count, char **err_msg)

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 98 of file alpha.c.

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

Referenced by compute_alpha_shape().

99  {
100  Datum binval;
101  bool isnull;
102 
103  binval = SPI_getbinval(*tuple, *tupdesc, vertex_columns->x, &isnull);
104  if (isnull)
105  elog(ERROR, "x contains a null value");
106  target_vertex->x = DatumGetFloat8(binval);
107 
108  binval = SPI_getbinval(*tuple, *tupdesc, vertex_columns->y, &isnull);
109  if (isnull)
110  elog(ERROR, "y contains a null value");
111  target_vertex->y = DatumGetFloat8(binval);
112 }
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 71 of file alpha.c.

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

Referenced by compute_alpha_shape().

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

Here is the caller graph for this function:

static int finish ( int  code,
int  ret 
)
static

Definition at line 52 of file alpha.c.

Referenced by compute_alpha_shape().

52  {
53  code = SPI_finish();
54  if (code != SPI_OK_FINISH) {
55  elog(ERROR, "couldn't disconnect from SPI");
56  return -1;
57  }
58  return ret;
59 }

Here is the caller graph for this function:

PG_FUNCTION_INFO_V1 ( alphashape  )