1 /*
2
3 gaia_auxtopo_table.c -- implementation of the Topology module
4 methods processing a whole GeoTable
5
6 version 5.0, 2020 August 1
7
8 Author: Sandro Furieri a.furieri@lqt.it
9
10 -----------------------------------------------------------------------------
11
12 Version: MPL 1.1/GPL 2.0/LGPL 2.1
13
14 The contents of this file are subject to the Mozilla Public License Version
15 1.1 (the "License"); you may not use this file except in compliance with
16 the License. You may obtain a copy of the License at
17 http://www.mozilla.org/MPL/
18
19 Software distributed under the License is distributed on an "AS IS" basis,
20 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
21 for the specific language governing rights and limitations under the
22 License.
23
24 The Original Code is the SpatiaLite library
25
26 The Initial Developer of the Original Code is Alessandro Furieri
27
28 Portions created by the Initial Developer are Copyright (C) 2015-2021
29 the Initial Developer. All Rights Reserved.
30
31 Contributor(s):
32
33 Alternatively, the contents of this file may be used under the terms of
34 either the GNU General Public License Version 2 or later (the "GPL"), or
35 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
36 in which case the provisions of the GPL or the LGPL are applicable instead
37 of those above. If you wish to allow use of your version of this file only
38 under the terms of either the GPL or the LGPL, and not to allow others to
39 use your version of this file under the terms of the MPL, indicate your
40 decision by deleting the provisions above and replace them with the notice
41 and other provisions required by the GPL or the LGPL. If you do not delete
42 the provisions above, a recipient may use your version of this file under
43 the terms of any one of the MPL, the GPL or the LGPL.
44
45 */
46
47 /*
48
49 CREDITS:
50
51 this module has been completely funded by:
52 Regione Toscana - Settore Sistema Informativo Territoriale ed Ambientale
53 (Topology support)
54
55 CIG: 6038019AE5
56
57 */
58
59 #include <stdlib.h>
60 #include <stdio.h>
61 #include <string.h>
62 #include <float.h>
63 #include <math.h>
64
65 #if defined(_WIN32) && !defined(__MINGW32__)
66 #include "config-msvc.h"
67 #else
68 #include "config.h"
69 #endif
70
71 #ifdef ENABLE_RTTOPO /* only if RTTOPO is enabled */
72
73 #include <spatialite/sqlite.h>
74 #include <spatialite/debug.h>
75 #include <spatialite/gaiageo.h>
76 #include <spatialite/gaia_topology.h>
77 #include <spatialite/gaia_network.h>
78 #include <spatialite/gaiaaux.h>
79
80 #include <spatialite.h>
81 #include <spatialite_private.h>
82
83 #include <librttopo.h>
84
85 #include <lwn_network.h>
86
87 #include "topology_private.h"
88 #include "network_private.h"
89
90 #ifdef _WIN32
91 #define strcasecmp _stricmp
92 #endif /* not WIN32 */
93
94 #define GAIA_UNUSED() if (argc || argv) argc = argc;
95
96 GAIATOPO_DECLARE int
gaiaTopoGeo_FromGeoTable(GaiaTopologyAccessorPtr accessor,const char * db_prefix,const char * table,const char * column,double tolerance,int line_max_points,double max_length)97 gaiaTopoGeo_FromGeoTable (GaiaTopologyAccessorPtr accessor,
98 const char *db_prefix, const char *table,
99 const char *column, double tolerance,
100 int line_max_points, double max_length)
101 {
102 /* attempting to import a whole GeoTable into a Topology-Geometry */
103 struct gaia_topology *topo = (struct gaia_topology *) accessor;
104 sqlite3_stmt *stmt = NULL;
105 int ret;
106 char *sql;
107 char *xprefix;
108 char *xtable;
109 char *xcolumn;
110 int gpkg_amphibious = 0;
111 int gpkg_mode = 0;
112
113 if (topo == NULL)
114 return 0;
115 if (topo->cache != NULL)
116 {
117 struct splite_internal_cache *cache =
118 (struct splite_internal_cache *) (topo->cache);
119 gpkg_amphibious = cache->gpkg_amphibious_mode;
120 gpkg_mode = cache->gpkg_mode;
121 }
122
123 /* building the SQL statement */
124 xprefix = gaiaDoubleQuotedSql (db_prefix);
125 xtable = gaiaDoubleQuotedSql (table);
126 xcolumn = gaiaDoubleQuotedSql (column);
127 sql =
128 sqlite3_mprintf ("SELECT \"%s\" FROM \"%s\".\"%s\"", xcolumn,
129 xprefix, xtable);
130 free (xprefix);
131 free (xtable);
132 free (xcolumn);
133 ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
134 sqlite3_free (sql);
135 if (ret != SQLITE_OK)
136 {
137 char *msg = sqlite3_mprintf ("TopoGeo_FromGeoTable error: \"%s\"",
138 sqlite3_errmsg (topo->db_handle));
139 gaiatopo_set_last_error_msg (accessor, msg);
140 sqlite3_free (msg);
141 goto error;
142 }
143
144 /* setting up the prepared statement */
145 sqlite3_reset (stmt);
146 sqlite3_clear_bindings (stmt);
147
148 while (1)
149 {
150 /* scrolling the result set rows */
151 ret = sqlite3_step (stmt);
152 if (ret == SQLITE_DONE)
153 break; /* end of result set */
154 if (ret == SQLITE_ROW)
155 {
156 if (sqlite3_column_type (stmt, 0) == SQLITE_NULL)
157 continue;
158 if (sqlite3_column_type (stmt, 0) == SQLITE_BLOB)
159 {
160 const unsigned char *blob = sqlite3_column_blob (stmt, 0);
161 int blob_sz = sqlite3_column_bytes (stmt, 0);
162 gaiaGeomCollPtr geom =
163 gaiaFromSpatiaLiteBlobWkbEx (blob, blob_sz, gpkg_mode,
164 gpkg_amphibious);
165 if (geom != NULL)
166 {
167 if (!auxtopo_insert_into_topology
168 (accessor, geom, tolerance, line_max_points,
169 max_length, GAIA_MODE_TOPO_FACE, NULL))
170 {
171 gaiaFreeGeomColl (geom);
172 goto error;
173 }
174 gaiaFreeGeomColl (geom);
175 }
176 else
177 {
178 char *msg =
179 sqlite3_mprintf
180 ("TopoGeo_FromGeoTable error: Invalid Geometry");
181 gaiatopo_set_last_error_msg (accessor, msg);
182 sqlite3_free (msg);
183 goto error;
184 }
185 }
186 else
187 {
188 char *msg =
189 sqlite3_mprintf
190 ("TopoGeo_FromGeoTable error: not a BLOB value");
191 gaiatopo_set_last_error_msg (accessor, msg);
192 sqlite3_free (msg);
193 goto error;
194 }
195 }
196 else
197 {
198 char *msg =
199 sqlite3_mprintf ("TopoGeo_FromGeoTable error: \"%s\"",
200 sqlite3_errmsg (topo->db_handle));
201 gaiatopo_set_last_error_msg (accessor, msg);
202 sqlite3_free (msg);
203 goto error;
204 }
205 }
206
207 sqlite3_finalize (stmt);
208 return 1;
209
210 error:
211 if (stmt != NULL)
212 sqlite3_finalize (stmt);
213 return 0;
214 }
215
216 GAIATOPO_DECLARE int
gaiaTopoGeo_FromGeoTableNoFace(GaiaTopologyAccessorPtr accessor,const char * db_prefix,const char * table,const char * column,double tolerance,int line_max_points,double max_length)217 gaiaTopoGeo_FromGeoTableNoFace (GaiaTopologyAccessorPtr accessor,
218 const char *db_prefix, const char *table,
219 const char *column, double tolerance,
220 int line_max_points, double max_length)
221 {
222 /* attempting to import a whole GeoTable into a Topology-Geometry
223 / without determining generated faces */
224 struct gaia_topology *topo = (struct gaia_topology *) accessor;
225 sqlite3_stmt *stmt = NULL;
226 int ret;
227 char *sql;
228 char *xprefix;
229 char *xtable;
230 char *xcolumn;
231 int gpkg_amphibious = 0;
232 int gpkg_mode = 0;
233
234 if (topo == NULL)
235 return 0;
236 if (topo->cache != NULL)
237 {
238 struct splite_internal_cache *cache =
239 (struct splite_internal_cache *) (topo->cache);
240 gpkg_amphibious = cache->gpkg_amphibious_mode;
241 gpkg_mode = cache->gpkg_mode;
242 }
243
244 /* building the SQL statement */
245 xprefix = gaiaDoubleQuotedSql (db_prefix);
246 xtable = gaiaDoubleQuotedSql (table);
247 xcolumn = gaiaDoubleQuotedSql (column);
248 sql =
249 sqlite3_mprintf ("SELECT \"%s\" FROM \"%s\".\"%s\"", xcolumn,
250 xprefix, xtable);
251 free (xprefix);
252 free (xtable);
253 free (xcolumn);
254 ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
255 sqlite3_free (sql);
256 if (ret != SQLITE_OK)
257 {
258 char *msg =
259 sqlite3_mprintf ("TopoGeo_FromGeoTableNoFace error: \"%s\"",
260 sqlite3_errmsg (topo->db_handle));
261 gaiatopo_set_last_error_msg (accessor, msg);
262 sqlite3_free (msg);
263 goto error;
264 }
265
266 /* setting up the prepared statement */
267 sqlite3_reset (stmt);
268 sqlite3_clear_bindings (stmt);
269
270 while (1)
271 {
272 /* scrolling the result set rows */
273 ret = sqlite3_step (stmt);
274 if (ret == SQLITE_DONE)
275 break; /* end of result set */
276 if (ret == SQLITE_ROW)
277 {
278 if (sqlite3_column_type (stmt, 0) == SQLITE_NULL)
279 continue;
280 if (sqlite3_column_type (stmt, 0) == SQLITE_BLOB)
281 {
282 const unsigned char *blob = sqlite3_column_blob (stmt, 0);
283 int blob_sz = sqlite3_column_bytes (stmt, 0);
284 gaiaGeomCollPtr geom =
285 gaiaFromSpatiaLiteBlobWkbEx (blob, blob_sz, gpkg_mode,
286 gpkg_amphibious);
287 if (geom != NULL)
288 {
289 if (!auxtopo_insert_into_topology
290 (accessor, geom, tolerance, line_max_points,
291 max_length, GAIA_MODE_TOPO_NO_FACE, NULL))
292 {
293 gaiaFreeGeomColl (geom);
294 goto error;
295 }
296 gaiaFreeGeomColl (geom);
297 }
298 else
299 {
300 char *msg =
301 sqlite3_mprintf
302 ("TopoGeo_FromGeoTableNoFace error: Invalid Geometry");
303 gaiatopo_set_last_error_msg (accessor, msg);
304 sqlite3_free (msg);
305 goto error;
306 }
307 }
308 else
309 {
310 char *msg =
311 sqlite3_mprintf
312 ("TopoGeo_FromGeoTableNoFace error: not a BLOB value");
313 gaiatopo_set_last_error_msg (accessor, msg);
314 sqlite3_free (msg);
315 goto error;
316 }
317 }
318 else
319 {
320 char *msg =
321 sqlite3_mprintf ("TopoGeo_FromGeoTableNoFace error: \"%s\"",
322 sqlite3_errmsg (topo->db_handle));
323 gaiatopo_set_last_error_msg (accessor, msg);
324 sqlite3_free (msg);
325 goto error;
326 }
327 }
328
329 sqlite3_finalize (stmt);
330 return 1;
331
332 error:
333 if (stmt != NULL)
334 sqlite3_finalize (stmt);
335 return 0;
336 }
337
338 static int
insert_into_dustbin(sqlite3 * sqlite,const void * cache,sqlite3_stmt * stmt_dustbin,sqlite3_int64 pk_value,const char * message,double tolerance,int * count,gaiaGeomCollPtr geom)339 insert_into_dustbin (sqlite3 * sqlite, const void *cache,
340 sqlite3_stmt * stmt_dustbin, sqlite3_int64 pk_value,
341 const char *message, double tolerance, int *count,
342 gaiaGeomCollPtr geom)
343 {
344 /* failing feature: inserting a reference into the dustbin table */
345 int ret;
346
347 start_topo_savepoint (sqlite, cache);
348 sqlite3_reset (stmt_dustbin);
349 sqlite3_clear_bindings (stmt_dustbin);
350 /* binding the Primary Key */
351 sqlite3_bind_int64 (stmt_dustbin, 1, pk_value);
352 /* binding the error message */
353 sqlite3_bind_text (stmt_dustbin, 2, message, strlen (message),
354 SQLITE_STATIC);
355 /* binding the tolerance value */
356 sqlite3_bind_double (stmt_dustbin, 3, tolerance);
357 /* binding the failing geometry */
358 if (geom == NULL)
359 sqlite3_bind_null (stmt_dustbin, 4);
360 else
361 {
362 unsigned char *blob = NULL;
363 int blob_size = 0;
364 gaiaToSpatiaLiteBlobWkb (geom, &blob, &blob_size);
365 if (blob == NULL)
366 sqlite3_bind_null (stmt_dustbin, 4);
367 else
368 sqlite3_bind_blob (stmt_dustbin, 4, blob, blob_size, free);
369 }
370 ret = sqlite3_step (stmt_dustbin);
371
372 /* inserting the row into the dustbin table */
373 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
374 {
375 release_topo_savepoint (sqlite, cache);
376 *count += 1;
377 return 1;
378 }
379
380 /* some unexpected error occurred */
381 spatialite_e ("TopoGeo_FromGeoTableExt error: \"%s\"",
382 sqlite3_errmsg (sqlite));
383 rollback_topo_savepoint (sqlite, cache);
384 return 0;
385 }
386
387 static int
do_FromGeoTableExtended_block(GaiaTopologyAccessorPtr accessor,sqlite3_stmt * stmt,sqlite3_stmt * stmt_dustbin,double tolerance,int line_max_points,double max_length,sqlite3_int64 start,sqlite3_int64 * last,sqlite3_int64 * invalid,int * dustbin_count,sqlite3_int64 * dustbin_row,int mode)388 do_FromGeoTableExtended_block (GaiaTopologyAccessorPtr accessor,
389 sqlite3_stmt * stmt, sqlite3_stmt * stmt_dustbin,
390 double tolerance, int line_max_points,
391 double max_length, sqlite3_int64 start,
392 sqlite3_int64 * last, sqlite3_int64 * invalid,
393 int *dustbin_count, sqlite3_int64 * dustbin_row,
394 int mode)
395 {
396 /* attempting to import a whole block of input features */
397 struct gaia_topology *topo = (struct gaia_topology *) accessor;
398 int ret;
399 int gpkg_amphibious = 0;
400 int gpkg_mode = 0;
401 int totcnt = 0;
402 sqlite3_int64 last_rowid;
403
404 if (topo->cache != NULL)
405 {
406 struct splite_internal_cache *cache =
407 (struct splite_internal_cache *) (topo->cache);
408 gpkg_amphibious = cache->gpkg_amphibious_mode;
409 gpkg_mode = cache->gpkg_mode;
410 }
411
412 start_topo_savepoint (topo->db_handle, topo->cache);
413
414 /* setting up the prepared statement */
415 sqlite3_reset (stmt);
416 sqlite3_clear_bindings (stmt);
417 sqlite3_bind_int64 (stmt, 1, start);
418
419 while (1)
420 {
421 /* scrolling the result set rows */
422 ret = sqlite3_step (stmt);
423 if (ret == SQLITE_DONE)
424 break; /* end of result set */
425 if (ret == SQLITE_ROW)
426 {
427 sqlite3_int64 rowid = sqlite3_column_int64 (stmt, 0);
428 int igeo = sqlite3_column_count (stmt) - 1; /* geometry always corresponds to the last resultset column */
429 if (rowid == *invalid)
430 {
431 /* succesfully recovered a previously failing block */
432 release_topo_savepoint (topo->db_handle, topo->cache);
433 *last = last_rowid;
434 return 1;
435 }
436 totcnt++;
437 if (totcnt > 256)
438 {
439 /* succesfully imported a full block */
440 release_topo_savepoint (topo->db_handle, topo->cache);
441 *last = last_rowid;
442 return 1;
443 }
444 if (sqlite3_column_type (stmt, igeo) == SQLITE_NULL)
445 {
446 last_rowid = rowid;
447 continue;
448 }
449 if (sqlite3_column_type (stmt, igeo) == SQLITE_BLOB)
450 {
451 const unsigned char *blob =
452 sqlite3_column_blob (stmt, igeo);
453 int blob_sz = sqlite3_column_bytes (stmt, igeo);
454 gaiaGeomCollPtr geom =
455 gaiaFromSpatiaLiteBlobWkbEx (blob, blob_sz, gpkg_mode,
456 gpkg_amphibious);
457 if (geom != NULL)
458 {
459 gaiaGeomCollPtr failing_geometry = NULL;
460 gaiatopo_reset_last_error_msg (accessor);
461 if (tolerance < 0.0)
462 tolerance = topo->tolerance;
463 if (!auxtopo_insert_into_topology
464 (accessor, geom, tolerance, line_max_points,
465 max_length, mode, &failing_geometry))
466 {
467 char *msg;
468 const char *rt_msg =
469 gaiaGetRtTopoErrorMsg (topo->cache);
470 if (rt_msg == NULL)
471 msg =
472 sqlite3_mprintf
473 ("TopoGeo_FromGeoTableExt exception: UNKNOWN reason");
474 else
475 msg = sqlite3_mprintf ("%s", rt_msg);
476 rollback_topo_savepoint (topo->db_handle,
477 topo->cache);
478 gaiaFreeGeomColl (geom);
479 if (tolerance < 0.0)
480 tolerance = topo->tolerance;
481 if (!insert_into_dustbin
482 (topo->db_handle, topo->cache,
483 stmt_dustbin, rowid, msg, tolerance,
484 dustbin_count, failing_geometry))
485 {
486 sqlite3_free (msg);
487 goto error;
488 }
489 sqlite3_free (msg);
490 if (failing_geometry != NULL)
491 gaiaFreeGeomColl (failing_geometry);
492 last_rowid = rowid;
493 *invalid = rowid;
494 *dustbin_row =
495 sqlite3_last_insert_rowid
496 (topo->db_handle);
497 return 0;
498 }
499 gaiaFreeGeomColl (geom);
500 if (failing_geometry != NULL)
501 gaiaFreeGeomColl (failing_geometry);
502 last_rowid = rowid;
503 }
504 else
505 {
506 rollback_topo_savepoint (topo->db_handle,
507 topo->cache);
508 if (tolerance < 0.0)
509 tolerance = topo->tolerance;
510 if (!insert_into_dustbin
511 (topo->db_handle, topo->cache, stmt_dustbin,
512 rowid,
513 "TopoGeo_FromGeoTableExt error: Invalid Geometry",
514 tolerance, dustbin_count, NULL))
515 goto error;
516 }
517 last_rowid = rowid;
518 }
519 else
520 {
521 rollback_topo_savepoint (topo->db_handle, topo->cache);
522 if (!insert_into_dustbin
523 (topo->db_handle, topo->cache, stmt_dustbin, rowid,
524 "TopoGeo_FromGeoTableExt error: not a BLOB value",
525 tolerance, dustbin_count, NULL))
526 goto error;
527 }
528 }
529 else
530 {
531 char *msg =
532 sqlite3_mprintf ("TopoGeo_FromGeoTableExt error: \"%s\"",
533 sqlite3_errmsg (topo->db_handle));
534 gaiatopo_set_last_error_msg (accessor, msg);
535 sqlite3_free (msg);
536 rollback_topo_savepoint (topo->db_handle, topo->cache);
537 goto error;
538 }
539 }
540 /* eof */
541 release_topo_savepoint (topo->db_handle, topo->cache);
542 return 2;
543
544 error:
545 return -1;
546 }
547
548 GAIATOPO_DECLARE int
gaiaTopoGeo_FromGeoTableExtended(GaiaTopologyAccessorPtr accessor,const char * sql_in,const char * sql_out,const char * sql_in2,double tolerance,int line_max_points,double max_length)549 gaiaTopoGeo_FromGeoTableExtended (GaiaTopologyAccessorPtr accessor,
550 const char *sql_in, const char *sql_out,
551 const char *sql_in2, double tolerance,
552 int line_max_points, double max_length)
553 {
554 /* attempting to import a whole GeoTable into a Topology-Geometry - Extended mode */
555 struct gaia_topology *topo = (struct gaia_topology *) accessor;
556 sqlite3_stmt *stmt = NULL;
557 sqlite3_stmt *stmt_dustbin = NULL;
558 sqlite3_stmt *stmt_retry = NULL;
559 int ret;
560 int dustbin_count = 0;
561 sqlite3_int64 start = -1;
562 sqlite3_int64 last;
563 sqlite3_int64 invalid = -1;
564 sqlite3_int64 dustbin_row = -1;
565
566 if (topo == NULL)
567 return 0;
568 if (sql_in == NULL)
569 return 0;
570 if (sql_out == NULL)
571 return 0;
572
573 /* building the SQL statement */
574 ret =
575 sqlite3_prepare_v2 (topo->db_handle, sql_in, strlen (sql_in), &stmt,
576 NULL);
577 if (ret != SQLITE_OK)
578 {
579 char *msg = sqlite3_mprintf ("TopoGeo_FromGeoTableExt error: \"%s\"",
580 sqlite3_errmsg (topo->db_handle));
581 gaiatopo_set_last_error_msg (accessor, msg);
582 sqlite3_free (msg);
583 goto error;
584 }
585
586 /* building the SQL dustbin statement */
587 ret =
588 sqlite3_prepare_v2 (topo->db_handle, sql_out, strlen (sql_out),
589 &stmt_dustbin, NULL);
590 if (ret != SQLITE_OK)
591 {
592 char *msg = sqlite3_mprintf ("TopoGeo_FromGeoTableExt error: \"%s\"",
593 sqlite3_errmsg (topo->db_handle));
594 gaiatopo_set_last_error_msg (accessor, msg);
595 sqlite3_free (msg);
596 goto error;
597 }
598
599 /* building the SQL retry statement */
600 ret =
601 sqlite3_prepare_v2 (topo->db_handle, sql_in2, strlen (sql_in2),
602 &stmt_retry, NULL);
603 if (ret != SQLITE_OK)
604 {
605 char *msg = sqlite3_mprintf ("TopoGeo_FromGeoTableExt error: \"%s\"",
606 sqlite3_errmsg (topo->db_handle));
607 gaiatopo_set_last_error_msg (accessor, msg);
608 sqlite3_free (msg);
609 goto error;
610 }
611
612 while (1)
613 {
614 /* main loop: attempting to import a block of features */
615 ret =
616 do_FromGeoTableExtended_block (accessor, stmt, stmt_dustbin,
617 tolerance, line_max_points,
618 max_length, start, &last, &invalid,
619 &dustbin_count, &dustbin_row,
620 GAIA_MODE_TOPO_FACE);
621 if (ret < 0) /* some unexpected error occurred */
622 goto error;
623 if (ret > 1)
624 {
625 /* eof */
626 break;
627 }
628 if (ret == 0)
629 {
630 /* found a failing feature; recovering */
631 ret =
632 do_FromGeoTableExtended_block (accessor, stmt, stmt_dustbin,
633 tolerance, line_max_points,
634 max_length, start, &last,
635 &invalid, &dustbin_count,
636 &dustbin_row,
637 GAIA_MODE_TOPO_FACE);
638 if (ret != 1)
639 goto error;
640 start = invalid;
641 invalid = -1;
642 dustbin_row = -1;
643 continue;
644 }
645 start = last;
646 invalid = -1;
647 dustbin_row = -1;
648 }
649
650 sqlite3_finalize (stmt);
651 sqlite3_finalize (stmt_dustbin);
652 sqlite3_finalize (stmt_retry);
653 return dustbin_count;
654
655 error:
656 if (stmt != NULL)
657 sqlite3_finalize (stmt);
658 if (stmt_dustbin != NULL)
659 sqlite3_finalize (stmt_dustbin);
660 return -1;
661 }
662
663 GAIATOPO_DECLARE int
gaiaTopoGeo_FromGeoTableNoFaceExtended(GaiaTopologyAccessorPtr accessor,const char * sql_in,const char * sql_out,const char * sql_in2,double tolerance,int line_max_points,double max_length)664 gaiaTopoGeo_FromGeoTableNoFaceExtended (GaiaTopologyAccessorPtr accessor,
665 const char *sql_in, const char *sql_out,
666 const char *sql_in2, double tolerance,
667 int line_max_points, double max_length)
668 {
669 /* attempting to import a whole GeoTable into a Topology-Geometry
670 / without determining generated faces - Extended mode */
671 struct gaia_topology *topo = (struct gaia_topology *) accessor;
672 sqlite3_stmt *stmt = NULL;
673 sqlite3_stmt *stmt_dustbin = NULL;
674 sqlite3_stmt *stmt_retry = NULL;
675 int ret;
676 int dustbin_count = 0;
677 sqlite3_int64 start = -1;
678 sqlite3_int64 last;
679 sqlite3_int64 invalid = -1;
680 sqlite3_int64 dustbin_row = -1;
681
682 if (topo == NULL)
683 return 0;
684 if (sql_in == NULL)
685 return 0;
686 if (sql_out == NULL)
687 return 0;
688
689 /* building the SQL statement */
690 ret =
691 sqlite3_prepare_v2 (topo->db_handle, sql_in, strlen (sql_in), &stmt,
692 NULL);
693 if (ret != SQLITE_OK)
694 {
695 char *msg =
696 sqlite3_mprintf ("TopoGeo_FromGeoTableNoFaceExt error: \"%s\"",
697 sqlite3_errmsg (topo->db_handle));
698 gaiatopo_set_last_error_msg (accessor, msg);
699 sqlite3_free (msg);
700 goto error;
701 }
702
703 /* building the SQL dustbin statement */
704 ret =
705 sqlite3_prepare_v2 (topo->db_handle, sql_out, strlen (sql_out),
706 &stmt_dustbin, NULL);
707 if (ret != SQLITE_OK)
708 {
709 char *msg =
710 sqlite3_mprintf ("TopoGeo_FromGeoTableNoFaceExt error: \"%s\"",
711 sqlite3_errmsg (topo->db_handle));
712 gaiatopo_set_last_error_msg (accessor, msg);
713 sqlite3_free (msg);
714 goto error;
715 }
716
717 /* building the SQL retry statement */
718 ret =
719 sqlite3_prepare_v2 (topo->db_handle, sql_in2, strlen (sql_in2),
720 &stmt_retry, NULL);
721 if (ret != SQLITE_OK)
722 {
723 char *msg =
724 sqlite3_mprintf ("TopoGeo_FromGeoTableNoFaceExt error: \"%s\"",
725 sqlite3_errmsg (topo->db_handle));
726 gaiatopo_set_last_error_msg (accessor, msg);
727 sqlite3_free (msg);
728 goto error;
729 }
730
731 while (1)
732 {
733 /* main loop: attempting to import a block of features */
734 ret =
735 do_FromGeoTableExtended_block (accessor, stmt, stmt_dustbin,
736 tolerance, line_max_points,
737 max_length, start, &last, &invalid,
738 &dustbin_count, &dustbin_row,
739 GAIA_MODE_TOPO_NO_FACE);
740 if (ret < 0) /* some unexpected error occurred */
741 goto error;
742 if (ret > 1)
743 {
744 /* eof */
745 break;
746 }
747 if (ret == 0)
748 {
749 /* found a failing feature; recovering */
750 ret =
751 do_FromGeoTableExtended_block (accessor, stmt, stmt_dustbin,
752 tolerance, line_max_points,
753 max_length, start, &last,
754 &invalid, &dustbin_count,
755 &dustbin_row,
756 GAIA_MODE_TOPO_NO_FACE);
757 if (ret != 1)
758 goto error;
759 start = invalid;
760 invalid = -1;
761 dustbin_row = -1;
762 continue;
763 }
764 start = last;
765 invalid = -1;
766 dustbin_row = -1;
767 }
768
769 sqlite3_finalize (stmt);
770 sqlite3_finalize (stmt_dustbin);
771 sqlite3_finalize (stmt_retry);
772 return dustbin_count;
773
774 error:
775 if (stmt != NULL)
776 sqlite3_finalize (stmt);
777 if (stmt_dustbin != NULL)
778 sqlite3_finalize (stmt_dustbin);
779 return -1;
780 }
781
782 GAIATOPO_DECLARE gaiaGeomCollPtr
gaiaGetEdgeSeed(GaiaTopologyAccessorPtr accessor,sqlite3_int64 edge)783 gaiaGetEdgeSeed (GaiaTopologyAccessorPtr accessor, sqlite3_int64 edge)
784 {
785 /* attempting to get a Point (seed) identifying a Topology Edge */
786 struct gaia_topology *topo = (struct gaia_topology *) accessor;
787 sqlite3_stmt *stmt = NULL;
788 int ret;
789 char *sql;
790 char *table;
791 char *xtable;
792 gaiaGeomCollPtr point = NULL;
793 if (topo == NULL)
794 return NULL;
795
796 /* building the SQL statement */
797 table = sqlite3_mprintf ("%s_edge", topo->topology_name);
798 xtable = gaiaDoubleQuotedSql (table);
799 sqlite3_free (table);
800 sql =
801 sqlite3_mprintf ("SELECT geom FROM MAIN.\"%s\" WHERE edge_id = ?",
802 xtable);
803 free (xtable);
804 ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
805 sqlite3_free (sql);
806 if (ret != SQLITE_OK)
807 {
808 char *msg = sqlite3_mprintf ("GetEdgeSeed error: \"%s\"",
809 sqlite3_errmsg (topo->db_handle));
810 gaiatopo_set_last_error_msg (accessor, msg);
811 sqlite3_free (msg);
812 goto error;
813 }
814
815 /* setting up the prepared statement */
816 sqlite3_reset (stmt);
817 sqlite3_clear_bindings (stmt);
818 sqlite3_bind_int64 (stmt, 1, edge);
819
820 while (1)
821 {
822 /* scrolling the result set rows */
823 ret = sqlite3_step (stmt);
824 if (ret == SQLITE_DONE)
825 break; /* end of result set */
826 if (ret == SQLITE_ROW)
827 {
828 if (sqlite3_column_type (stmt, 0) == SQLITE_BLOB)
829 {
830 const unsigned char *blob = sqlite3_column_blob (stmt, 0);
831 int blob_sz = sqlite3_column_bytes (stmt, 0);
832 gaiaGeomCollPtr geom =
833 gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
834 if (geom != NULL)
835 {
836 int iv;
837 double x;
838 double y;
839 double z = 0.0;
840 double m = 0.0;
841 gaiaLinestringPtr ln = geom->FirstLinestring;
842 if (ln == NULL)
843 {
844 char *msg =
845 sqlite3_mprintf
846 ("TopoGeo_GetEdgeSeed error: Invalid Geometry");
847 gaiatopo_set_last_error_msg (accessor, msg);
848 sqlite3_free (msg);
849 gaiaFreeGeomColl (geom);
850 goto error;
851 }
852 if (ln->Points == 2)
853 {
854 /*
855 // special case: if the Edge has only 2 points then
856 // the Seed will always be placed on the first point
857 */
858 iv = 0;
859 }
860 else
861 {
862 /* ordinary case: placing the Seed into the middle */
863 iv = ln->Points / 2;
864 }
865 if (ln->DimensionModel == GAIA_XY_Z)
866 {
867 gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
868 }
869 else if (ln->DimensionModel == GAIA_XY_M)
870 {
871 gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
872 }
873 else if (ln->DimensionModel == GAIA_XY_Z_M)
874 {
875 gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z,
876 &m);
877 }
878 else
879 {
880 gaiaGetPoint (ln->Coords, iv, &x, &y);
881 }
882 gaiaFreeGeomColl (geom);
883 if (topo->has_z)
884 {
885 point = gaiaAllocGeomCollXYZ ();
886 gaiaAddPointToGeomCollXYZ (point, x, y, z);
887 }
888 else
889 {
890 point = gaiaAllocGeomColl ();
891 gaiaAddPointToGeomColl (point, x, y);
892 }
893 point->Srid = topo->srid;
894 }
895 else
896 {
897 char *msg =
898 sqlite3_mprintf
899 ("TopoGeo_GetEdgeSeed error: Invalid Geometry");
900 gaiatopo_set_last_error_msg (accessor, msg);
901 sqlite3_free (msg);
902 goto error;
903 }
904 }
905 else
906 {
907 char *msg =
908 sqlite3_mprintf
909 ("TopoGeo_GetEdgeSeed error: not a BLOB value");
910 gaiatopo_set_last_error_msg (accessor, msg);
911 sqlite3_free (msg);
912 goto error;
913 }
914 }
915 else
916 {
917 char *msg =
918 sqlite3_mprintf ("TopoGeo_GetEdgeSeed error: \"%s\"",
919 sqlite3_errmsg (topo->db_handle));
920 gaiatopo_set_last_error_msg (accessor, msg);
921 sqlite3_free (msg);
922 goto error;
923 }
924 }
925
926 sqlite3_finalize (stmt);
927 return point;
928
929 error:
930 if (stmt != NULL)
931 sqlite3_finalize (stmt);
932 return NULL;
933 }
934
935 GAIATOPO_DECLARE gaiaGeomCollPtr
gaiaGetFaceSeed(GaiaTopologyAccessorPtr accessor,sqlite3_int64 face)936 gaiaGetFaceSeed (GaiaTopologyAccessorPtr accessor, sqlite3_int64 face)
937 {
938 /* attempting to get a Point (seed) identifying a Topology Face */
939 struct gaia_topology *topo = (struct gaia_topology *) accessor;
940 sqlite3_stmt *stmt = NULL;
941 int ret;
942 char *sql;
943 gaiaGeomCollPtr point = NULL;
944 if (topo == NULL)
945 return NULL;
946
947 /* building the SQL statement */
948 sql =
949 sqlite3_mprintf ("SELECT ST_PointOnSurface(ST_GetFaceGeometry(%Q, ?))",
950 topo->topology_name);
951 ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
952 sqlite3_free (sql);
953 if (ret != SQLITE_OK)
954 {
955 char *msg = sqlite3_mprintf ("GetFaceSeed error: \"%s\"",
956 sqlite3_errmsg (topo->db_handle));
957 gaiatopo_set_last_error_msg (accessor, msg);
958 sqlite3_free (msg);
959 goto error;
960 }
961
962 /* setting up the prepared statement */
963 sqlite3_reset (stmt);
964 sqlite3_clear_bindings (stmt);
965 sqlite3_bind_int64 (stmt, 1, face);
966
967 while (1)
968 {
969 /* scrolling the result set rows */
970 ret = sqlite3_step (stmt);
971 if (ret == SQLITE_DONE)
972 break; /* end of result set */
973 if (ret == SQLITE_ROW)
974 {
975 if (sqlite3_column_type (stmt, 0) == SQLITE_BLOB)
976 {
977 const unsigned char *blob = sqlite3_column_blob (stmt, 0);
978 int blob_sz = sqlite3_column_bytes (stmt, 0);
979 point = gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
980 if (point == NULL)
981 {
982 char *msg =
983 sqlite3_mprintf
984 ("TopoGeo_GetFaceSeed error: Invalid Geometry");
985 gaiatopo_set_last_error_msg (accessor, msg);
986 sqlite3_free (msg);
987 goto error;
988 }
989 }
990 else
991 {
992 char *msg =
993 sqlite3_mprintf
994 ("TopoGeo_GetFaceSeed error: not a BLOB value");
995 gaiatopo_set_last_error_msg (accessor, msg);
996 sqlite3_free (msg);
997 goto error;
998 }
999 }
1000 else
1001 {
1002 char *msg =
1003 sqlite3_mprintf ("TopoGeo_GetFaceSeed error: \"%s\"",
1004 sqlite3_errmsg (topo->db_handle));
1005 gaiatopo_set_last_error_msg (accessor, msg);
1006 sqlite3_free (msg);
1007 goto error;
1008 }
1009 }
1010
1011 sqlite3_finalize (stmt);
1012 return point;
1013
1014 error:
1015 if (stmt != NULL)
1016 sqlite3_finalize (stmt);
1017 return NULL;
1018 }
1019
1020 static int
delete_all_seeds(struct gaia_topology * topo)1021 delete_all_seeds (struct gaia_topology *topo)
1022 {
1023 /* deleting all existing Seeds */
1024 char *table;
1025 char *xtable;
1026 char *sql;
1027 char *errMsg;
1028 int ret;
1029
1030 table = sqlite3_mprintf ("%s_seeds", topo->topology_name);
1031 xtable = gaiaDoubleQuotedSql (table);
1032 sqlite3_free (table);
1033 sql = sqlite3_mprintf ("DELETE FROM MAIN.\"%s\"", xtable);
1034 free (xtable);
1035 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
1036 sqlite3_free (sql);
1037 if (ret != SQLITE_OK)
1038 {
1039 char *msg =
1040 sqlite3_mprintf ("TopoGeo_UpdateSeeds() error: \"%s\"", errMsg);
1041 sqlite3_free (errMsg);
1042 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
1043 sqlite3_free (msg);
1044 return 0;
1045 }
1046 return 1;
1047 }
1048
1049 static int
update_outdated_edge_seeds(struct gaia_topology * topo)1050 update_outdated_edge_seeds (struct gaia_topology *topo)
1051 {
1052 /* updating all outdated Edge Seeds */
1053 char *table;
1054 char *xseeds;
1055 char *xedges;
1056 char *sql;
1057 int ret;
1058 sqlite3_stmt *stmt_out;
1059 sqlite3_stmt *stmt_in;
1060
1061 /* preparing the UPDATE statement */
1062 table = sqlite3_mprintf ("%s_seeds", topo->topology_name);
1063 xseeds = gaiaDoubleQuotedSql (table);
1064 sqlite3_free (table);
1065 sql = sqlite3_mprintf ("UPDATE MAIN.\"%s\" SET geom = "
1066 "TopoGeo_GetEdgeSeed(%Q, edge_id) WHERE edge_id = ?",
1067 xseeds, topo->topology_name);
1068 free (xseeds);
1069 ret =
1070 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_out,
1071 NULL);
1072 sqlite3_free (sql);
1073 if (ret != SQLITE_OK)
1074 {
1075 char *msg = sqlite3_mprintf ("TopoGeo_UpdateSeeds() error: \"%s\"",
1076 sqlite3_errmsg (topo->db_handle));
1077 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
1078 sqlite3_free (msg);
1079 goto error;
1080 }
1081
1082 /* preparing the SELECT statement */
1083 table = sqlite3_mprintf ("%s_seeds", topo->topology_name);
1084 xseeds = gaiaDoubleQuotedSql (table);
1085 sqlite3_free (table);
1086 table = sqlite3_mprintf ("%s_edge", topo->topology_name);
1087 xedges = gaiaDoubleQuotedSql (table);
1088 sqlite3_free (table);
1089 sql = sqlite3_mprintf ("SELECT s.edge_id FROM MAIN.\"%s\" AS s "
1090 "JOIN MAIN.\"%s\" AS e ON (e.edge_id = s.edge_id) "
1091 "WHERE s.edge_id IS NOT NULL AND e.timestamp > s.timestamp",
1092 xseeds, xedges);
1093 free (xseeds);
1094 free (xedges);
1095 ret =
1096 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
1097 sqlite3_free (sql);
1098 if (ret != SQLITE_OK)
1099 {
1100 char *msg = sqlite3_mprintf ("TopoGeo_UpdateSeeds() error: \"%s\"",
1101 sqlite3_errmsg (topo->db_handle));
1102 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
1103 sqlite3_free (msg);
1104 goto error;
1105 }
1106
1107 sqlite3_reset (stmt_in);
1108 sqlite3_clear_bindings (stmt_in);
1109 while (1)
1110 {
1111 /* scrolling the result set rows */
1112 ret = sqlite3_step (stmt_in);
1113 if (ret == SQLITE_DONE)
1114 break; /* end of result set */
1115 if (ret == SQLITE_ROW)
1116 {
1117 sqlite3_reset (stmt_out);
1118 sqlite3_clear_bindings (stmt_out);
1119 sqlite3_bind_int64 (stmt_out, 1,
1120 sqlite3_column_int64 (stmt_in, 0));
1121 /* updating the Seeds table */
1122 ret = sqlite3_step (stmt_out);
1123 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
1124 ;
1125 else
1126 {
1127 char *msg =
1128 sqlite3_mprintf
1129 ("TopoGeo_UpdateSeeds() error: \"%s\"",
1130 sqlite3_errmsg (topo->db_handle));
1131 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr)
1132 topo, msg);
1133 sqlite3_free (msg);
1134 goto error;
1135 }
1136 }
1137 else
1138 {
1139 char *msg =
1140 sqlite3_mprintf ("TopoGeo_UpdateSeeds() error: \"%s\"",
1141 sqlite3_errmsg (topo->db_handle));
1142 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
1143 msg);
1144 sqlite3_free (msg);
1145 goto error;
1146 }
1147 }
1148
1149 sqlite3_finalize (stmt_in);
1150 sqlite3_finalize (stmt_out);
1151 return 1;
1152
1153 error:
1154 if (stmt_in != NULL)
1155 sqlite3_finalize (stmt_in);
1156 if (stmt_out != NULL)
1157 sqlite3_finalize (stmt_out);
1158 return 0;
1159 }
1160
1161 static int
update_outdated_face_seeds(struct gaia_topology * topo)1162 update_outdated_face_seeds (struct gaia_topology *topo)
1163 {
1164 /* updating all outdated Face Seeds */
1165 char *table;
1166 char *xseeds;
1167 char *xedges;
1168 char *xfaces;
1169 char *sql;
1170 int ret;
1171 sqlite3_stmt *stmt_out;
1172 sqlite3_stmt *stmt_in;
1173
1174 /* preparing the UPDATE statement */
1175 table = sqlite3_mprintf ("%s_seeds", topo->topology_name);
1176 xseeds = gaiaDoubleQuotedSql (table);
1177 sqlite3_free (table);
1178 sql = sqlite3_mprintf ("UPDATE MAIN.\"%s\" SET geom = "
1179 "TopoGeo_GetFaceSeed(%Q, face_id) WHERE face_id = ?",
1180 xseeds, topo->topology_name);
1181 free (xseeds);
1182 ret =
1183 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_out,
1184 NULL);
1185 sqlite3_free (sql);
1186 if (ret != SQLITE_OK)
1187 {
1188 char *msg = sqlite3_mprintf ("TopoGeo_UpdateSeeds() error: \"%s\"",
1189 sqlite3_errmsg (topo->db_handle));
1190 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
1191 sqlite3_free (msg);
1192 goto error;
1193 }
1194
1195 /* preparing the SELECT statement */
1196 table = sqlite3_mprintf ("%s_seeds", topo->topology_name);
1197 xseeds = gaiaDoubleQuotedSql (table);
1198 sqlite3_free (table);
1199 table = sqlite3_mprintf ("%s_edge", topo->topology_name);
1200 xedges = gaiaDoubleQuotedSql (table);
1201 sqlite3_free (table);
1202 table = sqlite3_mprintf ("%s_face", topo->topology_name);
1203 xfaces = gaiaDoubleQuotedSql (table);
1204 sqlite3_free (table);
1205 sql = sqlite3_mprintf ("SELECT x.face_id FROM MAIN.\"%s\" AS s, "
1206 "(SELECT f.face_id AS face_id, Max(e.timestamp) AS max_tm "
1207 "FROM MAIN.\"%s\" AS f "
1208 "JOIN MAIN.\"%s\" AS e ON (e.left_face = f.face_id OR e.right_face = f.face_id) "
1209 "GROUP BY f.face_id) AS x "
1210 "WHERE s.face_id IS NOT NULL AND s.face_id = x.face_id AND x.max_tm > s.timestamp",
1211 xseeds, xfaces, xedges);
1212 free (xseeds);
1213 free (xedges);
1214 free (xfaces);
1215 ret =
1216 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
1217 sqlite3_free (sql);
1218 if (ret != SQLITE_OK)
1219 {
1220 char *msg = sqlite3_mprintf ("TopoGeo_UpdateSeeds() error: \"%s\"",
1221 sqlite3_errmsg (topo->db_handle));
1222 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
1223 sqlite3_free (msg);
1224 goto error;
1225 }
1226
1227 sqlite3_reset (stmt_in);
1228 sqlite3_clear_bindings (stmt_in);
1229 while (1)
1230 {
1231 /* scrolling the result set rows */
1232 ret = sqlite3_step (stmt_in);
1233 if (ret == SQLITE_DONE)
1234 break; /* end of result set */
1235 if (ret == SQLITE_ROW)
1236 {
1237 sqlite3_reset (stmt_out);
1238 sqlite3_clear_bindings (stmt_out);
1239 sqlite3_bind_int64 (stmt_out, 1,
1240 sqlite3_column_int64 (stmt_in, 0));
1241 /* updating the Seeds table */
1242 ret = sqlite3_step (stmt_out);
1243 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
1244 ;
1245 else
1246 {
1247 char *msg =
1248 sqlite3_mprintf
1249 ("TopoGeo_UpdateSeeds() error: \"%s\"",
1250 sqlite3_errmsg (topo->db_handle));
1251 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr)
1252 topo, msg);
1253 sqlite3_free (msg);
1254 goto error;
1255 }
1256 }
1257 else
1258 {
1259 char *msg =
1260 sqlite3_mprintf ("TopoGeo_UpdateSeeds() error: \"%s\"",
1261 sqlite3_errmsg (topo->db_handle));
1262 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
1263 msg);
1264 sqlite3_free (msg);
1265 goto error;
1266 }
1267 }
1268
1269 sqlite3_finalize (stmt_in);
1270 sqlite3_finalize (stmt_out);
1271 return 1;
1272
1273 error:
1274 if (stmt_in != NULL)
1275 sqlite3_finalize (stmt_in);
1276 if (stmt_out != NULL)
1277 sqlite3_finalize (stmt_out);
1278 return 0;
1279 }
1280
1281 GAIATOPO_DECLARE int
gaiaTopoGeoUpdateSeeds(GaiaTopologyAccessorPtr accessor,int incremental_mode)1282 gaiaTopoGeoUpdateSeeds (GaiaTopologyAccessorPtr accessor, int incremental_mode)
1283 {
1284 /* updating all TopoGeo Seeds */
1285 char *table;
1286 char *xseeds;
1287 char *xedges;
1288 char *xfaces;
1289 char *sql;
1290 char *errMsg;
1291 int ret;
1292 struct gaia_topology *topo = (struct gaia_topology *) accessor;
1293 if (topo == NULL)
1294 return 0;
1295
1296 if (!incremental_mode)
1297 {
1298 /* deleting all existing Seeds */
1299 if (!delete_all_seeds (topo))
1300 return 0;
1301 }
1302
1303 /* paranoid precaution: deleting all orphan Edge Seeds */
1304 table = sqlite3_mprintf ("%s_seeds", topo->topology_name);
1305 xseeds = gaiaDoubleQuotedSql (table);
1306 sqlite3_free (table);
1307 table = sqlite3_mprintf ("%s_edge", topo->topology_name);
1308 xedges = gaiaDoubleQuotedSql (table);
1309 sqlite3_free (table);
1310 sql = sqlite3_mprintf ("DELETE FROM MAIN.\"%s\" WHERE edge_id IN ("
1311 "SELECT s.edge_id FROM MAIN.\"%s\" AS s "
1312 "LEFT JOIN MAIN.\"%s\" AS e ON (s.edge_id = e.edge_id) "
1313 "WHERE s.edge_id IS NOT NULL AND e.edge_id IS NULL)",
1314 xseeds, xseeds, xedges);
1315 free (xseeds);
1316 free (xedges);
1317 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
1318 sqlite3_free (sql);
1319 if (ret != SQLITE_OK)
1320 {
1321 char *msg =
1322 sqlite3_mprintf ("TopoGeo_UpdateSeeds() error: \"%s\"", errMsg);
1323 sqlite3_free (errMsg);
1324 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
1325 sqlite3_free (msg);
1326 return 0;
1327 }
1328
1329 /* paranoid precaution: deleting all orphan Face Seeds */
1330 table = sqlite3_mprintf ("%s_seeds", topo->topology_name);
1331 xseeds = gaiaDoubleQuotedSql (table);
1332 sqlite3_free (table);
1333 table = sqlite3_mprintf ("%s_face", topo->topology_name);
1334 xfaces = gaiaDoubleQuotedSql (table);
1335 sqlite3_free (table);
1336 sql = sqlite3_mprintf ("DELETE FROM MAIN.\"%s\" WHERE face_id IN ("
1337 "SELECT s.face_id FROM MAIN.\"%s\" AS s "
1338 "LEFT JOIN MAIN.\"%s\" AS f ON (s.face_id = f.face_id) "
1339 "WHERE s.face_id IS NOT NULL AND f.face_id IS NULL)",
1340 xseeds, xseeds, xfaces);
1341 free (xseeds);
1342 free (xfaces);
1343 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
1344 sqlite3_free (sql);
1345 if (ret != SQLITE_OK)
1346 {
1347 char *msg =
1348 sqlite3_mprintf ("TopoGeo_UpdateSeeds() error: \"%s\"", errMsg);
1349 sqlite3_free (errMsg);
1350 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
1351 sqlite3_free (msg);
1352 return 0;
1353 }
1354
1355 /* updating all outdated Edge Seeds */
1356 if (!update_outdated_edge_seeds (topo))
1357 return 0;
1358
1359 /* updating all outdated Facee Seeds */
1360 if (!update_outdated_face_seeds (topo))
1361 return 0;
1362
1363 /* inserting all missing Edge Seeds */
1364 table = sqlite3_mprintf ("%s_seeds", topo->topology_name);
1365 xseeds = gaiaDoubleQuotedSql (table);
1366 sqlite3_free (table);
1367 table = sqlite3_mprintf ("%s_edge", topo->topology_name);
1368 xedges = gaiaDoubleQuotedSql (table);
1369 sqlite3_free (table);
1370 sql =
1371 sqlite3_mprintf
1372 ("INSERT INTO MAIN.\"%s\" (seed_id, edge_id, face_id, geom) "
1373 "SELECT NULL, e.edge_id, NULL, TopoGeo_GetEdgeSeed(%Q, e.edge_id) "
1374 "FROM MAIN.\"%s\" AS e "
1375 "LEFT JOIN MAIN.\"%s\" AS s ON (e.edge_id = s.edge_id) WHERE s.edge_id IS NULL",
1376 xseeds, topo->topology_name, xedges, xseeds);
1377 free (xseeds);
1378 free (xedges);
1379 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
1380 sqlite3_free (sql);
1381 if (ret != SQLITE_OK)
1382 {
1383 char *msg =
1384 sqlite3_mprintf ("TopoGeo_UpdateSeeds() error: \"%s\"", errMsg);
1385 sqlite3_free (errMsg);
1386 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
1387 sqlite3_free (msg);
1388 return 0;
1389 }
1390
1391 /* inserting all missing Face Seeds */
1392 table = sqlite3_mprintf ("%s_seeds", topo->topology_name);
1393 xseeds = gaiaDoubleQuotedSql (table);
1394 sqlite3_free (table);
1395 table = sqlite3_mprintf ("%s_face", topo->topology_name);
1396 xfaces = gaiaDoubleQuotedSql (table);
1397 sqlite3_free (table);
1398 sql =
1399 sqlite3_mprintf
1400 ("INSERT INTO MAIN.\"%s\" (seed_id, edge_id, face_id, geom) "
1401 "SELECT NULL, NULL, f.face_id, TopoGeo_GetFaceSeed(%Q, f.face_id) "
1402 "FROM MAIN.\"%s\" AS f "
1403 "LEFT JOIN MAIN.\"%s\" AS s ON (f.face_id = s.face_id) "
1404 "WHERE s.face_id IS NULL AND f.face_id <> 0", xseeds,
1405 topo->topology_name, xfaces, xseeds);
1406 free (xseeds);
1407 free (xfaces);
1408 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
1409 sqlite3_free (sql);
1410 if (ret != SQLITE_OK)
1411 {
1412 char *msg =
1413 sqlite3_mprintf ("TopoGeo_UpdateSeeds() error: \"%s\"", errMsg);
1414 sqlite3_free (errMsg);
1415 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
1416 sqlite3_free (msg);
1417 return 0;
1418 }
1419
1420 return 1;
1421 }
1422
1423 GAIATOPO_DECLARE gaiaGeomCollPtr
gaiaTopoGeoSnapPointToSeed(GaiaTopologyAccessorPtr accessor,gaiaGeomCollPtr pt,double distance)1424 gaiaTopoGeoSnapPointToSeed (GaiaTopologyAccessorPtr accessor,
1425 gaiaGeomCollPtr pt, double distance)
1426 {
1427 /* snapping a Point to TopoSeeds */
1428 char *sql;
1429 char *table;
1430 char *xtable;
1431 sqlite3_stmt *stmt = NULL;
1432 sqlite3_stmt *stmt_snap = NULL;
1433 int ret;
1434 unsigned char *blob;
1435 int blob_size;
1436 unsigned char *blob2;
1437 int blob_size2;
1438 gaiaGeomCollPtr result = NULL;
1439 struct gaia_topology *topo = (struct gaia_topology *) accessor;
1440 if (topo == NULL)
1441 return NULL;
1442
1443 /* preparing the Snap statement */
1444 sql = "SELECT ST_Snap(?, ?, ?)";
1445 ret =
1446 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_snap,
1447 NULL);
1448 if (ret != SQLITE_OK)
1449 {
1450 char *msg =
1451 sqlite3_mprintf ("TopoGeo_SnapPointToSeed() error: \"%s\"",
1452 sqlite3_errmsg (topo->db_handle));
1453 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
1454 sqlite3_free (msg);
1455 goto error;
1456 }
1457
1458 /* preparing the SELECT statement */
1459 table = sqlite3_mprintf ("%s_node", topo->topology_name);
1460 xtable = gaiaDoubleQuotedSql (table);
1461 sql = sqlite3_mprintf ("SELECT geom "
1462 "FROM \"%s\" WHERE ST_Distance(?, geom) <= ? AND rowid IN "
1463 "(SELECT rowid FROM SpatialIndex WHERE f_table_name = %Q AND search_frame = ST_Buffer(?, ?))",
1464 xtable, table);
1465 free (xtable);
1466 sqlite3_free (table);
1467 ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
1468 sqlite3_free (sql);
1469 if (ret != SQLITE_OK)
1470 {
1471 char *msg =
1472 sqlite3_mprintf ("TopoGeo_SnapPointToSeed() error: \"%s\"",
1473 sqlite3_errmsg (topo->db_handle));
1474 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
1475 sqlite3_free (msg);
1476 goto error;
1477 }
1478
1479 /* querying Seeds */
1480 if (topo->has_z)
1481 result = gaiaAllocGeomCollXYZ ();
1482 else
1483 result = gaiaAllocGeomColl ();
1484 result->Srid = pt->Srid;
1485 gaiaToSpatiaLiteBlobWkb (pt, &blob, &blob_size);
1486 gaiaToSpatiaLiteBlobWkb (pt, &blob2, &blob_size2);
1487 sqlite3_reset (stmt);
1488 sqlite3_clear_bindings (stmt);
1489 sqlite3_bind_blob (stmt, 1, blob, blob_size, free);
1490 sqlite3_bind_double (stmt, 2, distance);
1491 sqlite3_bind_blob (stmt, 3, blob2, blob_size2, free);
1492 sqlite3_bind_double (stmt, 4, distance * 1.2);
1493 while (1)
1494 {
1495 /* scrolling the result set rows */
1496 ret = sqlite3_step (stmt);
1497 if (ret == SQLITE_DONE)
1498 break; /* end of result set */
1499 if (ret == SQLITE_ROW)
1500 {
1501 const unsigned char *p_blob = sqlite3_column_blob (stmt, 0);
1502 int blobsz = sqlite3_column_bytes (stmt, 0);
1503 gaiaGeomCollPtr geom =
1504 gaiaFromSpatiaLiteBlobWkb (p_blob, blobsz);
1505 if (geom != NULL)
1506 {
1507 gaiaPointPtr pt = geom->FirstPoint;
1508 while (pt != NULL)
1509 {
1510 /* copying all Points into the result Geometry */
1511 if (topo->has_z)
1512 gaiaAddPointToGeomCollXYZ (result, pt->X, pt->Y,
1513 pt->Z);
1514 else
1515 gaiaAddPointToGeomColl (result, pt->X, pt->Y);
1516 pt = pt->Next;
1517 }
1518 gaiaFreeGeomColl (geom);
1519 }
1520 }
1521 else
1522 {
1523 char *msg =
1524 sqlite3_mprintf ("TopoGeo_SnapPointToSeed error: \"%s\"",
1525 sqlite3_errmsg (topo->db_handle));
1526 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
1527 msg);
1528 sqlite3_free (msg);
1529 goto error;
1530 }
1531 }
1532
1533 sqlite3_finalize (stmt);
1534 stmt = NULL;
1535 if (result->FirstPoint == NULL)
1536 goto error;
1537
1538 /* Snap */
1539 gaiaToSpatiaLiteBlobWkb (pt, &blob, &blob_size);
1540 gaiaToSpatiaLiteBlobWkb (result, &blob2, &blob_size2);
1541 gaiaFreeGeomColl (result);
1542 result = NULL;
1543 sqlite3_reset (stmt_snap);
1544 sqlite3_clear_bindings (stmt_snap);
1545 sqlite3_bind_blob (stmt_snap, 1, blob, blob_size, free);
1546 sqlite3_bind_blob (stmt_snap, 2, blob2, blob_size2, free);
1547 sqlite3_bind_double (stmt_snap, 3, distance);
1548 while (1)
1549 {
1550 /* scrolling the result set rows */
1551 ret = sqlite3_step (stmt_snap);
1552
1553 if (ret == SQLITE_DONE)
1554 break; /* end of result set */
1555 if (ret == SQLITE_ROW)
1556 {
1557 if (sqlite3_column_type (stmt_snap, 0) != SQLITE_NULL)
1558 {
1559 const unsigned char *p_blob =
1560 sqlite3_column_blob (stmt_snap, 0);
1561 int blobsz = sqlite3_column_bytes (stmt_snap, 0);
1562 if (result != NULL)
1563 gaiaFreeGeomColl (result);
1564 result = gaiaFromSpatiaLiteBlobWkb (p_blob, blobsz);
1565 }
1566 }
1567 else
1568 {
1569 char *msg =
1570 sqlite3_mprintf ("TopoGeo_SnapPointToSeed error: \"%s\"",
1571 sqlite3_errmsg (topo->db_handle));
1572 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
1573 msg);
1574 sqlite3_free (msg);
1575 goto error;
1576 }
1577 }
1578 sqlite3_finalize (stmt_snap);
1579 stmt_snap = NULL;
1580 if (result == NULL)
1581 goto error;
1582 if (result->FirstLinestring != NULL || result->FirstPolygon != NULL)
1583 goto error;
1584 if (result->FirstPoint == NULL)
1585 goto error;
1586 if (result->FirstPoint != result->LastPoint)
1587 goto error;
1588 return result;
1589
1590 error:
1591 if (stmt != NULL)
1592 sqlite3_finalize (stmt);
1593 if (stmt_snap != NULL)
1594 sqlite3_finalize (stmt_snap);
1595 if (result != NULL)
1596 gaiaFreeGeomColl (result);
1597 return NULL;
1598 }
1599
1600 GAIATOPO_DECLARE gaiaGeomCollPtr
gaiaTopoGeoSnapLinestringToSeed(GaiaTopologyAccessorPtr accessor,gaiaGeomCollPtr ln,double distance)1601 gaiaTopoGeoSnapLinestringToSeed (GaiaTopologyAccessorPtr accessor,
1602 gaiaGeomCollPtr ln, double distance)
1603 {
1604 /* snapping a Linestring to TopoSeeds */
1605 char *sql;
1606 char *table;
1607 char *xtable;
1608 int ret;
1609 unsigned char *blob;
1610 int blob_size;
1611 unsigned char *blob2;
1612 int blob_size2;
1613 gaiaGeomCollPtr result = NULL;
1614 sqlite3_stmt *stmt = NULL;
1615 sqlite3_stmt *stmt_snap = NULL;
1616 struct gaia_topology *topo = (struct gaia_topology *) accessor;
1617 if (topo == NULL)
1618 return NULL;
1619
1620 /* preparing the Snap statement */
1621 sql = "SELECT ST_Snap(?, ?, ?)";
1622 ret =
1623 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_snap,
1624 NULL);
1625 if (ret != SQLITE_OK)
1626 {
1627 char *msg =
1628 sqlite3_mprintf ("TopoGeo_SnapLinestringToSeed() error: \"%s\"",
1629 sqlite3_errmsg (topo->db_handle));
1630 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
1631 sqlite3_free (msg);
1632 goto error;
1633 }
1634
1635 /* preparing the SELECT statement */
1636 table = sqlite3_mprintf ("%s_seeds", topo->topology_name);
1637 xtable = gaiaDoubleQuotedSql (table);
1638 sql = sqlite3_mprintf ("SELECT edge_id, geom "
1639 "FROM \"%s\" WHERE ST_Distance(?, geom) <= ? AND rowid IN "
1640 "(SELECT rowid FROM SpatialIndex WHERE f_table_name = %Q AND search_frame = ST_Buffer(?, ?))",
1641 xtable, table);
1642 free (xtable);
1643 sqlite3_free (table);
1644 ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
1645 sqlite3_free (sql);
1646 if (ret != SQLITE_OK)
1647 {
1648 char *msg =
1649 sqlite3_mprintf ("TopoGeo_SnapLinestringToSeed() error: \"%s\"",
1650 sqlite3_errmsg (topo->db_handle));
1651 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
1652 sqlite3_free (msg);
1653 goto error;
1654 }
1655
1656 /* querying Seeds */
1657 if (topo->has_z)
1658 result = gaiaAllocGeomCollXYZ ();
1659 else
1660 result = gaiaAllocGeomColl ();
1661 result->Srid = ln->Srid;
1662 gaiaToSpatiaLiteBlobWkb (ln, &blob, &blob_size);
1663 gaiaToSpatiaLiteBlobWkb (ln, &blob2, &blob_size2);
1664 sqlite3_reset (stmt);
1665 sqlite3_clear_bindings (stmt);
1666 sqlite3_bind_blob (stmt, 1, blob, blob_size, free);
1667 sqlite3_bind_double (stmt, 2, distance);
1668 sqlite3_bind_blob (stmt, 3, blob2, blob_size2, free);
1669 sqlite3_bind_double (stmt, 4, distance * 1.2);
1670 while (1)
1671 {
1672 /* scrolling the result set rows */
1673 ret = sqlite3_step (stmt);
1674 if (ret == SQLITE_DONE)
1675 break; /* end of result set */
1676 if (ret == SQLITE_ROW)
1677 {
1678 if (sqlite3_column_type (stmt, 0) != SQLITE_NULL)
1679 {
1680 const unsigned char *p_blob =
1681 sqlite3_column_blob (stmt, 1);
1682 int blobsz = sqlite3_column_bytes (stmt, 1);
1683 gaiaGeomCollPtr geom =
1684 gaiaFromSpatiaLiteBlobWkb (p_blob, blobsz);
1685 if (geom != NULL)
1686 {
1687 gaiaPointPtr pt = geom->FirstPoint;
1688 while (pt != NULL)
1689 {
1690 /* copying all Points into the result Geometry */
1691 if (topo->has_z)
1692 gaiaAddPointToGeomCollXYZ (result, pt->X,
1693 pt->Y, pt->Z);
1694 else
1695 gaiaAddPointToGeomColl (result, pt->X,
1696 pt->Y);
1697 pt = pt->Next;
1698 }
1699 gaiaFreeGeomColl (geom);
1700 }
1701 }
1702 }
1703 else
1704 {
1705 char *msg =
1706 sqlite3_mprintf
1707 ("TopoGeo_SnapLinestringToSeed error: \"%s\"",
1708 sqlite3_errmsg (topo->db_handle));
1709 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
1710 msg);
1711 sqlite3_free (msg);
1712 goto error;
1713 }
1714 }
1715
1716 sqlite3_finalize (stmt);
1717 stmt = NULL;
1718 if (result->FirstPoint == NULL)
1719 goto error;
1720
1721 /* Snap */
1722 gaiaToSpatiaLiteBlobWkb (ln, &blob, &blob_size);
1723 gaiaToSpatiaLiteBlobWkb (result, &blob2, &blob_size2);
1724 gaiaFreeGeomColl (result);
1725 result = NULL;
1726 sqlite3_reset (stmt_snap);
1727 sqlite3_clear_bindings (stmt_snap);
1728 sqlite3_bind_blob (stmt_snap, 1, blob, blob_size, free);
1729 sqlite3_bind_blob (stmt_snap, 2, blob2, blob_size2, free);
1730 sqlite3_bind_double (stmt_snap, 3, distance);
1731 while (1)
1732 {
1733 /* scrolling the result set rows */
1734 ret = sqlite3_step (stmt_snap);
1735 if (ret == SQLITE_DONE)
1736 break; /* end of result set */
1737 if (ret == SQLITE_ROW)
1738 {
1739 if (sqlite3_column_type (stmt_snap, 0) == SQLITE_BLOB)
1740 {
1741 const unsigned char *p_blob =
1742 sqlite3_column_blob (stmt_snap, 0);
1743 int blobsz = sqlite3_column_bytes (stmt_snap, 0);
1744 if (result != NULL)
1745 gaiaFreeGeomColl (result);
1746 result = gaiaFromSpatiaLiteBlobWkb (p_blob, blobsz);
1747 }
1748 }
1749 else
1750 {
1751 char *msg =
1752 sqlite3_mprintf
1753 ("TopoGeo_SnapLinestringToSeed error: \"%s\"",
1754 sqlite3_errmsg (topo->db_handle));
1755 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
1756 msg);
1757 sqlite3_free (msg);
1758 goto error;
1759 }
1760 }
1761 sqlite3_finalize (stmt_snap);
1762 stmt_snap = NULL;
1763 if (result == NULL)
1764 goto error;
1765 if (result->FirstPoint != NULL || result->FirstPolygon != NULL)
1766 goto error;
1767 if (result->FirstLinestring == NULL)
1768 goto error;
1769 if (result->FirstLinestring != result->LastLinestring)
1770 goto error;
1771 return result;
1772
1773 error:
1774 if (stmt != NULL)
1775 sqlite3_finalize (stmt);
1776 if (stmt_snap != NULL)
1777 sqlite3_finalize (stmt_snap);
1778 if (result != NULL)
1779 gaiaFreeGeomColl (result);
1780 return NULL;
1781 }
1782
1783 static gaiaGeomCollPtr
make_geom_from_polyg(int srid,gaiaPolygonPtr pg)1784 make_geom_from_polyg (int srid, gaiaPolygonPtr pg)
1785 {
1786 /* quick constructor: Geometry based on external polyg */
1787 gaiaGeomCollPtr reference;
1788 if (pg->DimensionModel == GAIA_XY_Z_M)
1789 reference = gaiaAllocGeomCollXYZM ();
1790 else if (pg->DimensionModel == GAIA_XY_Z)
1791 reference = gaiaAllocGeomCollXYZ ();
1792 else if (pg->DimensionModel == GAIA_XY_M)
1793 reference = gaiaAllocGeomCollXYM ();
1794 else
1795 reference = gaiaAllocGeomColl ();
1796 reference->Srid = srid;
1797 pg->Next = NULL;
1798 reference->FirstPolygon = pg;
1799 reference->LastPolygon = pg;
1800 return reference;
1801 }
1802
1803 static void
do_eval_topogeo_point(struct gaia_topology * topo,gaiaGeomCollPtr result,gaiaGeomCollPtr reference,sqlite3_stmt * stmt_node)1804 do_eval_topogeo_point (struct gaia_topology *topo, gaiaGeomCollPtr result,
1805 gaiaGeomCollPtr reference, sqlite3_stmt * stmt_node)
1806 {
1807 /* retrieving Points from Topology */
1808 int ret;
1809 unsigned char *p_blob;
1810 int n_bytes;
1811
1812 /* initializing the Topo-Node query */
1813 gaiaToSpatiaLiteBlobWkb (reference, &p_blob, &n_bytes);
1814 sqlite3_reset (stmt_node);
1815 sqlite3_clear_bindings (stmt_node);
1816 sqlite3_bind_blob (stmt_node, 1, p_blob, n_bytes, SQLITE_TRANSIENT);
1817 sqlite3_bind_blob (stmt_node, 2, p_blob, n_bytes, SQLITE_TRANSIENT);
1818 free (p_blob);
1819
1820 while (1)
1821 {
1822 /* scrolling the result set rows */
1823 ret = sqlite3_step (stmt_node);
1824 if (ret == SQLITE_DONE)
1825 break; /* end of result set */
1826 if (ret == SQLITE_ROW)
1827 {
1828 const unsigned char *blob = sqlite3_column_blob (stmt_node, 0);
1829 int blob_sz = sqlite3_column_bytes (stmt_node, 0);
1830 gaiaGeomCollPtr geom =
1831 gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
1832 if (geom != NULL)
1833 {
1834 gaiaPointPtr pt = geom->FirstPoint;
1835 while (pt != NULL)
1836 {
1837 /* copying all Points into the result Geometry */
1838 if (topo->has_z)
1839 gaiaAddPointToGeomCollXYZ (result, pt->X, pt->Y,
1840 pt->Z);
1841 else
1842 gaiaAddPointToGeomColl (result, pt->X, pt->Y);
1843 pt = pt->Next;
1844 }
1845 gaiaFreeGeomColl (geom);
1846 }
1847 }
1848 else
1849 {
1850 char *msg = sqlite3_mprintf ("TopoGeo_ToGeoTable error: \"%s\"",
1851 sqlite3_errmsg (topo->db_handle));
1852 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
1853 msg);
1854 sqlite3_free (msg);
1855 return;
1856 }
1857 }
1858 }
1859
1860 static void
do_collect_topo_edges(struct gaia_topology * topo,gaiaGeomCollPtr sparse,sqlite3_stmt * stmt_edge,sqlite3_int64 edge_id)1861 do_collect_topo_edges (struct gaia_topology *topo, gaiaGeomCollPtr sparse,
1862 sqlite3_stmt * stmt_edge, sqlite3_int64 edge_id)
1863 {
1864 /* collecting Edge Geometries one by one */
1865 int ret;
1866
1867 /* initializing the Topo-Edge query */
1868 sqlite3_reset (stmt_edge);
1869 sqlite3_clear_bindings (stmt_edge);
1870 sqlite3_bind_int64 (stmt_edge, 1, edge_id);
1871
1872 while (1)
1873 {
1874 /* scrolling the result set rows */
1875 ret = sqlite3_step (stmt_edge);
1876 if (ret == SQLITE_DONE)
1877 break; /* end of result set */
1878 if (ret == SQLITE_ROW)
1879 {
1880 const unsigned char *blob = sqlite3_column_blob (stmt_edge, 0);
1881 int blob_sz = sqlite3_column_bytes (stmt_edge, 0);
1882 gaiaGeomCollPtr geom =
1883 gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
1884 if (geom != NULL)
1885 {
1886 gaiaLinestringPtr ln = geom->FirstLinestring;
1887 while (ln != NULL)
1888 {
1889 if (topo->has_z)
1890 auxtopo_copy_linestring3d (ln, sparse);
1891 else
1892 auxtopo_copy_linestring (ln, sparse);
1893 ln = ln->Next;
1894 }
1895 gaiaFreeGeomColl (geom);
1896 }
1897 }
1898 else
1899 {
1900 char *msg = sqlite3_mprintf ("TopoGeo_ToGeoTable error: \"%s\"",
1901 sqlite3_errmsg (topo->db_handle));
1902 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
1903 msg);
1904 sqlite3_free (msg);
1905 return;
1906 }
1907 }
1908 }
1909
1910 static void
do_eval_topogeo_line(struct gaia_topology * topo,gaiaGeomCollPtr result,gaiaGeomCollPtr reference,sqlite3_stmt * stmt_seed_edge,sqlite3_stmt * stmt_edge)1911 do_eval_topogeo_line (struct gaia_topology *topo, gaiaGeomCollPtr result,
1912 gaiaGeomCollPtr reference, sqlite3_stmt * stmt_seed_edge,
1913 sqlite3_stmt * stmt_edge)
1914 {
1915 /* retrieving Linestrings from Topology */
1916 int ret;
1917 unsigned char *p_blob;
1918 int n_bytes;
1919 gaiaGeomCollPtr sparse;
1920 gaiaGeomCollPtr rearranged;
1921 gaiaLinestringPtr ln;
1922
1923 if (topo->has_z)
1924 sparse = gaiaAllocGeomCollXYZ ();
1925 else
1926 sparse = gaiaAllocGeomColl ();
1927 sparse->Srid = topo->srid;
1928
1929 /* initializing the Topo-Seed-Edge query */
1930 gaiaToSpatiaLiteBlobWkb (reference, &p_blob, &n_bytes);
1931 sqlite3_reset (stmt_seed_edge);
1932 sqlite3_clear_bindings (stmt_seed_edge);
1933 sqlite3_bind_blob (stmt_seed_edge, 1, p_blob, n_bytes, SQLITE_TRANSIENT);
1934 sqlite3_bind_blob (stmt_seed_edge, 2, p_blob, n_bytes, SQLITE_TRANSIENT);
1935 free (p_blob);
1936
1937 while (1)
1938 {
1939 /* scrolling the result set rows */
1940 ret = sqlite3_step (stmt_seed_edge);
1941 if (ret == SQLITE_DONE)
1942 break; /* end of result set */
1943 if (ret == SQLITE_ROW)
1944 {
1945 sqlite3_int64 edge_id =
1946 sqlite3_column_int64 (stmt_seed_edge, 0);
1947 do_collect_topo_edges (topo, sparse, stmt_edge, edge_id);
1948 }
1949 else
1950 {
1951 char *msg = sqlite3_mprintf ("TopoGeo_ToGeoTable error: \"%s\"",
1952 sqlite3_errmsg (topo->db_handle));
1953 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
1954 msg);
1955 sqlite3_free (msg);
1956 gaiaFreeGeomColl (sparse);
1957 return;
1958 }
1959 }
1960
1961 /* attempting to rearrange sparse lines */
1962 rearranged = gaiaLineMerge_r (topo->cache, sparse);
1963 gaiaFreeGeomColl (sparse);
1964 if (rearranged == NULL)
1965 return;
1966 ln = rearranged->FirstLinestring;
1967 while (ln != NULL)
1968 {
1969 if (topo->has_z)
1970 auxtopo_copy_linestring3d (ln, result);
1971 else
1972 auxtopo_copy_linestring (ln, result);
1973 ln = ln->Next;
1974 }
1975 gaiaFreeGeomColl (rearranged);
1976 }
1977
1978 static void
do_explode_topo_face(struct gaia_topology * topo,struct face_edges * list,sqlite3_stmt * stmt_face,sqlite3_int64 face_id)1979 do_explode_topo_face (struct gaia_topology *topo, struct face_edges *list,
1980 sqlite3_stmt * stmt_face, sqlite3_int64 face_id)
1981 {
1982 /* exploding all Edges required by the same face */
1983 int ret;
1984
1985 /* initializing the Topo-Face query */
1986 sqlite3_reset (stmt_face);
1987 sqlite3_clear_bindings (stmt_face);
1988 sqlite3_bind_int64 (stmt_face, 1, face_id);
1989 sqlite3_bind_int64 (stmt_face, 2, face_id);
1990
1991 while (1)
1992 {
1993 /* scrolling the result set rows */
1994 ret = sqlite3_step (stmt_face);
1995 if (ret == SQLITE_DONE)
1996 break; /* end of result set */
1997 if (ret == SQLITE_ROW)
1998 {
1999 sqlite3_int64 edge_id = sqlite3_column_int64 (stmt_face, 0);
2000 sqlite3_int64 left_face = sqlite3_column_int64 (stmt_face, 1);
2001 sqlite3_int64 right_face = sqlite3_column_int64 (stmt_face, 2);
2002 const unsigned char *blob = sqlite3_column_blob (stmt_face, 3);
2003 int blob_sz = sqlite3_column_bytes (stmt_face, 3);
2004 gaiaGeomCollPtr geom =
2005 gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
2006 if (geom != NULL)
2007 auxtopo_add_face_edge (list, face_id, edge_id, left_face,
2008 right_face, geom);
2009 }
2010 else
2011 {
2012 char *msg = sqlite3_mprintf ("TopoGeo_ToGeoTable error: \"%s\"",
2013 sqlite3_errmsg (topo->db_handle));
2014 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
2015 msg);
2016 sqlite3_free (msg);
2017 return;
2018 }
2019 }
2020 }
2021
2022 static void
do_copy_ring3d(gaiaRingPtr in,gaiaRingPtr out)2023 do_copy_ring3d (gaiaRingPtr in, gaiaRingPtr out)
2024 {
2025 /* inserting/copying a Ring 3D into another Ring */
2026 int iv;
2027 double x;
2028 double y;
2029 double z;
2030 for (iv = 0; iv < in->Points; iv++)
2031 {
2032 gaiaGetPointXYZ (in->Coords, iv, &x, &y, &z);
2033 gaiaSetPointXYZ (out->Coords, iv, x, y, z);
2034 }
2035 }
2036
2037 static void
do_copy_ring(gaiaRingPtr in,gaiaRingPtr out)2038 do_copy_ring (gaiaRingPtr in, gaiaRingPtr out)
2039 {
2040 /* inserting/copying a Ring into another Ring */
2041 int iv;
2042 double x;
2043 double y;
2044 for (iv = 0; iv < in->Points; iv++)
2045 {
2046 gaiaGetPoint (in->Coords, iv, &x, &y);
2047 gaiaSetPoint (out->Coords, iv, x, y);
2048 }
2049 }
2050
2051 static void
do_copy_polygon3d(gaiaPolygonPtr in,gaiaGeomCollPtr geom)2052 do_copy_polygon3d (gaiaPolygonPtr in, gaiaGeomCollPtr geom)
2053 {
2054 /* inserting/copying a Polygon 3D into another Geometry */
2055 int ib;
2056 gaiaRingPtr rng_out;
2057 gaiaRingPtr rng_in = in->Exterior;
2058 gaiaPolygonPtr out =
2059 gaiaAddPolygonToGeomColl (geom, rng_in->Points, in->NumInteriors);
2060 rng_out = out->Exterior;
2061 do_copy_ring3d (rng_in, rng_out);
2062 for (ib = 0; ib < in->NumInteriors; ib++)
2063 {
2064 rng_in = in->Interiors + ib;
2065 rng_out = gaiaAddInteriorRing (out, ib, rng_in->Points);
2066 do_copy_ring3d (rng_in, rng_out);
2067 }
2068 }
2069
2070 static void
do_copy_polygon(gaiaPolygonPtr in,gaiaGeomCollPtr geom)2071 do_copy_polygon (gaiaPolygonPtr in, gaiaGeomCollPtr geom)
2072 {
2073 /* inserting/copying a Polygon into another Geometry */
2074 int ib;
2075 gaiaRingPtr rng_out;
2076 gaiaRingPtr rng_in = in->Exterior;
2077 gaiaPolygonPtr out =
2078 gaiaAddPolygonToGeomColl (geom, rng_in->Points, in->NumInteriors);
2079 rng_out = out->Exterior;
2080 do_copy_ring (rng_in, rng_out);
2081 for (ib = 0; ib < in->NumInteriors; ib++)
2082 {
2083 rng_in = in->Interiors + ib;
2084 rng_out = gaiaAddInteriorRing (out, ib, rng_in->Points);
2085 do_copy_ring (rng_in, rng_out);
2086 }
2087 }
2088
2089 static void
do_copy_filter_polygon3d(gaiaPolygonPtr in,gaiaGeomCollPtr geom,const void * cache,double tolerance)2090 do_copy_filter_polygon3d (gaiaPolygonPtr in, gaiaGeomCollPtr geom,
2091 const void *cache, double tolerance)
2092 {
2093 /* inserting/copying a Polygon 3D into another Geometry (with tolerance) */
2094 int ib;
2095 gaiaGeomCollPtr polyg;
2096 gaiaPolygonPtr pg;
2097 gaiaRingPtr rng_out;
2098 gaiaRingPtr rng_in = in->Exterior;
2099 gaiaPolygonPtr out;
2100 double area;
2101 int ret;
2102 int numints = 0;
2103
2104 polyg = gaiaAllocGeomCollXYZ ();
2105 pg = gaiaAddPolygonToGeomColl (polyg, rng_in->Points, 0);
2106 rng_out = pg->Exterior;
2107 do_copy_ring3d (rng_in, rng_out);
2108 ret = gaiaGeomCollArea_r (cache, polyg, &area);
2109 gaiaFreeGeomColl (polyg);
2110 if (!ret)
2111 return;
2112 if ((tolerance * tolerance) > area)
2113 return; /* skipping smaller polygons */
2114
2115 for (ib = 0; ib < in->NumInteriors; ib++)
2116 {
2117 /* counting how many interior rings do we really have */
2118 rng_in = in->Interiors + ib;
2119 polyg = gaiaAllocGeomCollXYZ ();
2120 pg = gaiaAddPolygonToGeomColl (polyg, rng_in->Points, 0);
2121 rng_out = pg->Exterior;
2122 do_copy_ring3d (rng_in, rng_out);
2123 ret = gaiaGeomCollArea_r (cache, polyg, &area);
2124 gaiaFreeGeomColl (polyg);
2125 if (!ret)
2126 continue;
2127 if ((tolerance * tolerance) > area)
2128 continue; /* skipping smaller holes */
2129 numints++;
2130 }
2131
2132 rng_in = in->Exterior;
2133 out = gaiaAddPolygonToGeomColl (geom, rng_in->Points, numints);
2134 rng_out = out->Exterior;
2135 do_copy_ring3d (rng_in, rng_out);
2136 numints = 0;
2137 for (ib = 0; ib < in->NumInteriors; ib++)
2138 {
2139 /* copying interior rings */
2140 rng_in = in->Interiors + ib;
2141 polyg = gaiaAllocGeomCollXYZ ();
2142 pg = gaiaAddPolygonToGeomColl (polyg, rng_in->Points, 0);
2143 rng_out = pg->Exterior;
2144 do_copy_ring3d (rng_in, rng_out);
2145 ret = gaiaGeomCollArea_r (cache, polyg, &area);
2146 gaiaFreeGeomColl (polyg);
2147 if (!ret)
2148 continue;
2149 if ((tolerance * tolerance) > area)
2150 continue; /* skipping smaller holes */
2151 rng_out = gaiaAddInteriorRing (out, numints++, rng_in->Points);
2152 do_copy_ring3d (rng_in, rng_out);
2153 }
2154 }
2155
2156 static void
do_copy_filter_polygon(gaiaPolygonPtr in,gaiaGeomCollPtr geom,const void * cache,double tolerance)2157 do_copy_filter_polygon (gaiaPolygonPtr in, gaiaGeomCollPtr geom,
2158 const void *cache, double tolerance)
2159 {
2160 /* inserting/copying a Polygon into another Geometry (with tolerance) */
2161 int ib;
2162 gaiaGeomCollPtr polyg;
2163 gaiaPolygonPtr pg;
2164 gaiaRingPtr rng_out;
2165 gaiaRingPtr rng_in = in->Exterior;
2166 gaiaPolygonPtr out;
2167 double area;
2168 int ret;
2169 int numints = 0;
2170
2171 polyg = gaiaAllocGeomColl ();
2172 pg = gaiaAddPolygonToGeomColl (polyg, rng_in->Points, 0);
2173 rng_out = pg->Exterior;
2174 do_copy_ring (rng_in, rng_out);
2175 ret = gaiaGeomCollArea_r (cache, polyg, &area);
2176 gaiaFreeGeomColl (polyg);
2177 if (!ret)
2178 return;
2179 if ((tolerance * tolerance) > area)
2180 return; /* skipping smaller polygons */
2181
2182 for (ib = 0; ib < in->NumInteriors; ib++)
2183 {
2184 /* counting how many interior rings do we really have */
2185 rng_in = in->Interiors + ib;
2186 polyg = gaiaAllocGeomColl ();
2187 pg = gaiaAddPolygonToGeomColl (polyg, rng_in->Points, 0);
2188 rng_out = pg->Exterior;
2189 do_copy_ring (rng_in, rng_out);
2190 ret = gaiaGeomCollArea_r (cache, polyg, &area);
2191 gaiaFreeGeomColl (polyg);
2192 if (!ret)
2193 continue;
2194 if ((tolerance * tolerance) > area)
2195 continue; /* skipping smaller holes */
2196 numints++;
2197 }
2198
2199 rng_in = in->Exterior;
2200 out = gaiaAddPolygonToGeomColl (geom, rng_in->Points, numints);
2201 rng_out = out->Exterior;
2202 do_copy_ring (rng_in, rng_out);
2203 numints = 0;
2204 for (ib = 0; ib < in->NumInteriors; ib++)
2205 {
2206 /* copying interior rings */
2207 rng_in = in->Interiors + ib;
2208 polyg = gaiaAllocGeomColl ();
2209 pg = gaiaAddPolygonToGeomColl (polyg, rng_in->Points, 0);
2210 rng_out = pg->Exterior;
2211 do_copy_ring (rng_in, rng_out);
2212 ret = gaiaGeomCollArea_r (cache, polyg, &area);
2213 gaiaFreeGeomColl (polyg);
2214 if (!ret)
2215 continue;
2216 if ((tolerance * tolerance) > area)
2217 continue; /* skipping smaller holes */
2218 rng_out = gaiaAddInteriorRing (out, numints++, rng_in->Points);
2219 do_copy_ring (rng_in, rng_out);
2220 }
2221 }
2222
2223 static void
do_eval_topo_polyg(struct gaia_topology * topo,gaiaGeomCollPtr result,gaiaGeomCollPtr reference,sqlite3_stmt * stmt_seed_face,sqlite3_stmt * stmt_face)2224 do_eval_topo_polyg (struct gaia_topology *topo, gaiaGeomCollPtr result,
2225 gaiaGeomCollPtr reference, sqlite3_stmt * stmt_seed_face,
2226 sqlite3_stmt * stmt_face)
2227 {
2228 /* retrieving Polygons from Topology */
2229 int ret;
2230 unsigned char *p_blob;
2231 int n_bytes;
2232 gaiaGeomCollPtr rearranged;
2233 gaiaPolygonPtr pg;
2234 struct face_edges *list =
2235 auxtopo_create_face_edges (topo->has_z, topo->srid);
2236
2237 /* initializing the Topo-Seed-Face query */
2238 gaiaToSpatiaLiteBlobWkb (reference, &p_blob, &n_bytes);
2239 sqlite3_reset (stmt_seed_face);
2240 sqlite3_clear_bindings (stmt_seed_face);
2241 sqlite3_bind_blob (stmt_seed_face, 1, p_blob, n_bytes, SQLITE_TRANSIENT);
2242 sqlite3_bind_blob (stmt_seed_face, 2, p_blob, n_bytes, SQLITE_TRANSIENT);
2243 free (p_blob);
2244
2245 while (1)
2246 {
2247 /* scrolling the result set rows */
2248 ret = sqlite3_step (stmt_seed_face);
2249 if (ret == SQLITE_DONE)
2250 break; /* end of result set */
2251 if (ret == SQLITE_ROW)
2252 {
2253 sqlite3_int64 face_id =
2254 sqlite3_column_int64 (stmt_seed_face, 0);
2255 do_explode_topo_face (topo, list, stmt_face, face_id);
2256 }
2257 else
2258 {
2259 char *msg = sqlite3_mprintf ("TopoGeo_ToGeoTable error: \"%s\"",
2260 sqlite3_errmsg (topo->db_handle));
2261 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
2262 msg);
2263 sqlite3_free (msg);
2264 auxtopo_free_face_edges (list);
2265 return;
2266 }
2267 }
2268
2269 /* attempting to rearrange sparse lines into Polygons */
2270 auxtopo_select_valid_face_edges (list);
2271 rearranged = auxtopo_polygonize_face_edges (list, topo->cache);
2272 auxtopo_free_face_edges (list);
2273 if (rearranged == NULL)
2274 return;
2275 pg = rearranged->FirstPolygon;
2276 while (pg != NULL)
2277 {
2278 if (topo->has_z)
2279 do_copy_polygon3d (pg, result);
2280 else
2281 do_copy_polygon (pg, result);
2282 pg = pg->Next;
2283 }
2284 gaiaFreeGeomColl (rearranged);
2285 }
2286
2287 static void
do_eval_topo_polyg_generalize(struct gaia_topology * topo,gaiaGeomCollPtr result,gaiaGeomCollPtr reference,sqlite3_stmt * stmt_seed_face,sqlite3_stmt * stmt_face,double tolerance)2288 do_eval_topo_polyg_generalize (struct gaia_topology *topo,
2289 gaiaGeomCollPtr result,
2290 gaiaGeomCollPtr reference,
2291 sqlite3_stmt * stmt_seed_face,
2292 sqlite3_stmt * stmt_face, double tolerance)
2293 {
2294 /* retrieving Polygons from Topology */
2295 int ret;
2296 unsigned char *p_blob;
2297 int n_bytes;
2298 gaiaGeomCollPtr rearranged;
2299 gaiaPolygonPtr pg;
2300 struct face_edges *list =
2301 auxtopo_create_face_edges (topo->has_z, topo->srid);
2302
2303 /* initializing the Topo-Seed-Face query */
2304 gaiaToSpatiaLiteBlobWkb (reference, &p_blob, &n_bytes);
2305 sqlite3_reset (stmt_seed_face);
2306 sqlite3_clear_bindings (stmt_seed_face);
2307 sqlite3_bind_blob (stmt_seed_face, 1, p_blob, n_bytes, SQLITE_TRANSIENT);
2308 sqlite3_bind_blob (stmt_seed_face, 2, p_blob, n_bytes, SQLITE_TRANSIENT);
2309 free (p_blob);
2310
2311 while (1)
2312 {
2313 /* scrolling the result set rows */
2314 ret = sqlite3_step (stmt_seed_face);
2315 if (ret == SQLITE_DONE)
2316 break; /* end of result set */
2317 if (ret == SQLITE_ROW)
2318 {
2319 sqlite3_int64 face_id =
2320 sqlite3_column_int64 (stmt_seed_face, 0);
2321 do_explode_topo_face (topo, list, stmt_face, face_id);
2322 }
2323 else
2324 {
2325 char *msg = sqlite3_mprintf ("TopoGeo_ToGeoTable error: \"%s\"",
2326 sqlite3_errmsg (topo->db_handle));
2327 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
2328 msg);
2329 sqlite3_free (msg);
2330 auxtopo_free_face_edges (list);
2331 return;
2332 }
2333 }
2334
2335 /* attempting to rearrange sparse lines into Polygons */
2336 auxtopo_select_valid_face_edges (list);
2337 rearranged = auxtopo_polygonize_face_edges_generalize (list, topo->cache);
2338 auxtopo_free_face_edges (list);
2339 if (rearranged == NULL)
2340 return;
2341 pg = rearranged->FirstPolygon;
2342 while (pg != NULL)
2343 {
2344 if (topo->has_z)
2345 do_copy_filter_polygon3d (pg, result, topo->cache, tolerance);
2346 else
2347 do_copy_filter_polygon (pg, result, topo->cache, tolerance);
2348 pg = pg->Next;
2349 }
2350 gaiaFreeGeomColl (rearranged);
2351 }
2352
2353 static gaiaGeomCollPtr
do_eval_topogeo_geom(struct gaia_topology * topo,gaiaGeomCollPtr geom,sqlite3_stmt * stmt_seed_edge,sqlite3_stmt * stmt_seed_face,sqlite3_stmt * stmt_node,sqlite3_stmt * stmt_edge,sqlite3_stmt * stmt_face,int out_type,double tolerance)2354 do_eval_topogeo_geom (struct gaia_topology *topo, gaiaGeomCollPtr geom,
2355 sqlite3_stmt * stmt_seed_edge,
2356 sqlite3_stmt * stmt_seed_face, sqlite3_stmt * stmt_node,
2357 sqlite3_stmt * stmt_edge, sqlite3_stmt * stmt_face,
2358 int out_type, double tolerance)
2359 {
2360 /* retrieving Topology-Geometry geometries via matching Seeds */
2361 gaiaGeomCollPtr result;
2362
2363 if (topo->has_z)
2364 result = gaiaAllocGeomCollXYZ ();
2365 else
2366 result = gaiaAllocGeomColl ();
2367 result->Srid = topo->srid;
2368 result->DeclaredType = out_type;
2369
2370 if (out_type == GAIA_POINT || out_type == GAIA_MULTIPOINT
2371 || out_type == GAIA_GEOMETRYCOLLECTION || out_type == GAIA_UNKNOWN)
2372 {
2373 /* processing all Points */
2374 gaiaPointPtr pt = geom->FirstPoint;
2375 while (pt != NULL)
2376 {
2377 gaiaPointPtr next = pt->Next;
2378 gaiaGeomCollPtr reference = (gaiaGeomCollPtr)
2379 auxtopo_make_geom_from_point (topo->srid, topo->has_z, pt);
2380 do_eval_topogeo_point (topo, result, reference, stmt_node);
2381 auxtopo_destroy_geom_from (reference);
2382 pt->Next = next;
2383 pt = pt->Next;
2384 }
2385 }
2386
2387 if (out_type == GAIA_MULTILINESTRING || out_type == GAIA_GEOMETRYCOLLECTION
2388 || out_type == GAIA_UNKNOWN)
2389 {
2390 /* processing all Linestrings */
2391 gaiaLinestringPtr ln = geom->FirstLinestring;
2392 while (ln != NULL)
2393 {
2394 gaiaLinestringPtr next = ln->Next;
2395 gaiaGeomCollPtr reference = (gaiaGeomCollPtr)
2396 auxtopo_make_geom_from_line (topo->srid, ln);
2397 do_eval_topogeo_line (topo, result, reference, stmt_seed_edge,
2398 stmt_edge);
2399 auxtopo_destroy_geom_from (reference);
2400 ln->Next = next;
2401 ln = ln->Next;
2402 }
2403 }
2404
2405 if (out_type == GAIA_MULTIPOLYGON || out_type == GAIA_GEOMETRYCOLLECTION
2406 || out_type == GAIA_UNKNOWN)
2407 {
2408 /* processing all Polygons */
2409 gaiaPolygonPtr pg = geom->FirstPolygon;
2410 while (pg != NULL)
2411 {
2412 gaiaPolygonPtr next = pg->Next;
2413 gaiaGeomCollPtr reference =
2414 make_geom_from_polyg (topo->srid, pg);
2415 if (tolerance > 0.0)
2416 do_eval_topo_polyg_generalize (topo, result, reference,
2417 stmt_seed_face, stmt_face,
2418 tolerance);
2419 else
2420 do_eval_topo_polyg (topo, result, reference, stmt_seed_face,
2421 stmt_face);
2422 auxtopo_destroy_geom_from (reference);
2423 pg->Next = next;
2424 pg = pg->Next;
2425 }
2426 }
2427
2428 if (result->FirstPoint == NULL && result->FirstLinestring == NULL
2429 && result->FirstPolygon == NULL)
2430 goto error;
2431 return result;
2432
2433 error:
2434 gaiaFreeGeomColl (result);
2435 return NULL;
2436 }
2437
2438 static int
do_eval_topogeo_seeds(struct gaia_topology * topo,sqlite3_stmt * stmt_ref,int ref_geom_col,sqlite3_stmt * stmt_ins,sqlite3_stmt * stmt_seed_edge,sqlite3_stmt * stmt_seed_face,sqlite3_stmt * stmt_node,sqlite3_stmt * stmt_edge,sqlite3_stmt * stmt_face,int out_type,double tolerance)2439 do_eval_topogeo_seeds (struct gaia_topology *topo, sqlite3_stmt * stmt_ref,
2440 int ref_geom_col, sqlite3_stmt * stmt_ins,
2441 sqlite3_stmt * stmt_seed_edge,
2442 sqlite3_stmt * stmt_seed_face, sqlite3_stmt * stmt_node,
2443 sqlite3_stmt * stmt_edge, sqlite3_stmt * stmt_face,
2444 int out_type, double tolerance)
2445 {
2446 /* querying the ref-table */
2447 int ret;
2448
2449 sqlite3_reset (stmt_ref);
2450 sqlite3_clear_bindings (stmt_ref);
2451 while (1)
2452 {
2453 /* scrolling the result set rows */
2454 ret = sqlite3_step (stmt_ref);
2455 if (ret == SQLITE_DONE)
2456 break; /* end of result set */
2457 if (ret == SQLITE_ROW)
2458 {
2459 int icol;
2460 int ncol = sqlite3_column_count (stmt_ref);
2461 sqlite3_reset (stmt_ins);
2462 sqlite3_clear_bindings (stmt_ins);
2463 for (icol = 0; icol < ncol; icol++)
2464 {
2465 int col_type = sqlite3_column_type (stmt_ref, icol);
2466 if (icol == ref_geom_col)
2467 {
2468 /* the geometry column */
2469 const unsigned char *blob =
2470 sqlite3_column_blob (stmt_ref, icol);
2471 int blob_sz = sqlite3_column_bytes (stmt_ref, icol);
2472 gaiaGeomCollPtr geom =
2473 gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
2474 if (geom != NULL)
2475 {
2476 gaiaGeomCollPtr result;
2477 unsigned char *p_blob;
2478 int n_bytes;
2479 int gpkg_mode = 0;
2480 int tiny_point = 0;
2481 if (topo->cache != NULL)
2482 {
2483 struct splite_internal_cache *cache =
2484 (struct splite_internal_cache
2485 *) (topo->cache);
2486 gpkg_mode = cache->gpkg_mode;
2487 tiny_point = cache->tinyPointEnabled;
2488 }
2489 result = do_eval_topogeo_geom (topo, geom,
2490 stmt_seed_edge,
2491 stmt_seed_face,
2492 stmt_node,
2493 stmt_edge,
2494 stmt_face,
2495 out_type,
2496 tolerance);
2497 gaiaFreeGeomColl (geom);
2498 if (result != NULL)
2499 {
2500 gaiaToSpatiaLiteBlobWkbEx2 (result,
2501 &p_blob,
2502 &n_bytes,
2503 gpkg_mode,
2504 tiny_point);
2505 gaiaFreeGeomColl (result);
2506 sqlite3_bind_blob (stmt_ins, icol + 1,
2507 p_blob, n_bytes,
2508 free);
2509 }
2510 else
2511 sqlite3_bind_null (stmt_ins, icol + 1);
2512 }
2513 else
2514 sqlite3_bind_null (stmt_ins, icol + 1);
2515 continue;
2516 }
2517 switch (col_type)
2518 {
2519 case SQLITE_INTEGER:
2520 sqlite3_bind_int64 (stmt_ins, icol + 1,
2521 sqlite3_column_int64 (stmt_ref,
2522 icol));
2523 break;
2524 case SQLITE_FLOAT:
2525 sqlite3_bind_double (stmt_ins, icol + 1,
2526 sqlite3_column_double
2527 (stmt_ref, icol));
2528 break;
2529 case SQLITE_TEXT:
2530 sqlite3_bind_text (stmt_ins, icol + 1,
2531 (const char *)
2532 sqlite3_column_text (stmt_ref,
2533 icol),
2534 sqlite3_column_bytes (stmt_ref,
2535 icol),
2536 SQLITE_STATIC);
2537 break;
2538 case SQLITE_BLOB:
2539 sqlite3_bind_blob (stmt_ins, icol + 1,
2540 sqlite3_column_blob (stmt_ref,
2541 icol),
2542 sqlite3_column_bytes (stmt_ref,
2543 icol),
2544 SQLITE_STATIC);
2545 break;
2546 default:
2547 sqlite3_bind_null (stmt_ins, icol + 1);
2548 break;
2549 };
2550 }
2551 ret = sqlite3_step (stmt_ins);
2552 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
2553 ;
2554 else
2555 {
2556 char *msg =
2557 sqlite3_mprintf ("TopoGeo_ToGeoTable() error: \"%s\"",
2558 sqlite3_errmsg (topo->db_handle));
2559 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr)
2560 topo, msg);
2561 sqlite3_free (msg);
2562 return 0;
2563 }
2564 }
2565 else
2566 {
2567 char *msg =
2568 sqlite3_mprintf ("TopoGeo_ToGeoTable() error: \"%s\"",
2569 sqlite3_errmsg (topo->db_handle));
2570 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
2571 msg);
2572 sqlite3_free (msg);
2573 return 0;
2574 }
2575 }
2576 return 1;
2577 }
2578
2579 GAIATOPO_DECLARE int
gaiaTopoGeo_ToGeoTableGeneralize(GaiaTopologyAccessorPtr accessor,const char * db_prefix,const char * ref_table,const char * ref_column,const char * out_table,double tolerance,int with_spatial_index)2580 gaiaTopoGeo_ToGeoTableGeneralize (GaiaTopologyAccessorPtr accessor,
2581 const char *db_prefix, const char *ref_table,
2582 const char *ref_column, const char *out_table,
2583 double tolerance, int with_spatial_index)
2584 {
2585 /*
2586 / attempting to create and populate a new GeoTable out from a Topology-Geometry
2587 / (simplified/generalized form)
2588 */
2589 struct gaia_topology *topo = (struct gaia_topology *) accessor;
2590 sqlite3_stmt *stmt_ref = NULL;
2591 sqlite3_stmt *stmt_ins = NULL;
2592 sqlite3_stmt *stmt_seed_edge = NULL;
2593 sqlite3_stmt *stmt_seed_face = NULL;
2594 sqlite3_stmt *stmt_node = NULL;
2595 sqlite3_stmt *stmt_edge = NULL;
2596 sqlite3_stmt *stmt_face = NULL;
2597 int ret;
2598 char *create;
2599 char *select;
2600 char *insert;
2601 char *sql;
2602 char *errMsg;
2603 char *xprefix;
2604 char *xtable;
2605 int ref_type;
2606 const char *type;
2607 int out_type;
2608 int ref_geom_col;
2609 if (topo == NULL)
2610 return 0;
2611
2612 /* incrementally updating all Topology Seeds */
2613 if (!gaiaTopoGeoUpdateSeeds (accessor, 1))
2614 return 0;
2615
2616 /* composing the CREATE TABLE output-table statement */
2617 if (!auxtopo_create_togeotable_sql
2618 (topo->db_handle, db_prefix, ref_table, ref_column, out_table, &create,
2619 &select, &insert, &ref_geom_col))
2620 goto error;
2621
2622 /* creating the output-table */
2623 ret = sqlite3_exec (topo->db_handle, create, NULL, NULL, &errMsg);
2624 sqlite3_free (create);
2625 create = NULL;
2626 if (ret != SQLITE_OK)
2627 {
2628 char *msg =
2629 sqlite3_mprintf ("TopoGeo_ToGeoTableGeneralize() error: \"%s\"",
2630 errMsg);
2631 sqlite3_free (errMsg);
2632 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
2633 sqlite3_free (msg);
2634 goto error;
2635 }
2636
2637 /* checking the Geometry Type */
2638 if (!auxtopo_retrieve_geometry_type
2639 (topo->db_handle, db_prefix, ref_table, ref_column, &ref_type))
2640 goto error;
2641 switch (ref_type)
2642 {
2643 case GAIA_POINT:
2644 case GAIA_POINTZ:
2645 case GAIA_POINTM:
2646 case GAIA_POINTZM:
2647 type = "POINT";
2648 out_type = GAIA_POINT;
2649 break;
2650 case GAIA_MULTIPOINT:
2651 case GAIA_MULTIPOINTZ:
2652 case GAIA_MULTIPOINTM:
2653 case GAIA_MULTIPOINTZM:
2654 type = "MULTIPOINT";
2655 out_type = GAIA_MULTIPOINT;
2656 break;
2657 case GAIA_LINESTRING:
2658 case GAIA_LINESTRINGZ:
2659 case GAIA_LINESTRINGM:
2660 case GAIA_LINESTRINGZM:
2661 case GAIA_MULTILINESTRING:
2662 case GAIA_MULTILINESTRINGZ:
2663 case GAIA_MULTILINESTRINGM:
2664 case GAIA_MULTILINESTRINGZM:
2665 type = "MULTILINESTRING";
2666 out_type = GAIA_MULTILINESTRING;
2667 break;
2668 case GAIA_POLYGON:
2669 case GAIA_POLYGONZ:
2670 case GAIA_POLYGONM:
2671 case GAIA_POLYGONZM:
2672 case GAIA_MULTIPOLYGON:
2673 case GAIA_MULTIPOLYGONZ:
2674 case GAIA_MULTIPOLYGONM:
2675 case GAIA_MULTIPOLYGONZM:
2676 type = "MULTIPOLYGON";
2677 out_type = GAIA_MULTIPOLYGON;
2678 break;
2679 case GAIA_GEOMETRYCOLLECTION:
2680 case GAIA_GEOMETRYCOLLECTIONZ:
2681 case GAIA_GEOMETRYCOLLECTIONM:
2682 case GAIA_GEOMETRYCOLLECTIONZM:
2683 type = "GEOMETRYCOLLECTION";
2684 out_type = GAIA_GEOMETRYCOLLECTION;
2685 break;
2686 default:
2687 type = "GEOMETRY";
2688 out_type = GAIA_UNKNOWN;
2689 break;
2690 };
2691
2692 /* creating the output Geometry Column */
2693 sql =
2694 sqlite3_mprintf
2695 ("SELECT AddGeometryColumn(Lower(%Q), Lower(%Q), %d, '%s', '%s')",
2696 out_table, ref_column, topo->srid, type,
2697 (topo->has_z == 0) ? "XY" : "XYZ");
2698 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
2699 sqlite3_free (sql);
2700 if (ret != SQLITE_OK)
2701 {
2702 char *msg =
2703 sqlite3_mprintf ("TopoGeo_ToGeoTableGeneralize() error: \"%s\"",
2704 errMsg);
2705 sqlite3_free (errMsg);
2706 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
2707 sqlite3_free (msg);
2708 goto error;
2709 }
2710
2711 if (with_spatial_index)
2712 {
2713 /* adding a Spatial Index supporting the Geometry Column */
2714 sql =
2715 sqlite3_mprintf
2716 ("SELECT CreateSpatialIndex(Lower(%Q), Lower(%Q))",
2717 out_table, ref_column);
2718 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
2719 sqlite3_free (sql);
2720 if (ret != SQLITE_OK)
2721 {
2722 char *msg =
2723 sqlite3_mprintf
2724 ("TopoGeo_ToGeoTableGeneralize() error: \"%s\"",
2725 errMsg);
2726 sqlite3_free (errMsg);
2727 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
2728 msg);
2729 sqlite3_free (msg);
2730 goto error;
2731 }
2732 }
2733
2734 /* preparing the "SELECT * FROM ref-table" query */
2735 ret =
2736 sqlite3_prepare_v2 (topo->db_handle, select, strlen (select), &stmt_ref,
2737 NULL);
2738 sqlite3_free (select);
2739 select = NULL;
2740 if (ret != SQLITE_OK)
2741 {
2742 char *msg =
2743 sqlite3_mprintf ("TopoGeo_ToGeoTableGeneralize() error: \"%s\"",
2744 sqlite3_errmsg (topo->db_handle));
2745 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
2746 sqlite3_free (msg);
2747 goto error;
2748 }
2749
2750 /* preparing the "INSERT INTO out-table" query */
2751 ret =
2752 sqlite3_prepare_v2 (topo->db_handle, insert, strlen (insert), &stmt_ins,
2753 NULL);
2754 sqlite3_free (insert);
2755 insert = NULL;
2756 if (ret != SQLITE_OK)
2757 {
2758 char *msg =
2759 sqlite3_mprintf ("TopoGeo_ToGeoTableGeneralize() error: \"%s\"",
2760 sqlite3_errmsg (topo->db_handle));
2761 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
2762 sqlite3_free (msg);
2763 goto error;
2764 }
2765
2766 /* preparing the Topo-Seed-Edges query */
2767 xprefix = sqlite3_mprintf ("%s_seeds", topo->topology_name);
2768 xtable = gaiaDoubleQuotedSql (xprefix);
2769 sql = sqlite3_mprintf ("SELECT edge_id FROM MAIN.\"%s\" "
2770 "WHERE edge_id IS NOT NULL AND ST_Intersects(geom, ?) = 1 AND ROWID IN ("
2771 "SELECT ROWID FROM SpatialIndex WHERE f_table_name = %Q AND search_frame = ?)",
2772 xtable, xprefix);
2773 free (xtable);
2774 sqlite3_free (xprefix);
2775 ret =
2776 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_seed_edge,
2777 NULL);
2778 sqlite3_free (sql);
2779 if (ret != SQLITE_OK)
2780 {
2781 char *msg =
2782 sqlite3_mprintf ("TopoGeo_ToGeoTableGeneralize() error: \"%s\"",
2783 sqlite3_errmsg (topo->db_handle));
2784 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
2785 sqlite3_free (msg);
2786 goto error;
2787 }
2788
2789 /* preparing the Topo-Seed-Faces query */
2790 xprefix = sqlite3_mprintf ("%s_seeds", topo->topology_name);
2791 xtable = gaiaDoubleQuotedSql (xprefix);
2792 sql = sqlite3_mprintf ("SELECT face_id FROM MAIN.\"%s\" "
2793 "WHERE face_id IS NOT NULL AND ST_Intersects(geom, ?) = 1 AND ROWID IN ("
2794 "SELECT ROWID FROM SpatialIndex WHERE f_table_name = %Q AND search_frame = ?)",
2795 xtable, xprefix);
2796 free (xtable);
2797 sqlite3_free (xprefix);
2798 ret =
2799 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_seed_face,
2800 NULL);
2801 sqlite3_free (sql);
2802 if (ret != SQLITE_OK)
2803 {
2804 char *msg =
2805 sqlite3_mprintf ("TopoGeo_ToGeoTableGeneralize() error: \"%s\"",
2806 sqlite3_errmsg (topo->db_handle));
2807 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
2808 sqlite3_free (msg);
2809 goto error;
2810 }
2811
2812 /* preparing the Topo-Nodes query */
2813 xprefix = sqlite3_mprintf ("%s_node", topo->topology_name);
2814 xtable = gaiaDoubleQuotedSql (xprefix);
2815 sql = sqlite3_mprintf ("SELECT geom FROM MAIN.\"%s\" "
2816 "WHERE ST_Intersects(geom, ?) = 1 AND ROWID IN ("
2817 "SELECT ROWID FROM SpatialIndex WHERE f_table_name = %Q AND search_frame = ?)",
2818 xtable, xprefix);
2819 free (xtable);
2820 sqlite3_free (xprefix);
2821 ret =
2822 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_node,
2823 NULL);
2824 sqlite3_free (sql);
2825 if (ret != SQLITE_OK)
2826 {
2827 char *msg =
2828 sqlite3_mprintf ("TopoGeo_ToGeoTableGeneralize() error: \"%s\"",
2829 sqlite3_errmsg (topo->db_handle));
2830 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
2831 sqlite3_free (msg);
2832 goto error;
2833 }
2834
2835 /* preparing the Topo-Edges query */
2836 xprefix = sqlite3_mprintf ("%s_edge", topo->topology_name);
2837 xtable = gaiaDoubleQuotedSql (xprefix);
2838 if (tolerance > 0.0)
2839 sql =
2840 sqlite3_mprintf
2841 ("SELECT ST_SimplifyPreserveTopology(geom, %1.6f) FROM MAIN.\"%s\" WHERE edge_id = ?",
2842 tolerance, xtable, xprefix);
2843 else
2844 sql = sqlite3_mprintf ("SELECT geom FROM MAIN.\"%s\" WHERE edge_id = ?",
2845 xtable, xprefix);
2846 free (xtable);
2847 sqlite3_free (xprefix);
2848 ret =
2849 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_edge,
2850 NULL);
2851 sqlite3_free (sql);
2852 if (ret != SQLITE_OK)
2853 {
2854 char *msg =
2855 sqlite3_mprintf ("TopoGeo_ToGeoTableGeneralize() error: \"%s\"",
2856 sqlite3_errmsg (topo->db_handle));
2857 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
2858 sqlite3_free (msg);
2859 goto error;
2860 }
2861
2862 /* preparing the Topo-Faces query */
2863 xprefix = sqlite3_mprintf ("%s_edge", topo->topology_name);
2864 xtable = gaiaDoubleQuotedSql (xprefix);
2865 if (tolerance > 0.0)
2866 sql =
2867 sqlite3_mprintf
2868 ("SELECT edge_id, left_face, right_face, ST_SimplifyPreserveTopology(geom, %1.6f) FROM MAIN.\"%s\" "
2869 "WHERE left_face = ? OR right_face = ?", tolerance, xtable);
2870 else
2871 sql =
2872 sqlite3_mprintf
2873 ("SELECT edge_id, left_face, right_face, geom FROM MAIN.\"%s\" "
2874 "WHERE left_face = ? OR right_face = ?", xtable);
2875 free (xtable);
2876 sqlite3_free (xprefix);
2877 ret =
2878 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_face,
2879 NULL);
2880 sqlite3_free (sql);
2881 if (ret != SQLITE_OK)
2882 {
2883 char *msg =
2884 sqlite3_mprintf ("TopoGeo_ToGeoTableGeneralize() error: \"%s\"",
2885 sqlite3_errmsg (topo->db_handle));
2886 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
2887 sqlite3_free (msg);
2888 goto error;
2889 }
2890
2891 /* evaluating feature/topology matching via coincident topo-seeds */
2892 if (!do_eval_topogeo_seeds
2893 (topo, stmt_ref, ref_geom_col, stmt_ins, stmt_seed_edge, stmt_seed_face,
2894 stmt_node, stmt_edge, stmt_face, out_type, tolerance))
2895 goto error;
2896
2897 sqlite3_finalize (stmt_ref);
2898 sqlite3_finalize (stmt_ins);
2899 sqlite3_finalize (stmt_seed_edge);
2900 sqlite3_finalize (stmt_seed_face);
2901 sqlite3_finalize (stmt_node);
2902 sqlite3_finalize (stmt_edge);
2903 sqlite3_finalize (stmt_face);
2904 return 1;
2905
2906 error:
2907 if (create != NULL)
2908 sqlite3_free (create);
2909 if (select != NULL)
2910 sqlite3_free (select);
2911 if (insert != NULL)
2912 sqlite3_free (insert);
2913 if (stmt_ref != NULL)
2914 sqlite3_finalize (stmt_ref);
2915 if (stmt_ins != NULL)
2916 sqlite3_finalize (stmt_ins);
2917 if (stmt_seed_edge != NULL)
2918 sqlite3_finalize (stmt_seed_edge);
2919 if (stmt_seed_face != NULL)
2920 sqlite3_finalize (stmt_seed_face);
2921 if (stmt_node != NULL)
2922 sqlite3_finalize (stmt_node);
2923 if (stmt_edge != NULL)
2924 sqlite3_finalize (stmt_edge);
2925 if (stmt_face != NULL)
2926 sqlite3_finalize (stmt_face);
2927 return 0;
2928 }
2929
2930 static int
do_remove_small_faces2(struct gaia_topology * topo,sqlite3_int64 edge_id,sqlite3_stmt * stmt_rem)2931 do_remove_small_faces2 (struct gaia_topology *topo, sqlite3_int64 edge_id,
2932 sqlite3_stmt * stmt_rem)
2933 {
2934 /* removing an Edge from a Face (step 2) */
2935 int ret;
2936 sqlite3_reset (stmt_rem);
2937 sqlite3_clear_bindings (stmt_rem);
2938 sqlite3_bind_int64 (stmt_rem, 1, edge_id);
2939
2940 ret = sqlite3_step (stmt_rem);
2941 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
2942 return 1;
2943 else
2944 {
2945 char *msg = sqlite3_mprintf ("TopoGeo_RemoveSmallFaces error: \"%s\"",
2946 sqlite3_errmsg (topo->db_handle));
2947 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
2948 sqlite3_free (msg);
2949 }
2950 return 0;
2951 }
2952
2953 static int
do_remove_small_faces1(struct gaia_topology * topo,sqlite3_int64 face_id,sqlite3_stmt * stmt_edge,sqlite3_stmt * stmt_rem)2954 do_remove_small_faces1 (struct gaia_topology *topo, sqlite3_int64 face_id,
2955 sqlite3_stmt * stmt_edge, sqlite3_stmt * stmt_rem)
2956 {
2957 /* removing the longer Edge from a Face (step 1) */
2958 int ret;
2959 int first = 1;
2960 sqlite3_reset (stmt_edge);
2961 sqlite3_clear_bindings (stmt_edge);
2962 sqlite3_bind_int64 (stmt_edge, 1, face_id);
2963 sqlite3_bind_int64 (stmt_edge, 2, face_id);
2964
2965 while (1)
2966 {
2967 /* scrolling the result set rows */
2968 ret = sqlite3_step (stmt_edge);
2969 if (ret == SQLITE_DONE)
2970 break; /* end of result set */
2971 if (ret == SQLITE_ROW)
2972 {
2973 sqlite3_int64 edge_id = sqlite3_column_int64 (stmt_edge, 0);
2974 if (first)
2975 {
2976 first = 0;
2977 if (do_remove_small_faces2 (topo, edge_id, stmt_rem))
2978 goto error;
2979 }
2980 }
2981 else
2982 {
2983 char *msg =
2984 sqlite3_mprintf ("TopoGeo_RemoveSmallFaces error: \"%s\"",
2985 sqlite3_errmsg (topo->db_handle));
2986 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
2987 msg);
2988 sqlite3_free (msg);
2989 goto error;
2990 }
2991 }
2992 return 1;
2993
2994 error:
2995 return 0;
2996
2997 }
2998
2999 GAIATOPO_DECLARE int
gaiaTopoGeo_RemoveSmallFaces(GaiaTopologyAccessorPtr accessor,double min_circularity,double min_area)3000 gaiaTopoGeo_RemoveSmallFaces (GaiaTopologyAccessorPtr accessor,
3001 double min_circularity, double min_area)
3002 {
3003 /*
3004 / attempting to remove all small faces from a Topology-Geometry
3005 */
3006 struct gaia_topology *topo = (struct gaia_topology *) accessor;
3007 sqlite3_stmt *stmt_rem = NULL;
3008 sqlite3_stmt *stmt_face = NULL;
3009 sqlite3_stmt *stmt_edge = NULL;
3010 int ret;
3011 char *sql;
3012 char *table;
3013 char *xtable;
3014 int count;
3015 if (topo == NULL)
3016 return 0;
3017
3018 /* preparing the SELECT Face query */
3019 table = sqlite3_mprintf ("%s_face", topo->topology_name);
3020 xtable = gaiaDoubleQuotedSql (table);
3021 sqlite3_free (table);
3022 if (min_circularity < 1.0 && min_area > 0.0)
3023 {
3024 sql = sqlite3_mprintf ("SELECT face_id FROM (SELECT face_id, "
3025 "ST_GetFaceGeometry(%Q, face_id) AS geom FROM MAIN.\"%s\" "
3026 "WHERE face_id > 0) WHERE Circularity(geom) < %1.12f "
3027 "AND ST_Area(geom) < %1.12f",
3028 topo->topology_name, xtable, min_circularity,
3029 min_area);
3030 }
3031 else if (min_circularity >= 1.0 && min_area > 0.0)
3032 {
3033 sql =
3034 sqlite3_mprintf
3035 ("SELECT face_id FROM MAIN.\"%s\" WHERE face_id > 0 "
3036 "AND ST_Area(ST_GetFaceGeometry(%Q, face_id)) < %1.12f", xtable,
3037 topo->topology_name, min_area);
3038 }
3039 else if (min_circularity < 1.0 && min_area <= 0.0)
3040 {
3041 sql =
3042 sqlite3_mprintf
3043 ("SELECT face_id FROM MAIN.\"%s\" WHERE face_id > 0 "
3044 "AND Circularity(ST_GetFaceGeometry(%Q, face_id)) < %1.12f",
3045 xtable, topo->topology_name, min_circularity);
3046 }
3047 else
3048 {
3049 free (xtable);
3050 return 0;
3051 }
3052 free (xtable);
3053 ret =
3054 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_face,
3055 NULL);
3056 sqlite3_free (sql);
3057 sql = NULL;
3058 if (ret != SQLITE_OK)
3059 {
3060 char *msg =
3061 sqlite3_mprintf ("TopoGeo_RemoveSmallFaces() error: \"%s\"",
3062 sqlite3_errmsg (topo->db_handle));
3063 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
3064 sqlite3_free (msg);
3065 goto error;
3066 }
3067
3068 /* preparing the SELECT Edge query */
3069 table = sqlite3_mprintf ("%s_edge", topo->topology_name);
3070 xtable = gaiaDoubleQuotedSql (table);
3071 sqlite3_free (table);
3072 sql =
3073 sqlite3_mprintf ("SELECT edge_id FROM MAIN.\"%s\" WHERE right_face = ? "
3074 "OR left_face = ? ORDER BY ST_Length(geom) DESC",
3075 xtable);
3076 free (xtable);
3077 ret =
3078 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_edge,
3079 NULL);
3080 sqlite3_free (sql);
3081 sql = NULL;
3082 if (ret != SQLITE_OK)
3083 {
3084 char *msg =
3085 sqlite3_mprintf ("TopoGeo_RemoveSmallFaces() error: \"%s\"",
3086 sqlite3_errmsg (topo->db_handle));
3087 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
3088 sqlite3_free (msg);
3089 goto error;
3090 }
3091
3092 /* preparing the ST_RemEdgeNewFace() query */
3093 sql =
3094 sqlite3_mprintf ("SELECT ST_RemEdgeNewFace(%Q, ?)",
3095 topo->topology_name);
3096 ret =
3097 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_rem,
3098 NULL);
3099 sqlite3_free (sql);
3100 sql = NULL;
3101 if (ret != SQLITE_OK)
3102 {
3103 char *msg =
3104 sqlite3_mprintf ("TopoGeo_RemoveSmallFaces() error: \"%s\"",
3105 sqlite3_errmsg (topo->db_handle));
3106 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
3107 sqlite3_free (msg);
3108 goto error;
3109 }
3110
3111 count = 1;
3112 while (count)
3113 {
3114 sqlite3_reset (stmt_face);
3115 sqlite3_clear_bindings (stmt_face);
3116 count = 0;
3117 while (1)
3118 {
3119 /* scrolling the result set rows */
3120 ret = sqlite3_step (stmt_face);
3121 if (ret == SQLITE_DONE)
3122 break; /* end of result set */
3123 if (ret == SQLITE_ROW)
3124 {
3125 sqlite3_int64 face_id =
3126 sqlite3_column_int64 (stmt_face, 0);
3127 if (do_remove_small_faces1
3128 (topo, face_id, stmt_edge, stmt_rem))
3129 goto error;
3130 count++;
3131 }
3132 else
3133 {
3134 char *msg =
3135 sqlite3_mprintf
3136 ("TopoGeo_RemoveSmallFaces error: \"%s\"",
3137 sqlite3_errmsg (topo->db_handle));
3138 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr)
3139 topo, msg);
3140 sqlite3_free (msg);
3141 goto error;
3142 }
3143 }
3144 }
3145
3146 sqlite3_finalize (stmt_face);
3147 sqlite3_finalize (stmt_edge);
3148 sqlite3_finalize (stmt_rem);
3149 return 1;
3150
3151 error:
3152 if (sql != NULL)
3153 sqlite3_free (sql);
3154 if (stmt_face != NULL)
3155 sqlite3_finalize (stmt_face);
3156 if (stmt_edge != NULL)
3157 sqlite3_finalize (stmt_edge);
3158 if (stmt_rem != NULL)
3159 sqlite3_finalize (stmt_rem);
3160 return 0;
3161 }
3162
3163 GAIATOPO_DECLARE int
gaiaTopoGeo_RemoveDanglingEdges(GaiaTopologyAccessorPtr accessor)3164 gaiaTopoGeo_RemoveDanglingEdges (GaiaTopologyAccessorPtr accessor)
3165 {
3166 /*
3167 / attempting to remove all dangling edges from a Topology-Geometry
3168 */
3169 struct gaia_topology *topo = (struct gaia_topology *) accessor;
3170 int ret;
3171 char *sql;
3172 char *table;
3173 char *xtable;
3174 char *err_msg = NULL;
3175 if (topo == NULL)
3176 return 0;
3177
3178 /* preparing the ST_RemEdgeNewFace() query */
3179 table = sqlite3_mprintf ("%s_edge", topo->topology_name);
3180 xtable = gaiaDoubleQuotedSql (table);
3181 sqlite3_free (table);
3182 sql =
3183 sqlite3_mprintf
3184 ("SELECT ST_RemEdgeNewFace(%Q, edge_id) FROM MAIN.\"%s\" "
3185 "WHERE left_face = right_face", topo->topology_name, xtable);
3186 free (xtable);
3187 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &err_msg);
3188 sqlite3_free (sql);
3189 if (ret != SQLITE_OK)
3190 {
3191 char *msg =
3192 sqlite3_mprintf ("TopoGeo_RemoveDanglingEdges error: \"%s\"",
3193 err_msg);
3194 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
3195 sqlite3_free (err_msg);
3196 sqlite3_free (msg);
3197 return 0;
3198 }
3199 return 1;
3200 }
3201
3202 GAIATOPO_DECLARE int
gaiaTopoGeo_RemoveDanglingNodes(GaiaTopologyAccessorPtr accessor)3203 gaiaTopoGeo_RemoveDanglingNodes (GaiaTopologyAccessorPtr accessor)
3204 {
3205 /*
3206 / attempting to remove all dangling nodes from a Topology-Geometry
3207 */
3208 struct gaia_topology *topo = (struct gaia_topology *) accessor;
3209 int ret;
3210 char *sql;
3211 char *table;
3212 char *xtable;
3213 char *err_msg = NULL;
3214 if (topo == NULL)
3215 return 0;
3216
3217 /* preparing the ST_RemIsoNode() query */
3218 table = sqlite3_mprintf ("%s_node", topo->topology_name);
3219 xtable = gaiaDoubleQuotedSql (table);
3220 sqlite3_free (table);
3221 sql =
3222 sqlite3_mprintf ("SELECT ST_RemIsoNode(%Q, node_id) FROM MAIN.\"%s\" "
3223 "WHERE containing_face IS NOT NULL",
3224 topo->topology_name, xtable);
3225 free (xtable);
3226 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &err_msg);
3227 sqlite3_free (sql);
3228 if (ret != SQLITE_OK)
3229 {
3230 char *msg =
3231 sqlite3_mprintf ("TopoGeo_RemoveDanglingNodes error: \"%s\"",
3232 err_msg);
3233 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
3234 sqlite3_free (err_msg);
3235 sqlite3_free (msg);
3236 return 0;
3237 }
3238 return 1;
3239 }
3240
3241 GAIATOPO_DECLARE int
gaiaTopoGeo_ToGeoTable(GaiaTopologyAccessorPtr accessor,const char * db_prefix,const char * ref_table,const char * ref_column,const char * out_table,int with_spatial_index)3242 gaiaTopoGeo_ToGeoTable (GaiaTopologyAccessorPtr accessor,
3243 const char *db_prefix, const char *ref_table,
3244 const char *ref_column, const char *out_table,
3245 int with_spatial_index)
3246 {
3247 /* attempting to create and populate a new GeoTable out from a Topology-Geometry */
3248 return gaiaTopoGeo_ToGeoTableGeneralize (accessor, db_prefix, ref_table,
3249 ref_column, out_table, -1.0,
3250 with_spatial_index);
3251 }
3252
3253 SPATIALITE_PRIVATE int
gaia_do_eval_disjoint(const void * handle,const char * matrix)3254 gaia_do_eval_disjoint (const void *handle, const char *matrix)
3255 {
3256 /* same as ST_Disjoint */
3257 sqlite3 *sqlite = (sqlite3 *) handle;
3258 char **results;
3259 int ret;
3260 int rows;
3261 int columns;
3262 int i;
3263 int value = 0;
3264 char *sql =
3265 sqlite3_mprintf ("SELECT ST_RelateMatch(%Q, 'FF*FF****')", matrix);
3266 ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, NULL);
3267 sqlite3_free (sql);
3268 if (ret != SQLITE_OK)
3269 return 0;
3270 for (i = 1; i <= rows; i++)
3271 value = atoi (results[(i * columns) + 0]);
3272 sqlite3_free_table (results);
3273 return value;
3274 }
3275
3276 SPATIALITE_PRIVATE int
gaia_do_eval_overlaps(const void * handle,const char * matrix)3277 gaia_do_eval_overlaps (const void *handle, const char *matrix)
3278 {
3279 /* same as ST_Overlaps */
3280 sqlite3 *sqlite = (sqlite3 *) handle;
3281 char **results;
3282 int ret;
3283 int rows;
3284 int columns;
3285 int i;
3286 int value = 0;
3287 char *sql = sqlite3_mprintf ("SELECT ST_RelateMatch(%Q, 'T*T***T**') "
3288 "OR ST_RelateMatch(%Q, '1*T***T**')", matrix,
3289 matrix);
3290 ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, NULL);
3291 sqlite3_free (sql);
3292 if (ret != SQLITE_OK)
3293 return 0;
3294 for (i = 1; i <= rows; i++)
3295 value = atoi (results[(i * columns) + 0]);
3296 sqlite3_free_table (results);
3297 return value;
3298 }
3299
3300 SPATIALITE_PRIVATE int
gaia_do_eval_covers(const void * handle,const char * matrix)3301 gaia_do_eval_covers (const void *handle, const char *matrix)
3302 {
3303 /* same as ST_Covers */
3304 sqlite3 *sqlite = (sqlite3 *) handle;
3305 char **results;
3306 int ret;
3307 int rows;
3308 int columns;
3309 int i;
3310 int value = 0;
3311 char *sql = sqlite3_mprintf ("SELECT ST_RelateMatch(%Q, 'T*****FF*') "
3312 "OR ST_RelateMatch(%Q, '*T****FF*') OR ST_RelateMatch(%Q, '***T**FF*') "
3313 "OR ST_RelateMatch(%Q, '****T*FF*')", matrix,
3314 matrix, matrix, matrix);
3315 ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, NULL);
3316 sqlite3_free (sql);
3317 if (ret != SQLITE_OK)
3318 return 0;
3319 for (i = 1; i <= rows; i++)
3320 value = atoi (results[(i * columns) + 0]);
3321 sqlite3_free_table (results);
3322 return value;
3323 }
3324
3325 SPATIALITE_PRIVATE int
gaia_do_eval_covered_by(const void * handle,const char * matrix)3326 gaia_do_eval_covered_by (const void *handle, const char *matrix)
3327 {
3328 /* same as ST_CoveredBy */
3329 sqlite3 *sqlite = (sqlite3 *) handle;
3330 char **results;
3331 int ret;
3332 int rows;
3333 int columns;
3334 int i;
3335 int value = 0;
3336 char *sql = sqlite3_mprintf ("SELECT ST_RelateMatch(%Q, 'T*F**F***') "
3337 "OR ST_RelateMatch(%Q, '*TF**F***') OR ST_RelateMatch(%Q, '**FT*F***') "
3338 "OR ST_RelateMatch(%Q, '**F*TF***')", matrix,
3339 matrix, matrix, matrix);
3340 ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, NULL);
3341 sqlite3_free (sql);
3342 if (ret != SQLITE_OK)
3343 return 0;
3344 for (i = 1; i <= rows; i++)
3345 value = atoi (results[(i * columns) + 0]);
3346 sqlite3_free_table (results);
3347 return value;
3348 }
3349
3350 static int
find_polyface_matches(struct gaia_topology * topo,sqlite3_stmt * stmt_ref,sqlite3_stmt * stmt_ins,sqlite3_int64 face_id,sqlite3_int64 containing_face)3351 find_polyface_matches (struct gaia_topology *topo, sqlite3_stmt * stmt_ref,
3352 sqlite3_stmt * stmt_ins, sqlite3_int64 face_id,
3353 sqlite3_int64 containing_face)
3354 {
3355 /* retrieving PolyFace matches */
3356 int ret;
3357 int count = 0;
3358
3359 sqlite3_reset (stmt_ref);
3360 sqlite3_clear_bindings (stmt_ref);
3361 sqlite3_bind_int64 (stmt_ref, 1, face_id);
3362
3363 while (1)
3364 {
3365 /* scrolling the result set rows - Spatial Relationships */
3366 ret = sqlite3_step (stmt_ref);
3367 if (ret == SQLITE_DONE)
3368 break; /* end of result set */
3369 if (ret == SQLITE_ROW)
3370 {
3371 sqlite3_int64 rowid = sqlite3_column_int64 (stmt_ref, 0);
3372
3373 sqlite3_reset (stmt_ins);
3374 sqlite3_clear_bindings (stmt_ins);
3375 sqlite3_bind_int64 (stmt_ins, 1, face_id);
3376 if (containing_face <= 0)
3377 {
3378 sqlite3_bind_int (stmt_ins, 2, 0);
3379 sqlite3_bind_null (stmt_ins, 3);
3380 }
3381 else
3382 {
3383 sqlite3_bind_int (stmt_ins, 2, 1);
3384 sqlite3_bind_int64 (stmt_ins, 3, containing_face);
3385 }
3386 sqlite3_bind_int64 (stmt_ins, 4, rowid);
3387 /* inserting a row into the output table */
3388 ret = sqlite3_step (stmt_ins);
3389 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
3390 count++;
3391 else
3392 {
3393 char *msg =
3394 sqlite3_mprintf ("PolyFacesList error: \"%s\"",
3395 sqlite3_errmsg (topo->db_handle));
3396 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr)
3397 topo, msg);
3398 sqlite3_free (msg);
3399 return 0;
3400 }
3401 }
3402 else
3403 {
3404 char *msg = sqlite3_mprintf ("PolyFacesList error: \"%s\"",
3405 sqlite3_errmsg (topo->db_handle));
3406 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
3407 msg);
3408 sqlite3_free (msg);
3409 return 0;
3410 }
3411 }
3412
3413 if (count == 0)
3414 {
3415 /* unrelated Face */
3416 sqlite3_reset (stmt_ins);
3417 sqlite3_clear_bindings (stmt_ins);
3418 sqlite3_bind_int64 (stmt_ins, 1, face_id);
3419 if (containing_face <= 0)
3420 {
3421 sqlite3_bind_int (stmt_ins, 2, 0);
3422 sqlite3_bind_null (stmt_ins, 3);
3423 }
3424 else
3425 {
3426 sqlite3_bind_int (stmt_ins, 2, 1);
3427 sqlite3_bind_int64 (stmt_ins, 3, containing_face);
3428 }
3429 sqlite3_bind_null (stmt_ins, 4);
3430 /* inserting a row into the output table */
3431 ret = sqlite3_step (stmt_ins);
3432 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
3433 ;
3434 else
3435 {
3436 char *msg = sqlite3_mprintf ("PolyFacesList error: \"%s\"",
3437 sqlite3_errmsg (topo->db_handle));
3438 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
3439 msg);
3440 sqlite3_free (msg);
3441 return 0;
3442 }
3443 }
3444 return 1;
3445 }
3446
3447 static int
insert_polyface_reverse(struct gaia_topology * topo,sqlite3_stmt * stmt_ins,sqlite3_int64 polygon_id)3448 insert_polyface_reverse (struct gaia_topology *topo, sqlite3_stmt * stmt_ins,
3449 sqlite3_int64 polygon_id)
3450 {
3451 /* found a mismatching RefPolygon - inserting into the output table */
3452 int ret;
3453
3454 sqlite3_reset (stmt_ins);
3455 sqlite3_clear_bindings (stmt_ins);
3456 sqlite3_bind_null (stmt_ins, 1);
3457 sqlite3_bind_int (stmt_ins, 2, 0);
3458 sqlite3_bind_null (stmt_ins, 3);
3459 sqlite3_bind_int64 (stmt_ins, 4, polygon_id);
3460 /* inserting a row into the output table */
3461 ret = sqlite3_step (stmt_ins);
3462 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
3463 ;
3464 else
3465 {
3466 char *msg = sqlite3_mprintf ("PolyFacesList error: \"%s\"",
3467 sqlite3_errmsg (topo->db_handle));
3468 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
3469 sqlite3_free (msg);
3470 return 0;
3471 }
3472 return 1;
3473 }
3474
3475 SPATIALITE_PRIVATE int
gaia_check_spatial_index(const void * handle,const char * db_prefix,const char * ref_table,const char * ref_column)3476 gaia_check_spatial_index (const void *handle, const char *db_prefix,
3477 const char *ref_table, const char *ref_column)
3478 {
3479 /* testing if the RefTable has an R*Tree Spatial Index */
3480 sqlite3 *sqlite = (sqlite3 *) handle;
3481 char *sql;
3482 char *xprefix;
3483 int has_rtree = 0;
3484 char **results;
3485 int ret;
3486 int rows;
3487 int columns;
3488 int i;
3489 char *errMsg = NULL;
3490
3491 xprefix = gaiaDoubleQuotedSql (db_prefix);
3492 sql =
3493 sqlite3_mprintf
3494 ("SELECT spatial_index_enabled FROM \"%s\".geometry_columns "
3495 "WHERE f_table_name = %Q AND f_geometry_column = %Q", xprefix,
3496 ref_table, ref_column);
3497 free (xprefix);
3498 ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, &errMsg);
3499 sqlite3_free (sql);
3500 if (ret != SQLITE_OK)
3501 return 0;
3502 for (i = 1; i <= rows; i++)
3503 {
3504 has_rtree = atoi (results[(i * columns) + 0]);
3505 }
3506 sqlite3_free_table (results);
3507 return has_rtree;
3508 }
3509
3510 GAIATOPO_DECLARE int
gaiaTopoGeo_PolyFacesList(GaiaTopologyAccessorPtr accessor,const char * db_prefix,const char * ref_table,const char * ref_column,const char * out_table)3511 gaiaTopoGeo_PolyFacesList (GaiaTopologyAccessorPtr accessor,
3512 const char *db_prefix, const char *ref_table,
3513 const char *ref_column, const char *out_table)
3514 {
3515 /* creating and populating a new Table reporting about Faces/Polygon correspondencies */
3516 struct gaia_topology *topo = (struct gaia_topology *) accessor;
3517 sqlite3_stmt *stmt_holes = NULL;
3518 sqlite3_stmt *stmt_ref = NULL;
3519 sqlite3_stmt *stmt_rev = NULL;
3520 sqlite3_stmt *stmt_ins = NULL;
3521 int ret;
3522 char *sql;
3523 char *face;
3524 char *table;
3525 char *idx_name;
3526 char *xface;
3527 char *xtable;
3528 char *xprefix;
3529 char *xcolumn;
3530 char *xidx_name;
3531 char *rtree_name;
3532 char *seeds;
3533 char *xseeds;
3534 int ref_has_spatial_index = 0;
3535 if (topo == NULL)
3536 return 0;
3537
3538 /* attempting to build the output table */
3539 xtable = gaiaDoubleQuotedSql (out_table);
3540 sql = sqlite3_mprintf ("CREATE TABLE main.\"%s\" (\n"
3541 "\tid INTEGER PRIMARY KEY AUTOINCREMENT,\n"
3542 "\tface_id INTEGER,\n"
3543 "\tis_hole INTEGER NOT NULL,\n"
3544 "\tcontaining_face INTEGER,\n"
3545 "\tref_rowid INTEGER)", xtable);
3546 free (xtable);
3547 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, NULL);
3548 sqlite3_free (sql);
3549 if (ret != SQLITE_OK)
3550 {
3551 char *msg = sqlite3_mprintf ("PolyFacesList error: \"%s\"",
3552 sqlite3_errmsg (topo->db_handle));
3553 gaiatopo_set_last_error_msg (accessor, msg);
3554 sqlite3_free (msg);
3555 goto error;
3556 }
3557 idx_name = sqlite3_mprintf ("idx_%s_face_id", out_table);
3558 xidx_name = gaiaDoubleQuotedSql (idx_name);
3559 sqlite3_free (idx_name);
3560 xtable = gaiaDoubleQuotedSql (out_table);
3561 sql =
3562 sqlite3_mprintf
3563 ("CREATE INDEX main.\"%s\" ON \"%s\" (face_id, ref_rowid)", xidx_name,
3564 xtable);
3565 free (xidx_name);
3566 free (xtable);
3567 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, NULL);
3568 sqlite3_free (sql);
3569 if (ret != SQLITE_OK)
3570 {
3571 char *msg = sqlite3_mprintf ("PolyFacesList error: \"%s\"",
3572 sqlite3_errmsg (topo->db_handle));
3573 gaiatopo_set_last_error_msg (accessor, msg);
3574 sqlite3_free (msg);
3575 goto error;
3576 }
3577 idx_name = sqlite3_mprintf ("idx_%s_holes", out_table);
3578 xidx_name = gaiaDoubleQuotedSql (idx_name);
3579 sqlite3_free (idx_name);
3580 xtable = gaiaDoubleQuotedSql (out_table);
3581 sql =
3582 sqlite3_mprintf
3583 ("CREATE INDEX main.\"%s\" ON \"%s\" (containing_face, face_id)",
3584 xidx_name, xtable);
3585 free (xidx_name);
3586 free (xtable);
3587 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, NULL);
3588 sqlite3_free (sql);
3589 if (ret != SQLITE_OK)
3590 {
3591 char *msg = sqlite3_mprintf ("PolyFacesList error: \"%s\"",
3592 sqlite3_errmsg (topo->db_handle));
3593 gaiatopo_set_last_error_msg (accessor, msg);
3594 sqlite3_free (msg);
3595 goto error;
3596 }
3597
3598 /* building the IsHole SQL statement */
3599 face = sqlite3_mprintf ("%s_face", topo->topology_name);
3600 xface = gaiaDoubleQuotedSql (face);
3601 sqlite3_free (face);
3602 table = sqlite3_mprintf ("%s_edge", topo->topology_name);
3603 xtable = gaiaDoubleQuotedSql (table);
3604 sqlite3_free (table);
3605 sql =
3606 sqlite3_mprintf
3607 ("SELECT f.face_id, Count(DISTINCT r.left_face) AS cnt1, "
3608 "Count(DISTINCT l.right_face) AS cnt2, r.left_face, l.right_face "
3609 "FROM main.\"%s\" AS f "
3610 "LEFT JOIN main.\"%s\" AS r ON (f.face_id = r.right_face) "
3611 "LEFT JOIN main.\"%s\" AS l ON (f.face_id = l.left_face) "
3612 "GROUP BY f.face_id", xface, xtable, xtable);
3613 free (xface);
3614 free (xtable);
3615 ret =
3616 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_holes,
3617 NULL);
3618 sqlite3_free (sql);
3619 if (ret != SQLITE_OK)
3620 {
3621 char *msg = sqlite3_mprintf ("PolyFacesList error: \"%s\"",
3622 sqlite3_errmsg (topo->db_handle));
3623 gaiatopo_set_last_error_msg (accessor, msg);
3624 sqlite3_free (msg);
3625 goto error;
3626 }
3627
3628 /* building the RefTable SQL statement */
3629 seeds = sqlite3_mprintf ("%s_seeds", topo->topology_name);
3630 rtree_name = sqlite3_mprintf ("DB=%s.%s", db_prefix, ref_table);
3631 ref_has_spatial_index =
3632 gaia_check_spatial_index (topo->db_handle, db_prefix, ref_table,
3633 ref_column);
3634 xprefix = gaiaDoubleQuotedSql (db_prefix);
3635 xtable = gaiaDoubleQuotedSql (ref_table);
3636 xcolumn = gaiaDoubleQuotedSql (ref_column);
3637 xseeds = gaiaDoubleQuotedSql (seeds);
3638 if (ref_has_spatial_index)
3639 sql =
3640 sqlite3_mprintf
3641 ("SELECT r.rowid FROM MAIN.\"%s\" AS s, \"%s\".\"%s\" AS r "
3642 "WHERE ST_Intersects(r.\"%s\", s.geom) == 1 AND s.face_id = ? "
3643 "AND r.rowid IN (SELECT rowid FROM SpatialIndex WHERE f_table_name = %Q "
3644 "AND f_geometry_column = %Q AND search_frame = s.geom)", xseeds,
3645 xprefix, xtable, xcolumn, rtree_name, xcolumn);
3646 else
3647 sql =
3648 sqlite3_mprintf
3649 ("SELECT r.rowid FROM MAIN.\"%s\" AS s, \"%s\".\"%s\" AS r "
3650 "WHERE ST_Intersects(r.\"%s\", s.geom) == 1 AND s.face_id = ?",
3651 xseeds, xprefix, xtable, xcolumn);
3652 free (xprefix);
3653 free (xtable);
3654 free (xcolumn);
3655 free (xseeds);
3656 sqlite3_free (rtree_name);
3657 sqlite3_free (seeds);
3658 ret =
3659 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_ref,
3660 NULL);
3661 sqlite3_free (sql);
3662 if (ret != SQLITE_OK)
3663 {
3664 char *msg = sqlite3_mprintf ("PolyFacesList error: \"%s\"",
3665 sqlite3_errmsg (topo->db_handle));
3666 gaiatopo_set_last_error_msg (accessor, msg);
3667 sqlite3_free (msg);
3668 goto error;
3669 }
3670
3671 /* building the Reverse RefTable SQL statement */
3672 seeds = sqlite3_mprintf ("%s_seeds", topo->topology_name);
3673 rtree_name =
3674 sqlite3_mprintf ("DB=%s.%s_seeds", db_prefix, topo->topology_name);
3675 xprefix = gaiaDoubleQuotedSql (db_prefix);
3676 xtable = gaiaDoubleQuotedSql (ref_table);
3677 xcolumn = gaiaDoubleQuotedSql (ref_column);
3678 xseeds = gaiaDoubleQuotedSql (seeds);
3679 sql = sqlite3_mprintf ("SELECT r.rowid FROM \"%s\".\"%s\" AS r "
3680 "LEFT JOIN MAIN.\"%s\" AS s ON (ST_Intersects(r.\"%s\", s.geom) = 1 "
3681 "AND s.face_id IS NOT NULL AND s.rowid IN (SELECT rowid FROM SpatialIndex "
3682 "WHERE f_table_name = %Q AND search_frame = r.\"%s\")) "
3683 "WHERE s.face_id IS NULL", xprefix, xtable, xseeds,
3684 xcolumn, rtree_name, xcolumn);
3685 free (xprefix);
3686 free (xtable);
3687 free (xcolumn);
3688 free (xseeds);
3689 sqlite3_free (rtree_name);
3690 sqlite3_free (seeds);
3691 ret =
3692 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_rev,
3693 NULL);
3694 sqlite3_free (sql);
3695 if (ret != SQLITE_OK)
3696 {
3697 char *msg = sqlite3_mprintf ("PolyFacesList error: \"%s\"",
3698 sqlite3_errmsg (topo->db_handle));
3699 gaiatopo_set_last_error_msg (accessor, msg);
3700 sqlite3_free (msg);
3701 goto error;
3702 }
3703
3704 /* building the Insert SQL statement */
3705 xtable = gaiaDoubleQuotedSql (out_table);
3706 sql = sqlite3_mprintf ("INSERT INTO main.\"%s\" (id, face_id, is_hole, "
3707 "containing_face, ref_rowid) "
3708 "VALUES (NULL, ?, ?, ?, ?)", xtable);
3709 free (xtable);
3710 ret =
3711 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_ins,
3712 NULL);
3713 sqlite3_free (sql);
3714 if (ret != SQLITE_OK)
3715 {
3716 char *msg = sqlite3_mprintf ("PolyFacesList error: \"%s\"",
3717 sqlite3_errmsg (topo->db_handle));
3718 gaiatopo_set_last_error_msg (accessor, msg);
3719 sqlite3_free (msg);
3720 goto error;
3721 }
3722
3723 while (1)
3724 {
3725 /* scrolling the result set rows - Faces/Holes */
3726 ret = sqlite3_step (stmt_holes);
3727 if (ret == SQLITE_DONE)
3728 break; /* end of result set */
3729 if (ret == SQLITE_ROW)
3730 {
3731 sqlite3_int64 containing_face = -1;
3732 sqlite3_int64 face_id = sqlite3_column_int64 (stmt_holes, 0);
3733 int count1 = sqlite3_column_int (stmt_holes, 1);
3734 int count2 = sqlite3_column_int (stmt_holes, 2);
3735 if (count1 == 1 && count2 == 1)
3736 {
3737 sqlite3_int64 id1 = sqlite3_column_int64 (stmt_holes, 3);
3738 sqlite3_int64 id2 = sqlite3_column_int64 (stmt_holes, 4);
3739 if (id1 == id2)
3740 containing_face = id1;
3741 }
3742 else if (count1 == 1 && count2 == 0)
3743 containing_face = sqlite3_column_int64 (stmt_holes, 3);
3744 else if (count1 == 0 && count2 == 1)
3745 containing_face = sqlite3_column_int64 (stmt_holes, 4);
3746 if (!find_polyface_matches
3747 (topo, stmt_ref, stmt_ins, face_id, containing_face))
3748 goto error;
3749 }
3750 else
3751 {
3752 char *msg = sqlite3_mprintf ("PolyFacesList error: \"%s\"",
3753 sqlite3_errmsg (topo->db_handle));
3754 gaiatopo_set_last_error_msg (accessor, msg);
3755 sqlite3_free (msg);
3756 goto error;
3757 }
3758 }
3759
3760 while (1)
3761 {
3762 /* scrolling the Reverse result set rows - Polygons */
3763 ret = sqlite3_step (stmt_rev);
3764 if (ret == SQLITE_DONE)
3765 break; /* end of result set */
3766 if (ret == SQLITE_ROW)
3767 {
3768 sqlite3_int64 polyg_id = sqlite3_column_int64 (stmt_rev, 0);
3769 if (!insert_polyface_reverse (topo, stmt_ins, polyg_id))
3770 goto error;
3771 }
3772 else
3773 {
3774 char *msg = sqlite3_mprintf ("PolyFacesList error: \"%s\"",
3775 sqlite3_errmsg (topo->db_handle));
3776 gaiatopo_set_last_error_msg (accessor, msg);
3777 sqlite3_free (msg);
3778 goto error;
3779 }
3780 }
3781
3782 sqlite3_finalize (stmt_holes);
3783 sqlite3_finalize (stmt_ref);
3784 sqlite3_finalize (stmt_rev);
3785 sqlite3_finalize (stmt_ins);
3786 return 1;
3787
3788 error:
3789 if (stmt_holes != NULL)
3790 sqlite3_finalize (stmt_holes);
3791 if (stmt_ref != NULL)
3792 sqlite3_finalize (stmt_ref);
3793 if (stmt_rev != NULL)
3794 sqlite3_finalize (stmt_rev);
3795 if (stmt_ins != NULL)
3796 sqlite3_finalize (stmt_ins);
3797 return 0;
3798 }
3799
3800 static int
do_find_matching_point(gaiaLinestringPtr ln1,int * idx1,gaiaLinestringPtr ln2,int * idx2)3801 do_find_matching_point (gaiaLinestringPtr ln1, int *idx1, gaiaLinestringPtr ln2,
3802 int *idx2)
3803 {
3804 /* searching for a common point in both Linestrings */
3805 int i1;
3806 int i2;
3807 double x1;
3808 double y1;
3809 double z1;
3810 double m1;
3811 double x2;
3812 double y2;
3813 double z2;
3814 double m2;
3815 for (i1 = 0; i1 < ln1->Points; i1++)
3816 {
3817 /* extracting a Vertex from the first Linestring */
3818 z1 = 0.0;
3819 m1 = 0.0;
3820 if (ln1->DimensionModel == GAIA_XY_Z)
3821 {
3822 gaiaGetPointXYZ (ln1->Coords, i1, &x1, &y1, &z1);
3823 }
3824 else if (ln1->DimensionModel == GAIA_XY_M)
3825 {
3826 gaiaGetPointXYM (ln1->Coords, i1, &x1, &y1, &m1);
3827 }
3828 else if (ln1->DimensionModel == GAIA_XY_Z_M)
3829 {
3830 gaiaGetPointXYZM (ln1->Coords, i1, &x1, &y1, &z1, &m1);
3831 }
3832 else
3833 {
3834 gaiaGetPoint (ln1->Coords, i1, &x1, &y1);
3835 }
3836 for (i2 = 0; i2 < ln2->Points; i2++)
3837 {
3838 /* extracting a Vertex from the second Linestring */
3839 z2 = 0.0;
3840 m2 = 0.0;
3841 if (ln2->DimensionModel == GAIA_XY_Z)
3842 {
3843 gaiaGetPointXYZ (ln2->Coords, i2, &x2, &y2, &z2);
3844 }
3845 else if (ln2->DimensionModel == GAIA_XY_M)
3846 {
3847 gaiaGetPointXYM (ln2->Coords, i2, &x2, &y2, &m2);
3848 }
3849 else if (ln2->DimensionModel == GAIA_XY_Z_M)
3850 {
3851 gaiaGetPointXYZM (ln2->Coords, i2, &x2, &y2, &z2, &m2);
3852 }
3853 else
3854 {
3855 gaiaGetPoint (ln2->Coords, i2, &x2, &y2);
3856 }
3857 if (x1 == x2 && y1 == y2 && z1 == z2 && m1 == m2)
3858 {
3859 *idx1 = i1;
3860 *idx2 = i2;
3861 return 1;
3862 }
3863 }
3864 }
3865 *idx1 = -1;
3866 *idx2 = -1;
3867 return 0;
3868 }
3869
3870 static int
do_check_forward(gaiaLinestringPtr ln1,int idx1,gaiaLinestringPtr ln2,int idx2)3871 do_check_forward (gaiaLinestringPtr ln1, int idx1, gaiaLinestringPtr ln2,
3872 int idx2)
3873 {
3874 /* testing for further matching Vertices (same directions) */
3875 int i1;
3876 int i2;
3877 double x1;
3878 double y1;
3879 double z1;
3880 double m1;
3881 double x2;
3882 double y2;
3883 double z2;
3884 double m2;
3885 int count = 0;
3886 for (i1 = idx1; i1 < ln1->Points; i1++)
3887 {
3888 /* extracting a Vertex from the first Linestring */
3889 z1 = 0.0;
3890 m1 = 0.0;
3891 if (ln1->DimensionModel == GAIA_XY_Z)
3892 {
3893 gaiaGetPointXYZ (ln1->Coords, i1, &x1, &y1, &z1);
3894 }
3895 else if (ln1->DimensionModel == GAIA_XY_M)
3896 {
3897 gaiaGetPointXYM (ln1->Coords, i1, &x1, &y1, &m1);
3898 }
3899 else if (ln1->DimensionModel == GAIA_XY_Z_M)
3900 {
3901 gaiaGetPointXYZM (ln1->Coords, i1, &x1, &y1, &z1, &m1);
3902 }
3903 else
3904 {
3905 gaiaGetPoint (ln1->Coords, i1, &x1, &y1);
3906 }
3907 for (i2 = idx2; i2 < ln2->Points; i2++)
3908 {
3909 /* extracting a Vertex from the second Linestring */
3910 z2 = 0.0;
3911 m2 = 0.0;
3912 if (ln2->DimensionModel == GAIA_XY_Z)
3913 {
3914 gaiaGetPointXYZ (ln2->Coords, i2, &x2, &y2, &z2);
3915 }
3916 else if (ln2->DimensionModel == GAIA_XY_M)
3917 {
3918 gaiaGetPointXYM (ln2->Coords, i2, &x2, &y2, &m2);
3919 }
3920 else if (ln2->DimensionModel == GAIA_XY_Z_M)
3921 {
3922 gaiaGetPointXYZM (ln2->Coords, i2, &x2, &y2, &z2, &m2);
3923 }
3924 else
3925 {
3926 gaiaGetPoint (ln2->Coords, i2, &x2, &y2);
3927 }
3928 if (x1 == x2 && y1 == y2 && z1 == z2 && m1 == m2)
3929 {
3930 idx2++;
3931 count++;
3932 break;
3933 }
3934 }
3935 }
3936 if (count >= 2)
3937 return 1;
3938 return 0;
3939 }
3940
3941 static int
do_check_backward(gaiaLinestringPtr ln1,int idx1,gaiaLinestringPtr ln2,int idx2)3942 do_check_backward (gaiaLinestringPtr ln1, int idx1, gaiaLinestringPtr ln2,
3943 int idx2)
3944 {
3945 /* testing for further matching Vertices (opposite directions) */
3946 int i1;
3947 int i2;
3948 double x1;
3949 double y1;
3950 double z1;
3951 double m1;
3952 double x2;
3953 double y2;
3954 double z2;
3955 double m2;
3956 int count = 0;
3957 for (i1 = idx1; i1 < ln1->Points; i1++)
3958 {
3959 /* extracting a Vertex from the first Linestring */
3960 z1 = 0.0;
3961 m1 = 0.0;
3962 if (ln1->DimensionModel == GAIA_XY_Z)
3963 {
3964 gaiaGetPointXYZ (ln1->Coords, i1, &x1, &y1, &z1);
3965 }
3966 else if (ln1->DimensionModel == GAIA_XY_M)
3967 {
3968 gaiaGetPointXYM (ln1->Coords, i1, &x1, &y1, &m1);
3969 }
3970 else if (ln1->DimensionModel == GAIA_XY_Z_M)
3971 {
3972 gaiaGetPointXYZM (ln1->Coords, i1, &x1, &y1, &z1, &m1);
3973 }
3974 else
3975 {
3976 gaiaGetPoint (ln1->Coords, i1, &x1, &y1);
3977 }
3978 for (i2 = idx2; i2 >= 0; i2--)
3979 {
3980 /* extracting a Vertex from the second Linestring */
3981 z2 = 0.0;
3982 m2 = 0.0;
3983 if (ln2->DimensionModel == GAIA_XY_Z)
3984 {
3985 gaiaGetPointXYZ (ln2->Coords, i2, &x2, &y2, &z2);
3986 }
3987 else if (ln2->DimensionModel == GAIA_XY_M)
3988 {
3989 gaiaGetPointXYM (ln2->Coords, i2, &x2, &y2, &m2);
3990 }
3991 else if (ln2->DimensionModel == GAIA_XY_Z_M)
3992 {
3993 gaiaGetPointXYZM (ln2->Coords, i2, &x2, &y2, &z2, &m2);
3994 }
3995 else
3996 {
3997 gaiaGetPoint (ln2->Coords, i2, &x2, &y2);
3998 }
3999 if (x1 == x2 && y1 == y2 && z1 == z2 && m1 == m2)
4000 {
4001 idx2--;
4002 count++;
4003 break;
4004 }
4005 }
4006 }
4007 if (count >= 2)
4008 return 1;
4009 return 0;
4010 }
4011
4012 SPATIALITE_PRIVATE void
gaia_do_check_direction(const void * x1,const void * x2,char * direction)4013 gaia_do_check_direction (const void *x1, const void *x2, char *direction)
4014 {
4015 /* checking if two Linestrings have the same direction */
4016 gaiaGeomCollPtr g1 = (gaiaGeomCollPtr) x1;
4017 gaiaGeomCollPtr g2 = (gaiaGeomCollPtr) x2;
4018 int idx1;
4019 int idx2;
4020 gaiaLinestringPtr ln1 = g1->FirstLinestring;
4021 gaiaLinestringPtr ln2 = g2->FirstLinestring;
4022 while (ln2 != NULL)
4023 {
4024 /* the second Geometry could be a MultiLinestring */
4025 if (do_find_matching_point (ln1, &idx1, ln2, &idx2))
4026 {
4027 if (do_check_forward (ln1, idx1, ln2, idx2))
4028 {
4029 /* ok, same directions */
4030 *direction = '+';
4031 return;
4032 }
4033 if (do_check_backward (ln1, idx1, ln2, idx2))
4034 {
4035 /* ok, opposite directions */
4036 *direction = '-';
4037 return;
4038 }
4039 }
4040 ln2 = ln2->Next;
4041 }
4042 *direction = '?';
4043 }
4044
4045 static int
find_lineedge_relationships(struct gaia_topology * topo,sqlite3_stmt * stmt_ref,sqlite3_stmt * stmt_ins,sqlite3_int64 edge_id,const unsigned char * blob,int blob_sz)4046 find_lineedge_relationships (struct gaia_topology *topo,
4047 sqlite3_stmt * stmt_ref, sqlite3_stmt * stmt_ins,
4048 sqlite3_int64 edge_id, const unsigned char *blob,
4049 int blob_sz)
4050 {
4051 /* retrieving LineEdge relationships */
4052 int ret;
4053 int count = 0;
4054 char direction[2];
4055 strcpy (direction, "?");
4056
4057 sqlite3_reset (stmt_ref);
4058 sqlite3_clear_bindings (stmt_ref);
4059 sqlite3_bind_blob (stmt_ref, 1, blob, blob_sz, SQLITE_STATIC);
4060 sqlite3_bind_blob (stmt_ref, 2, blob, blob_sz, SQLITE_STATIC);
4061
4062 while (1)
4063 {
4064 /* scrolling the result set rows - Spatial Relationships */
4065 ret = sqlite3_step (stmt_ref);
4066 if (ret == SQLITE_DONE)
4067 break; /* end of result set */
4068 if (ret == SQLITE_ROW)
4069 {
4070 int overlaps = 0;
4071 int covers = 0;
4072 int covered_by = 0;
4073 sqlite3_int64 rowid = sqlite3_column_int64 (stmt_ref, 0);
4074 const char *matrix =
4075 (const char *) sqlite3_column_text (stmt_ref, 1);
4076 if (gaia_do_eval_disjoint (topo->db_handle, matrix))
4077 continue;
4078 overlaps = gaia_do_eval_overlaps (topo->db_handle, matrix);
4079 covers = gaia_do_eval_covers (topo->db_handle, matrix);
4080 covered_by = gaia_do_eval_covered_by (topo->db_handle, matrix);
4081 if (!overlaps && !covers && !covered_by)
4082 continue;
4083
4084 if (sqlite3_column_type (stmt_ref, 2) == SQLITE_BLOB)
4085 {
4086 /* testing directions */
4087 gaiaGeomCollPtr geom_edge = NULL;
4088 gaiaGeomCollPtr geom_line = NULL;
4089 const unsigned char *blob2 =
4090 sqlite3_column_blob (stmt_ref, 2);
4091 int blob2_sz = sqlite3_column_bytes (stmt_ref, 2);
4092 geom_edge = gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
4093 geom_line = gaiaFromSpatiaLiteBlobWkb (blob2, blob2_sz);
4094 if (geom_edge != NULL && geom_line != NULL)
4095 gaia_do_check_direction (geom_edge, geom_line,
4096 direction);
4097 if (geom_edge != NULL)
4098 gaiaFreeGeomColl (geom_edge);
4099 if (geom_line != NULL)
4100 gaiaFreeGeomColl (geom_line);
4101 }
4102
4103 sqlite3_reset (stmt_ins);
4104 sqlite3_clear_bindings (stmt_ins);
4105 sqlite3_bind_int64 (stmt_ins, 1, edge_id);
4106 sqlite3_bind_int64 (stmt_ins, 2, rowid);
4107 sqlite3_bind_text (stmt_ins, 3, direction, 1, SQLITE_STATIC);
4108 sqlite3_bind_text (stmt_ins, 4, matrix, strlen (matrix),
4109 SQLITE_STATIC);
4110 sqlite3_bind_int (stmt_ins, 5, overlaps);
4111 sqlite3_bind_int (stmt_ins, 6, covers);
4112 sqlite3_bind_int (stmt_ins, 7, covered_by);
4113 /* inserting a row into the output table */
4114 ret = sqlite3_step (stmt_ins);
4115 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
4116 count++;
4117 else
4118 {
4119 char *msg =
4120 sqlite3_mprintf ("LineEdgesList error: \"%s\"",
4121 sqlite3_errmsg (topo->db_handle));
4122 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr)
4123 topo, msg);
4124 sqlite3_free (msg);
4125 return 0;
4126 }
4127 }
4128 else
4129 {
4130 char *msg = sqlite3_mprintf ("LineEdgesList error: \"%s\"",
4131 sqlite3_errmsg (topo->db_handle));
4132 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
4133 msg);
4134 sqlite3_free (msg);
4135 return 0;
4136 }
4137 }
4138
4139 if (count == 0)
4140 {
4141 /* unrelated Edge */
4142 sqlite3_reset (stmt_ins);
4143 sqlite3_clear_bindings (stmt_ins);
4144 sqlite3_bind_int64 (stmt_ins, 1, edge_id);
4145 sqlite3_bind_null (stmt_ins, 2);
4146 sqlite3_bind_null (stmt_ins, 3);
4147 sqlite3_bind_null (stmt_ins, 4);
4148 sqlite3_bind_null (stmt_ins, 5);
4149 sqlite3_bind_null (stmt_ins, 6);
4150 sqlite3_bind_null (stmt_ins, 7);
4151 /* inserting a row into the output table */
4152 ret = sqlite3_step (stmt_ins);
4153 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
4154 ;
4155 else
4156 {
4157 char *msg = sqlite3_mprintf ("LineEdgesList error: \"%s\"",
4158 sqlite3_errmsg (topo->db_handle));
4159 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
4160 msg);
4161 sqlite3_free (msg);
4162 return 0;
4163 }
4164 }
4165 return 1;
4166 }
4167
4168 GAIATOPO_DECLARE int
gaiaTopoGeo_LineEdgesList(GaiaTopologyAccessorPtr accessor,const char * db_prefix,const char * ref_table,const char * ref_column,const char * out_table)4169 gaiaTopoGeo_LineEdgesList (GaiaTopologyAccessorPtr accessor,
4170 const char *db_prefix, const char *ref_table,
4171 const char *ref_column, const char *out_table)
4172 {
4173 /* creating and populating a new Table reporting about Edges/Linestring correspondencies */
4174 struct gaia_topology *topo = (struct gaia_topology *) accessor;
4175 sqlite3_stmt *stmt_edges = NULL;
4176 sqlite3_stmt *stmt_ref = NULL;
4177 sqlite3_stmt *stmt_ins = NULL;
4178 int ret;
4179 char *sql;
4180 char *table;
4181 char *idx_name;
4182 char *xtable;
4183 char *xprefix;
4184 char *xcolumn;
4185 char *xidx_name;
4186 char *rtree_name;
4187 int ref_has_spatial_index = 0;
4188 if (topo == NULL)
4189 return 0;
4190
4191 /* attempting to build the output table */
4192 xtable = gaiaDoubleQuotedSql (out_table);
4193 sql = sqlite3_mprintf ("CREATE TABLE main.\"%s\" (\n"
4194 "\tid INTEGER PRIMARY KEY AUTOINCREMENT,\n"
4195 "\tedge_id INTEGER NOT NULL,\n"
4196 "\tref_rowid INTEGER,\n"
4197 "\tdirection TEXT,\n"
4198 "\tmatrix TEXT,\n"
4199 "\toverlaps INTEGER,\n"
4200 "\tcovers INTEGER,\n"
4201 "\tcovered_by INTEGER)", xtable);
4202 free (xtable);
4203 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, NULL);
4204 sqlite3_free (sql);
4205 if (ret != SQLITE_OK)
4206 {
4207 char *msg = sqlite3_mprintf ("LineEdgesList error: \"%s\"",
4208 sqlite3_errmsg (topo->db_handle));
4209 gaiatopo_set_last_error_msg (accessor, msg);
4210 sqlite3_free (msg);
4211 goto error;
4212 }
4213 idx_name = sqlite3_mprintf ("idx_%s_edge_id", out_table);
4214 xidx_name = gaiaDoubleQuotedSql (idx_name);
4215 sqlite3_free (idx_name);
4216 xtable = gaiaDoubleQuotedSql (out_table);
4217 sql =
4218 sqlite3_mprintf
4219 ("CREATE INDEX main.\"%s\" ON \"%s\" (edge_id, ref_rowid)", xidx_name,
4220 xtable);
4221 free (xidx_name);
4222 free (xtable);
4223 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, NULL);
4224 sqlite3_free (sql);
4225 if (ret != SQLITE_OK)
4226 {
4227 char *msg = sqlite3_mprintf ("LineEdgesList error: \"%s\"",
4228 sqlite3_errmsg (topo->db_handle));
4229 gaiatopo_set_last_error_msg (accessor, msg);
4230 sqlite3_free (msg);
4231 goto error;
4232 }
4233
4234 /* building the Edges SQL statement */
4235 table = sqlite3_mprintf ("%s_edge", topo->topology_name);
4236 xtable = gaiaDoubleQuotedSql (table);
4237 sqlite3_free (table);
4238 sql = sqlite3_mprintf ("SELECT edge_id, geom FROM main.\"%s\"", xtable);
4239 free (xtable);
4240 ret =
4241 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_edges,
4242 NULL);
4243 sqlite3_free (sql);
4244 if (ret != SQLITE_OK)
4245 {
4246 char *msg = sqlite3_mprintf ("LineEdgesList error: \"%s\"",
4247 sqlite3_errmsg (topo->db_handle));
4248 gaiatopo_set_last_error_msg (accessor, msg);
4249 sqlite3_free (msg);
4250 goto error;
4251 }
4252
4253 /* building the RefTable SQL statement */
4254 rtree_name = sqlite3_mprintf ("DB=%s.%s", db_prefix, ref_table);
4255 ref_has_spatial_index =
4256 gaia_check_spatial_index (topo->db_handle, db_prefix, ref_table,
4257 ref_column);
4258 xprefix = gaiaDoubleQuotedSql (db_prefix);
4259 xtable = gaiaDoubleQuotedSql (ref_table);
4260 xcolumn = gaiaDoubleQuotedSql (ref_column);
4261 if (ref_has_spatial_index)
4262 sql =
4263 sqlite3_mprintf
4264 ("SELECT rowid, ST_Relate(?, \"%s\"), \"%s\" FROM \"%s\".\"%s\" "
4265 "WHERE rowid IN ("
4266 "SELECT rowid FROM SpatialIndex WHERE f_table_name = %Q AND "
4267 "f_geometry_column = %Q AND search_frame = ?)", xcolumn, xcolumn,
4268 xprefix, xtable, rtree_name, ref_column);
4269 else
4270 sql =
4271 sqlite3_mprintf
4272 ("SELECT rowid, ST_Relate(?, \"%s\"), \"%s\" FROM \"%s\".\"%s\" "
4273 "WHERE MbrIntersects(?, \"%s\")", xcolumn, xcolumn, xprefix,
4274 xtable, xcolumn);
4275 free (xprefix);
4276 free (xtable);
4277 free (xcolumn);
4278 sqlite3_free (rtree_name);
4279 ret =
4280 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_ref,
4281 NULL);
4282 sqlite3_free (sql);
4283 if (ret != SQLITE_OK)
4284 {
4285 char *msg = sqlite3_mprintf ("LineEdgesList error: \"%s\"",
4286 sqlite3_errmsg (topo->db_handle));
4287 gaiatopo_set_last_error_msg (accessor, msg);
4288 sqlite3_free (msg);
4289 goto error;
4290 }
4291
4292 /* building the Insert SQL statement */
4293 xtable = gaiaDoubleQuotedSql (out_table);
4294 sql = sqlite3_mprintf ("INSERT INTO main.\"%s\" (id, edge_id, ref_rowid, "
4295 "direction, matrix, overlaps, covers, covered_by) "
4296 "VALUES (NULL, ?, ?, ?, ?, ?, ?, ?)", xtable);
4297 free (xtable);
4298 ret =
4299 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_ins,
4300 NULL);
4301 sqlite3_free (sql);
4302 if (ret != SQLITE_OK)
4303 {
4304 char *msg = sqlite3_mprintf ("LineEdgesList error: \"%s\"",
4305 sqlite3_errmsg (topo->db_handle));
4306 gaiatopo_set_last_error_msg (accessor, msg);
4307 sqlite3_free (msg);
4308 goto error;
4309 }
4310
4311 while (1)
4312 {
4313 /* scrolling the result set rows - Edges */
4314 ret = sqlite3_step (stmt_edges);
4315 if (ret == SQLITE_DONE)
4316 break; /* end of result set */
4317 if (ret == SQLITE_ROW)
4318 {
4319 sqlite3_int64 edge_id = sqlite3_column_int64 (stmt_edges, 0);
4320 if (sqlite3_column_type (stmt_edges, 1) == SQLITE_BLOB)
4321 {
4322 if (!find_lineedge_relationships
4323 (topo, stmt_ref, stmt_ins, edge_id,
4324 sqlite3_column_blob (stmt_edges, 1),
4325 sqlite3_column_bytes (stmt_edges, 1)))
4326 goto error;
4327 }
4328 else
4329 {
4330 char *msg =
4331 sqlite3_mprintf
4332 ("LineEdgesList error: Edge not a BLOB value");
4333 gaiatopo_set_last_error_msg (accessor, msg);
4334 sqlite3_free (msg);
4335 goto error;
4336 }
4337 }
4338 else
4339 {
4340 char *msg = sqlite3_mprintf ("LineEdgesList error: \"%s\"",
4341 sqlite3_errmsg (topo->db_handle));
4342 gaiatopo_set_last_error_msg (accessor, msg);
4343 sqlite3_free (msg);
4344 goto error;
4345 }
4346 }
4347
4348 sqlite3_finalize (stmt_edges);
4349 sqlite3_finalize (stmt_ref);
4350 sqlite3_finalize (stmt_ins);
4351 return 1;
4352
4353 error:
4354 if (stmt_edges != NULL)
4355 sqlite3_finalize (stmt_edges);
4356 if (stmt_ref != NULL)
4357 sqlite3_finalize (stmt_ref);
4358 if (stmt_ins != NULL)
4359 sqlite3_finalize (stmt_ins);
4360 return 0;
4361 }
4362
4363 static struct face_item *
create_face_item(sqlite3_int64 face_id)4364 create_face_item (sqlite3_int64 face_id)
4365 {
4366 /* creating a Face Item */
4367 struct face_item *item = malloc (sizeof (struct face_item));
4368 item->face_id = face_id;
4369 item->next = NULL;
4370 return item;
4371 }
4372
4373 static void
destroy_face_item(struct face_item * item)4374 destroy_face_item (struct face_item *item)
4375 {
4376 /* destroying a Face Item */
4377 if (item == NULL)
4378 return;
4379 free (item);
4380 }
4381
4382 static struct face_edge_item *
create_face_edge_item(sqlite3_int64 edge_id,sqlite3_int64 left_face,sqlite3_int64 right_face,gaiaGeomCollPtr geom)4383 create_face_edge_item (sqlite3_int64 edge_id, sqlite3_int64 left_face,
4384 sqlite3_int64 right_face, gaiaGeomCollPtr geom)
4385 {
4386 /* creating a Face-Edge Item */
4387 struct face_edge_item *item = malloc (sizeof (struct face_edge_item));
4388 item->edge_id = edge_id;
4389 item->left_face = left_face;
4390 item->right_face = right_face;
4391 item->geom = geom;
4392 item->count = 0;
4393 item->next = NULL;
4394 return item;
4395 }
4396
4397 static void
destroy_face_edge_item(struct face_edge_item * item)4398 destroy_face_edge_item (struct face_edge_item *item)
4399 {
4400 /* destroying a Face-Edge Item */
4401 if (item == NULL)
4402 return;
4403 if (item->geom != NULL)
4404 gaiaFreeGeomColl (item->geom);
4405 free (item);
4406 }
4407
4408 TOPOLOGY_PRIVATE struct face_edges *
auxtopo_create_face_edges(int has_z,int srid)4409 auxtopo_create_face_edges (int has_z, int srid)
4410 {
4411 /* creating an empty Face-Edges list */
4412 struct face_edges *list = malloc (sizeof (struct face_edges));
4413 list->has_z = has_z;
4414 list->srid = srid;
4415 list->first_edge = NULL;
4416 list->last_edge = NULL;
4417 list->first_face = NULL;
4418 list->last_face = NULL;
4419 return list;
4420 }
4421
4422 TOPOLOGY_PRIVATE void
auxtopo_free_face_edges(struct face_edges * list)4423 auxtopo_free_face_edges (struct face_edges *list)
4424 {
4425 /* destroying a Face-Edges list */
4426 struct face_edge_item *fe;
4427 struct face_edge_item *fen;
4428 struct face_item *f;
4429 struct face_item *fn;
4430 if (list == NULL)
4431 return;
4432
4433 fe = list->first_edge;
4434 while (fe != NULL)
4435 {
4436 /* destroying all Face-Edge items */
4437 fen = fe->next;
4438 destroy_face_edge_item (fe);
4439 fe = fen;
4440 }
4441 f = list->first_face;
4442 while (f != NULL)
4443 {
4444 /* destroying all Face items */
4445 fn = f->next;
4446 destroy_face_item (f);
4447 f = fn;
4448 }
4449 free (list);
4450 }
4451
4452 TOPOLOGY_PRIVATE void
auxtopo_add_face_edge(struct face_edges * list,sqlite3_int64 face_id,sqlite3_int64 edge_id,sqlite3_int64 left_face,sqlite3_int64 right_face,gaiaGeomCollPtr geom)4453 auxtopo_add_face_edge (struct face_edges *list, sqlite3_int64 face_id,
4454 sqlite3_int64 edge_id, sqlite3_int64 left_face,
4455 sqlite3_int64 right_face, gaiaGeomCollPtr geom)
4456 {
4457 /* adding a Face-Edge Item into the list */
4458 struct face_item *f;
4459 struct face_edge_item *fe =
4460 create_face_edge_item (edge_id, left_face, right_face, geom);
4461 if (list->first_edge == NULL)
4462 list->first_edge = fe;
4463 if (list->last_edge != NULL)
4464 list->last_edge->next = fe;
4465 list->last_edge = fe;
4466
4467 f = list->first_face;
4468 while (f != NULL)
4469 {
4470 if (f->face_id == face_id)
4471 return;
4472 f = f->next;
4473 }
4474
4475 /* inserting the Face-ID into the list */
4476 f = create_face_item (face_id);
4477 if (list->first_face == NULL)
4478 list->first_face = f;
4479 if (list->last_face != NULL)
4480 list->last_face->next = f;
4481 list->last_face = f;
4482 }
4483
4484 TOPOLOGY_PRIVATE void
auxtopo_select_valid_face_edges(struct face_edges * list)4485 auxtopo_select_valid_face_edges (struct face_edges *list)
4486 {
4487 /* identifying all useless Edges */
4488 struct face_edge_item *fe = list->first_edge;
4489 while (fe != NULL)
4490 {
4491 struct face_item *f = list->first_face;
4492 while (f != NULL)
4493 {
4494 if (f->face_id == fe->left_face)
4495 fe->count += 1;
4496 if (f->face_id == fe->right_face)
4497 fe->count += 1;
4498 f = f->next;
4499 }
4500 fe = fe->next;
4501 }
4502 }
4503
4504 TOPOLOGY_PRIVATE gaiaGeomCollPtr
auxtopo_polygonize_face_edges(struct face_edges * list,const void * cache)4505 auxtopo_polygonize_face_edges (struct face_edges *list, const void *cache)
4506 {
4507 /* attempting to reaggregrate Polygons from valid Edges */
4508 gaiaGeomCollPtr sparse;
4509 gaiaGeomCollPtr rearranged;
4510 struct face_edge_item *fe;
4511
4512 if (list->has_z)
4513 sparse = gaiaAllocGeomCollXYZ ();
4514 else
4515 sparse = gaiaAllocGeomColl ();
4516 sparse->Srid = list->srid;
4517
4518 fe = list->first_edge;
4519 while (fe != NULL)
4520 {
4521 if (fe->count < 2)
4522 {
4523 /* found a valid Edge: adding to the MultiListring */
4524 gaiaLinestringPtr ln = fe->geom->FirstLinestring;
4525 while (ln != NULL)
4526 {
4527 if (list->has_z)
4528 auxtopo_copy_linestring3d (ln, sparse);
4529 else
4530 auxtopo_copy_linestring (ln, sparse);
4531 ln = ln->Next;
4532 }
4533 }
4534 fe = fe->next;
4535 }
4536 rearranged = gaiaPolygonize_r (cache, sparse, 0);
4537 gaiaFreeGeomColl (sparse);
4538 return rearranged;
4539 }
4540
4541 TOPOLOGY_PRIVATE gaiaGeomCollPtr
auxtopo_polygonize_face_edges_generalize(struct face_edges * list,const void * cache)4542 auxtopo_polygonize_face_edges_generalize (struct face_edges *list,
4543 const void *cache)
4544 {
4545 /* attempting to reaggregrate Polygons from valid Edges */
4546 gaiaGeomCollPtr sparse;
4547 gaiaGeomCollPtr renoded;
4548 gaiaGeomCollPtr rearranged;
4549 struct face_edge_item *fe;
4550
4551 if (list->has_z)
4552 sparse = gaiaAllocGeomCollXYZ ();
4553 else
4554 sparse = gaiaAllocGeomColl ();
4555 sparse->Srid = list->srid;
4556
4557 fe = list->first_edge;
4558 while (fe != NULL)
4559 {
4560 if (fe->count < 2)
4561 {
4562 /* found a valid Edge: adding to the MultiListring */
4563 gaiaLinestringPtr ln = fe->geom->FirstLinestring;
4564 while (ln != NULL)
4565 {
4566 if (list->has_z)
4567 auxtopo_copy_linestring3d (ln, sparse);
4568 else
4569 auxtopo_copy_linestring (ln, sparse);
4570 ln = ln->Next;
4571 }
4572 }
4573 fe = fe->next;
4574 }
4575 renoded = gaiaNodeLines (cache, sparse);
4576 gaiaFreeGeomColl (sparse);
4577 if (renoded == NULL)
4578 return NULL;
4579 rearranged = gaiaPolygonize_r (cache, renoded, 0);
4580 gaiaFreeGeomColl (renoded);
4581 return rearranged;
4582 }
4583
4584 TOPOLOGY_PRIVATE gaiaGeomCollPtr
auxtopo_make_geom_from_point(int srid,int has_z,gaiaPointPtr pt)4585 auxtopo_make_geom_from_point (int srid, int has_z, gaiaPointPtr pt)
4586 {
4587 /* quick constructor: Geometry based on external point */
4588 gaiaGeomCollPtr reference;
4589 if (has_z)
4590 reference = gaiaAllocGeomCollXYZ ();
4591 else
4592 reference = gaiaAllocGeomColl ();
4593 reference->Srid = srid;
4594 pt->Next = NULL;
4595 reference->FirstPoint = pt;
4596 reference->LastPoint = pt;
4597 return reference;
4598 }
4599
4600 TOPOLOGY_PRIVATE gaiaGeomCollPtr
auxtopo_make_geom_from_line(int srid,gaiaLinestringPtr ln)4601 auxtopo_make_geom_from_line (int srid, gaiaLinestringPtr ln)
4602 {
4603 /* quick constructor: Geometry based on external line */
4604 gaiaGeomCollPtr reference;
4605 if (ln->DimensionModel == GAIA_XY_Z_M)
4606 reference = gaiaAllocGeomCollXYZM ();
4607 else if (ln->DimensionModel == GAIA_XY_Z)
4608 reference = gaiaAllocGeomCollXYZ ();
4609 else if (ln->DimensionModel == GAIA_XY_M)
4610 reference = gaiaAllocGeomCollXYM ();
4611 else
4612 reference = gaiaAllocGeomColl ();
4613 reference->Srid = srid;
4614 ln->Next = NULL;
4615 reference->FirstLinestring = ln;
4616 reference->LastLinestring = ln;
4617 return reference;
4618 }
4619
4620 TOPOLOGY_PRIVATE void
auxtopo_copy_linestring3d(gaiaLinestringPtr in,gaiaGeomCollPtr geom)4621 auxtopo_copy_linestring3d (gaiaLinestringPtr in, gaiaGeomCollPtr geom)
4622 {
4623 /* inserting/copying a Linestring 3D into another Geometry */
4624 int iv;
4625 double x;
4626 double y;
4627 double z;
4628 gaiaLinestringPtr out = gaiaAddLinestringToGeomColl (geom, in->Points);
4629 for (iv = 0; iv < in->Points; iv++)
4630 {
4631 gaiaGetPointXYZ (in->Coords, iv, &x, &y, &z);
4632 gaiaSetPointXYZ (out->Coords, iv, x, y, z);
4633 }
4634 }
4635
4636 TOPOLOGY_PRIVATE void
auxtopo_copy_linestring(gaiaLinestringPtr in,gaiaGeomCollPtr geom)4637 auxtopo_copy_linestring (gaiaLinestringPtr in, gaiaGeomCollPtr geom)
4638 {
4639 /* inserting/copying a Linestring into another Geometry */
4640 int iv;
4641 double x;
4642 double y;
4643 gaiaLinestringPtr out = gaiaAddLinestringToGeomColl (geom, in->Points);
4644 for (iv = 0; iv < in->Points; iv++)
4645 {
4646 gaiaGetPoint (in->Coords, iv, &x, &y);
4647 gaiaSetPoint (out->Coords, iv, x, y);
4648 }
4649 }
4650
4651 TOPOLOGY_PRIVATE void
auxtopo_destroy_geom_from(gaiaGeomCollPtr reference)4652 auxtopo_destroy_geom_from (gaiaGeomCollPtr reference)
4653 {
4654 /* safely destroying a reference geometry */
4655 if (reference == NULL)
4656 return;
4657
4658 /* releasing ownership on external points, lines and polygs */
4659 reference->FirstPoint = NULL;
4660 reference->LastPoint = NULL;
4661 reference->FirstLinestring = NULL;
4662 reference->LastLinestring = NULL;
4663 reference->FirstPolygon = NULL;
4664 reference->LastPolygon = NULL;
4665
4666 gaiaFreeGeomColl (reference);
4667 }
4668
4669 TOPOLOGY_PRIVATE int
auxtopo_retrieve_geometry_type(sqlite3 * db_handle,const char * db_prefix,const char * table,const char * column,int * ref_type)4670 auxtopo_retrieve_geometry_type (sqlite3 * db_handle, const char *db_prefix,
4671 const char *table, const char *column,
4672 int *ref_type)
4673 {
4674 /* attempting to retrieve the reference Geometry Type */
4675 int ret;
4676 int i;
4677 char **results;
4678 int rows;
4679 int columns;
4680 char *errMsg = NULL;
4681 char *sql;
4682 char *xprefix;
4683 int type = -1;
4684
4685 /* querying GEOMETRY_COLUMNS */
4686 xprefix = gaiaDoubleQuotedSql (db_prefix);
4687 sql =
4688 sqlite3_mprintf
4689 ("SELECT geometry_type "
4690 "FROM \"%s\".geometry_columns WHERE Lower(f_table_name) = Lower(%Q) AND "
4691 "Lower(f_geometry_column) = Lower(%Q)", xprefix, table, column);
4692 free (xprefix);
4693 ret =
4694 sqlite3_get_table (db_handle, sql, &results, &rows, &columns, &errMsg);
4695 sqlite3_free (sql);
4696 if (ret != SQLITE_OK)
4697 {
4698 sqlite3_free (errMsg);
4699 return 0;
4700 }
4701 for (i = 1; i <= rows; i++)
4702 {
4703 type = atoi (results[(i * columns) + 0]);
4704 }
4705 sqlite3_free_table (results);
4706
4707 if (type < 0)
4708 return 0;
4709
4710 *ref_type = type;
4711 return 1;
4712 }
4713
4714 TOPOLOGY_PRIVATE int
auxtopo_create_togeotable_sql(sqlite3 * db_handle,const char * db_prefix,const char * ref_table,const char * ref_column,const char * out_table,char ** xcreate,char ** xselect,char ** xinsert,int * ref_geom_col)4715 auxtopo_create_togeotable_sql (sqlite3 * db_handle, const char *db_prefix,
4716 const char *ref_table, const char *ref_column,
4717 const char *out_table, char **xcreate,
4718 char **xselect, char **xinsert,
4719 int *ref_geom_col)
4720 {
4721 /* composing the CREATE TABLE output-table statement */
4722 char *create = NULL;
4723 char *select = NULL;
4724 char *insert = NULL;
4725 char *prev;
4726 char *sql;
4727 char *xprefix;
4728 char *xtable;
4729 int i;
4730 char **results;
4731 int rows;
4732 int columns;
4733 const char *name;
4734 const char *type;
4735 int notnull;
4736 int pk_no;
4737 int ret;
4738 int first_create = 1;
4739 int first_select = 1;
4740 int first_insert = 1;
4741 int npk = 0;
4742 int ipk;
4743 int ncols = 0;
4744 int icol;
4745 int ref_col = 0;
4746 int xref_geom_col;
4747
4748 *xcreate = NULL;
4749 *xselect = NULL;
4750 *xinsert = NULL;
4751 *ref_geom_col = -1;
4752
4753 xtable = gaiaDoubleQuotedSql (out_table);
4754 create = sqlite3_mprintf ("CREATE TABLE MAIN.\"%s\" (", xtable);
4755 select = sqlite3_mprintf ("SELECT ");
4756 insert = sqlite3_mprintf ("INSERT INTO MAIN.\"%s\" (", xtable);
4757 free (xtable);
4758
4759 xprefix = gaiaDoubleQuotedSql (db_prefix);
4760 xtable = gaiaDoubleQuotedSql (ref_table);
4761 sql = sqlite3_mprintf ("PRAGMA \"%s\".table_info(\"%s\")", xprefix, xtable);
4762 free (xprefix);
4763 free (xtable);
4764 ret = sqlite3_get_table (db_handle, sql, &results, &rows, &columns, NULL);
4765 sqlite3_free (sql);
4766 if (ret != SQLITE_OK)
4767 goto error;
4768 if (rows < 1)
4769 ;
4770 else
4771 {
4772 for (i = 1; i <= rows; i++)
4773 {
4774 /* counting how many PK columns are there */
4775 if (atoi (results[(i * columns) + 5]) != 0)
4776 npk++;
4777 }
4778 for (i = 1; i <= rows; i++)
4779 {
4780 name = results[(i * columns) + 1];
4781 type = results[(i * columns) + 2];
4782 notnull = atoi (results[(i * columns) + 3]);
4783 pk_no = atoi (results[(i * columns) + 5]);
4784 /* SELECT: adding a column */
4785 xprefix = gaiaDoubleQuotedSql (name);
4786 prev = select;
4787 if (first_select)
4788 select = sqlite3_mprintf ("%s\"%s\"", prev, xprefix);
4789 else
4790 select = sqlite3_mprintf ("%s, \"%s\"", prev, xprefix);
4791 first_select = 0;
4792 free (xprefix);
4793 sqlite3_free (prev);
4794 if (strcasecmp (name, ref_column) == 0)
4795 {
4796 /* saving the index of ref-geometry */
4797 xref_geom_col = ref_col;
4798 }
4799 ref_col++;
4800 /* INSERT: adding a column */
4801 xprefix = gaiaDoubleQuotedSql (name);
4802 prev = insert;
4803 if (first_insert)
4804 insert = sqlite3_mprintf ("%s\"%s\"", prev, xprefix);
4805 else
4806 insert = sqlite3_mprintf ("%s, \"%s\"", prev, xprefix);
4807 first_insert = 0;
4808 free (xprefix);
4809 sqlite3_free (prev);
4810 ncols++;
4811 /* CREATE: adding a column definition */
4812 if (strcasecmp (name, ref_column) == 0)
4813 {
4814 /* skipping the geometry column */
4815 continue;
4816 }
4817 prev = create;
4818 xprefix = gaiaDoubleQuotedSql (name);
4819 if (first_create)
4820 {
4821 first_create = 0;
4822 if (notnull)
4823 create =
4824 sqlite3_mprintf ("%s\n\t\"%s\" %s NOT NULL", prev,
4825 xprefix, type);
4826 else
4827 create =
4828 sqlite3_mprintf ("%s\n\t\"%s\" %s", prev, xprefix,
4829 type);
4830 }
4831 else
4832 {
4833 if (notnull)
4834 create =
4835 sqlite3_mprintf ("%s,\n\t\"%s\" %s NOT NULL",
4836 prev, xprefix, type);
4837 else
4838 create =
4839 sqlite3_mprintf ("%s,\n\t\"%s\" %s", prev,
4840 xprefix, type);
4841 }
4842 free (xprefix);
4843 sqlite3_free (prev);
4844 if (npk == 1 && pk_no != 0)
4845 {
4846 /* declaring a single-column Primary Key */
4847 prev = create;
4848 create = sqlite3_mprintf ("%s PRIMARY KEY", prev);
4849 sqlite3_free (prev);
4850 }
4851 }
4852 if (npk > 1)
4853 {
4854 /* declaring a multi-column Primary Key */
4855 prev = create;
4856 sql = sqlite3_mprintf ("pk_%s", out_table);
4857 xprefix = gaiaDoubleQuotedSql (sql);
4858 sqlite3_free (sql);
4859 create =
4860 sqlite3_mprintf ("%s,\n\tCONSTRAINT \"%s\" PRIMARY KEY (",
4861 prev, xprefix);
4862 free (xprefix);
4863 sqlite3_free (prev);
4864 for (ipk = 1; ipk <= npk; ipk++)
4865 {
4866 /* searching a Primary Key column */
4867 for (i = 1; i <= rows; i++)
4868 {
4869 if (atoi (results[(i * columns) + 5]) == ipk)
4870 {
4871 /* declaring a Primary Key column */
4872 name = results[(i * columns) + 1];
4873 xprefix = gaiaDoubleQuotedSql (name);
4874 prev = create;
4875 if (ipk == 1)
4876 create =
4877 sqlite3_mprintf ("%s\"%s\"", prev,
4878 xprefix);
4879 else
4880 create =
4881 sqlite3_mprintf ("%s, \"%s\"", prev,
4882 xprefix);
4883 free (xprefix);
4884 sqlite3_free (prev);
4885 }
4886 }
4887 }
4888 prev = create;
4889 create = sqlite3_mprintf ("%s)", prev);
4890 sqlite3_free (prev);
4891 }
4892 }
4893 sqlite3_free_table (results);
4894
4895 /* completing the SQL statements */
4896 prev = create;
4897 create = sqlite3_mprintf ("%s)", prev);
4898 sqlite3_free (prev);
4899 prev = select;
4900 xprefix = gaiaDoubleQuotedSql (db_prefix);
4901 xtable = gaiaDoubleQuotedSql (ref_table);
4902 select = sqlite3_mprintf ("%s FROM \"%s\".\"%s\"", prev, xprefix, xtable);
4903 free (xprefix);
4904 free (xtable);
4905 sqlite3_free (prev);
4906 prev = insert;
4907 insert = sqlite3_mprintf ("%s) VALUES (", prev);
4908 sqlite3_free (prev);
4909 for (icol = 0; icol < ncols; icol++)
4910 {
4911 prev = insert;
4912 if (icol == 0)
4913 insert = sqlite3_mprintf ("%s?", prev);
4914 else
4915 insert = sqlite3_mprintf ("%s, ?", prev);
4916 sqlite3_free (prev);
4917 }
4918 prev = insert;
4919 insert = sqlite3_mprintf ("%s)", prev);
4920 sqlite3_free (prev);
4921
4922 *xcreate = create;
4923 *xselect = select;
4924 *xinsert = insert;
4925 *ref_geom_col = xref_geom_col;
4926 return 1;
4927
4928 error:
4929 if (create != NULL)
4930 sqlite3_free (create);
4931 if (select != NULL)
4932 sqlite3_free (select);
4933 if (insert != NULL)
4934 sqlite3_free (insert);
4935 return 0;
4936 }
4937
4938 static int
is_geometry_column(sqlite3 * db_handle,const char * db_prefix,const char * table,const char * column)4939 is_geometry_column (sqlite3 * db_handle, const char *db_prefix,
4940 const char *table, const char *column)
4941 {
4942 /* testing for Geometry columns */
4943 int ret;
4944 int i;
4945 char **results;
4946 int rows;
4947 int columns;
4948 char *errMsg = NULL;
4949 char *sql;
4950 char *xprefix;
4951 int count = 0;
4952
4953 /* querying GEOMETRY_COLUMNS */
4954 xprefix = gaiaDoubleQuotedSql (db_prefix);
4955 sql =
4956 sqlite3_mprintf
4957 ("SELECT Count(*) "
4958 "FROM \"%s\".geometry_columns WHERE Lower(f_table_name) = Lower(%Q) AND "
4959 "Lower(f_geometry_column) = Lower(%Q)", xprefix, table, column);
4960 free (xprefix);
4961 ret =
4962 sqlite3_get_table (db_handle, sql, &results, &rows, &columns, &errMsg);
4963 sqlite3_free (sql);
4964 if (ret != SQLITE_OK)
4965 {
4966 sqlite3_free (errMsg);
4967 return 0;
4968 }
4969 for (i = 1; i <= rows; i++)
4970 {
4971 count = atoi (results[(i * columns) + 0]);
4972 }
4973 sqlite3_free_table (results);
4974
4975 if (count > 0)
4976 return 1;
4977 return 0;
4978 }
4979
4980 static int
auxtopo_create_features_sql(sqlite3 * db_handle,const char * db_prefix,const char * ref_table,const char * ref_column,const char * topology_name,sqlite3_int64 topolayer_id,char ** xcreate,char ** xselect,char ** xinsert)4981 auxtopo_create_features_sql (sqlite3 * db_handle, const char *db_prefix,
4982 const char *ref_table, const char *ref_column,
4983 const char *topology_name,
4984 sqlite3_int64 topolayer_id, char **xcreate,
4985 char **xselect, char **xinsert)
4986 {
4987 /* composing the CREATE TABLE fatures-table statement */
4988 char *create = NULL;
4989 char *select = NULL;
4990 char *insert = NULL;
4991 char *prev;
4992 char *sql;
4993 char *xprefix;
4994 char *xgeom;
4995 char *table;
4996 char *xtable;
4997 char dummy[64];
4998 int i;
4999 char **results;
5000 int rows;
5001 int columns;
5002 const char *name;
5003 const char *type;
5004 int notnull;
5005 int ret;
5006 int first_select = 1;
5007 int first_insert = 1;
5008 int ncols = 0;
5009 int icol;
5010 int ref_col = 0;
5011
5012 *xcreate = NULL;
5013 *xselect = NULL;
5014 *xinsert = NULL;
5015
5016 sprintf (dummy, "%lld", topolayer_id);
5017 table = sqlite3_mprintf ("%s_topofeatures_%s", topology_name, dummy);
5018 xtable = gaiaDoubleQuotedSql (table);
5019 sqlite3_free (table);
5020 create =
5021 sqlite3_mprintf
5022 ("CREATE TABLE MAIN.\"%s\" (\n\tfid INTEGER PRIMARY KEY AUTOINCREMENT",
5023 xtable);
5024 select = sqlite3_mprintf ("SELECT ");
5025 insert = sqlite3_mprintf ("INSERT INTO MAIN.\"%s\" (", xtable);
5026 free (xtable);
5027
5028 xprefix = gaiaDoubleQuotedSql (db_prefix);
5029 xtable = gaiaDoubleQuotedSql (ref_table);
5030 sql = sqlite3_mprintf ("PRAGMA \"%s\".table_info(\"%s\")", xprefix, xtable);
5031 free (xprefix);
5032 free (xtable);
5033 ret = sqlite3_get_table (db_handle, sql, &results, &rows, &columns, NULL);
5034 sqlite3_free (sql);
5035 if (ret != SQLITE_OK)
5036 goto error;
5037 if (rows < 1)
5038 ;
5039 else
5040 {
5041 for (i = 1; i <= rows; i++)
5042 {
5043 name = results[(i * columns) + 1];
5044 type = results[(i * columns) + 2];
5045 notnull = atoi (results[(i * columns) + 3]);
5046 if (strcasecmp (name, "fid") == 0)
5047 continue;
5048 if (is_geometry_column (db_handle, db_prefix, ref_table, name))
5049 continue;
5050 if (ref_column != NULL)
5051 {
5052 if (strcasecmp (ref_column, name) == 0)
5053 continue;
5054 }
5055 /* SELECT: adding a column */
5056 xprefix = gaiaDoubleQuotedSql (name);
5057 prev = select;
5058 if (first_select)
5059 select = sqlite3_mprintf ("%s\"%s\"", prev, xprefix);
5060 else
5061 select = sqlite3_mprintf ("%s, \"%s\"", prev, xprefix);
5062 first_select = 0;
5063 free (xprefix);
5064 sqlite3_free (prev);
5065 ref_col++;
5066 /* INSERT: adding a column */
5067 xprefix = gaiaDoubleQuotedSql (name);
5068 prev = insert;
5069 if (first_insert)
5070 insert = sqlite3_mprintf ("%s\"%s\"", prev, xprefix);
5071 else
5072 insert = sqlite3_mprintf ("%s, \"%s\"", prev, xprefix);
5073 first_insert = 0;
5074 free (xprefix);
5075 sqlite3_free (prev);
5076 ncols++;
5077 /* CREATE: adding a column definition */
5078 prev = create;
5079 xprefix = gaiaDoubleQuotedSql (name);
5080 if (notnull)
5081 create =
5082 sqlite3_mprintf ("%s,\n\t\"%s\" %s NOT NULL",
5083 prev, xprefix, type);
5084 else
5085 create =
5086 sqlite3_mprintf ("%s,\n\t\"%s\" %s", prev,
5087 xprefix, type);
5088 free (xprefix);
5089 sqlite3_free (prev);
5090 }
5091 }
5092 sqlite3_free_table (results);
5093
5094 /* completing the SQL statements */
5095 prev = create;
5096 create = sqlite3_mprintf ("%s)", prev);
5097 sqlite3_free (prev);
5098 prev = select;
5099 xprefix = gaiaDoubleQuotedSql (db_prefix);
5100 xtable = gaiaDoubleQuotedSql (ref_table);
5101 if (ref_column != NULL)
5102 {
5103 xgeom = gaiaDoubleQuotedSql (ref_column);
5104 select =
5105 sqlite3_mprintf ("%s, \"%s\" FROM \"%s\".\"%s\"", prev, xgeom,
5106 xprefix, xtable);
5107 free (xgeom);
5108 }
5109 else
5110 select =
5111 sqlite3_mprintf ("%s FROM \"%s\".\"%s\"", prev, xprefix, xtable);
5112 free (xprefix);
5113 free (xtable);
5114 sqlite3_free (prev);
5115 prev = insert;
5116 insert = sqlite3_mprintf ("%s) VALUES (", prev);
5117 sqlite3_free (prev);
5118 for (icol = 0; icol < ncols; icol++)
5119 {
5120 prev = insert;
5121 if (icol == 0)
5122 insert = sqlite3_mprintf ("%s?", prev);
5123 else
5124 insert = sqlite3_mprintf ("%s, ?", prev);
5125 sqlite3_free (prev);
5126 }
5127 prev = insert;
5128 insert = sqlite3_mprintf ("%s)", prev);
5129 sqlite3_free (prev);
5130
5131 *xcreate = create;
5132 *xselect = select;
5133 *xinsert = insert;
5134 return 1;
5135
5136 error:
5137 if (create != NULL)
5138 sqlite3_free (create);
5139 if (select != NULL)
5140 sqlite3_free (select);
5141 if (insert != NULL)
5142 sqlite3_free (insert);
5143 return 0;
5144 }
5145
5146 static int
do_register_topolayer(struct gaia_topology * topo,const char * topolayer_name,sqlite3_int64 * topolayer_id)5147 do_register_topolayer (struct gaia_topology *topo, const char *topolayer_name,
5148 sqlite3_int64 * topolayer_id)
5149 {
5150 /* attempting to register a new TopoLayer */
5151 char *table;
5152 char *xtable;
5153 char *sql;
5154 int ret;
5155 char *err_msg = NULL;
5156
5157 table = sqlite3_mprintf ("%s_topolayers", topo->topology_name);
5158 xtable = gaiaDoubleQuotedSql (table);
5159 sqlite3_free (table);
5160 sql =
5161 sqlite3_mprintf
5162 ("INSERT INTO \"%s\" (topolayer_name) VALUES (Lower(%Q))", xtable,
5163 topolayer_name);
5164 free (xtable);
5165 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &err_msg);
5166 sqlite3_free (sql);
5167 if (ret != SQLITE_OK)
5168 {
5169 char *msg =
5170 sqlite3_mprintf ("RegisterTopoLayer error: \"%s\"", err_msg);
5171 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
5172 sqlite3_free (err_msg);
5173 sqlite3_free (msg);
5174 return 0;
5175 }
5176
5177 *topolayer_id = sqlite3_last_insert_rowid (topo->db_handle);
5178 return 1;
5179 }
5180
5181 static int
do_eval_topolayer_point(struct gaia_topology * topo,gaiaGeomCollPtr reference,sqlite3_stmt * stmt_node,sqlite3_stmt * stmt_rels,sqlite3_int64 topolayer_id,sqlite3_int64 fid)5182 do_eval_topolayer_point (struct gaia_topology *topo, gaiaGeomCollPtr reference,
5183 sqlite3_stmt * stmt_node, sqlite3_stmt * stmt_rels,
5184 sqlite3_int64 topolayer_id, sqlite3_int64 fid)
5185 {
5186 /* retrieving Points from Topology */
5187 int ret;
5188 unsigned char *p_blob;
5189 int n_bytes;
5190
5191 /* initializing the Topo-Node query */
5192 gaiaToSpatiaLiteBlobWkb (reference, &p_blob, &n_bytes);
5193 sqlite3_reset (stmt_node);
5194 sqlite3_clear_bindings (stmt_node);
5195 sqlite3_bind_blob (stmt_node, 1, p_blob, n_bytes, SQLITE_TRANSIENT);
5196 sqlite3_bind_blob (stmt_node, 2, p_blob, n_bytes, SQLITE_TRANSIENT);
5197 free (p_blob);
5198
5199 while (1)
5200 {
5201 /* scrolling the result set rows */
5202 ret = sqlite3_step (stmt_node);
5203 if (ret == SQLITE_DONE)
5204 break; /* end of result set */
5205 if (ret == SQLITE_ROW)
5206 {
5207 sqlite3_int64 node_id = sqlite3_column_int64 (stmt_node, 0);
5208 sqlite3_reset (stmt_rels);
5209 sqlite3_clear_bindings (stmt_rels);
5210 sqlite3_bind_int64 (stmt_rels, 1, node_id);
5211 sqlite3_bind_null (stmt_rels, 2);
5212 sqlite3_bind_null (stmt_rels, 3);
5213 sqlite3_bind_int64 (stmt_rels, 4, topolayer_id);
5214 sqlite3_bind_int64 (stmt_rels, 5, fid);
5215 ret = sqlite3_step (stmt_rels);
5216 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
5217 ;
5218 else
5219 {
5220 char *msg =
5221 sqlite3_mprintf
5222 ("TopoGeo_CreateTopoLayer() error: \"%s\"",
5223 sqlite3_errmsg (topo->db_handle));
5224 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr)
5225 topo, msg);
5226 sqlite3_free (msg);
5227 return 0;
5228 }
5229 }
5230 else
5231 {
5232 char *msg =
5233 sqlite3_mprintf ("TopoGeo_CreateTopoLayer error: \"%s\"",
5234 sqlite3_errmsg (topo->db_handle));
5235 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
5236 msg);
5237 sqlite3_free (msg);
5238 return 0;
5239 }
5240 }
5241 return 1;
5242 }
5243
5244 static int
do_eval_topolayer_line(struct gaia_topology * topo,gaiaGeomCollPtr reference,sqlite3_stmt * stmt_edge,sqlite3_stmt * stmt_rels,sqlite3_int64 topolayer_id,sqlite3_int64 fid)5245 do_eval_topolayer_line (struct gaia_topology *topo, gaiaGeomCollPtr reference,
5246 sqlite3_stmt * stmt_edge, sqlite3_stmt * stmt_rels,
5247 sqlite3_int64 topolayer_id, sqlite3_int64 fid)
5248 {
5249 /* retrieving Linestrings from Topology */
5250 int ret;
5251 unsigned char *p_blob;
5252 int n_bytes;
5253
5254 /* initializing the Topo-Edge query */
5255 gaiaToSpatiaLiteBlobWkb (reference, &p_blob, &n_bytes);
5256 sqlite3_reset (stmt_edge);
5257 sqlite3_clear_bindings (stmt_edge);
5258 sqlite3_bind_blob (stmt_edge, 1, p_blob, n_bytes, SQLITE_TRANSIENT);
5259 sqlite3_bind_blob (stmt_edge, 2, p_blob, n_bytes, SQLITE_TRANSIENT);
5260 free (p_blob);
5261
5262 while (1)
5263 {
5264 /* scrolling the result set rows */
5265 ret = sqlite3_step (stmt_edge);
5266 if (ret == SQLITE_DONE)
5267 break; /* end of result set */
5268 if (ret == SQLITE_ROW)
5269 {
5270 sqlite3_int64 edge_id = sqlite3_column_int64 (stmt_edge, 0);
5271 sqlite3_reset (stmt_rels);
5272 sqlite3_clear_bindings (stmt_rels);
5273 sqlite3_bind_null (stmt_rels, 1);
5274 sqlite3_bind_int64 (stmt_rels, 2, edge_id);
5275 sqlite3_bind_null (stmt_rels, 3);
5276 sqlite3_bind_int64 (stmt_rels, 4, topolayer_id);
5277 sqlite3_bind_int64 (stmt_rels, 5, fid);
5278 ret = sqlite3_step (stmt_rels);
5279 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
5280 ;
5281 else
5282 {
5283 char *msg =
5284 sqlite3_mprintf
5285 ("TopoGeo_CreateTopoLayer() error: \"%s\"",
5286 sqlite3_errmsg (topo->db_handle));
5287 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr)
5288 topo, msg);
5289 sqlite3_free (msg);
5290 return 0;
5291 }
5292 }
5293 else
5294 {
5295 char *msg =
5296 sqlite3_mprintf ("TopoGeo_CreateTopoLayer error: \"%s\"",
5297 sqlite3_errmsg (topo->db_handle));
5298 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
5299 msg);
5300 sqlite3_free (msg);
5301 return 0;
5302 }
5303 }
5304 return 1;
5305 }
5306
5307 static int
do_eval_topolayer_polyg(struct gaia_topology * topo,gaiaGeomCollPtr reference,sqlite3_stmt * stmt_face,sqlite3_stmt * stmt_rels,sqlite3_int64 topolayer_id,sqlite3_int64 fid)5308 do_eval_topolayer_polyg (struct gaia_topology *topo, gaiaGeomCollPtr reference,
5309 sqlite3_stmt * stmt_face, sqlite3_stmt * stmt_rels,
5310 sqlite3_int64 topolayer_id, sqlite3_int64 fid)
5311 {
5312 /* retrieving Polygon from Topology */
5313 int ret;
5314 unsigned char *p_blob;
5315 int n_bytes;
5316
5317 /* initializing the Topo-Face query */
5318 gaiaToSpatiaLiteBlobWkb (reference, &p_blob, &n_bytes);
5319 sqlite3_reset (stmt_face);
5320 sqlite3_clear_bindings (stmt_face);
5321 sqlite3_bind_blob (stmt_face, 1, p_blob, n_bytes, SQLITE_TRANSIENT);
5322 sqlite3_bind_blob (stmt_face, 2, p_blob, n_bytes, SQLITE_TRANSIENT);
5323 free (p_blob);
5324
5325 while (1)
5326 {
5327 /* scrolling the result set rows */
5328 ret = sqlite3_step (stmt_face);
5329 if (ret == SQLITE_DONE)
5330 break; /* end of result set */
5331 if (ret == SQLITE_ROW)
5332 {
5333 sqlite3_int64 face_id = sqlite3_column_int64 (stmt_face, 0);
5334 sqlite3_reset (stmt_rels);
5335 sqlite3_clear_bindings (stmt_rels);
5336 sqlite3_bind_null (stmt_rels, 1);
5337 sqlite3_bind_null (stmt_rels, 2);
5338 sqlite3_bind_int64 (stmt_rels, 3, face_id);
5339 sqlite3_bind_int64 (stmt_rels, 4, topolayer_id);
5340 sqlite3_bind_int64 (stmt_rels, 5, fid);
5341 ret = sqlite3_step (stmt_rels);
5342 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
5343 ;
5344 else
5345 {
5346 char *msg =
5347 sqlite3_mprintf
5348 ("TopoGeo_CreateTopoLayer() error: \"%s\"",
5349 sqlite3_errmsg (topo->db_handle));
5350 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr)
5351 topo, msg);
5352 sqlite3_free (msg);
5353 return 0;
5354 }
5355 }
5356 else
5357 {
5358 char *msg =
5359 sqlite3_mprintf ("TopoGeo_CreateTopoLayer error: \"%s\"",
5360 sqlite3_errmsg (topo->db_handle));
5361 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
5362 msg);
5363 sqlite3_free (msg);
5364 return 0;
5365 }
5366 }
5367 return 1;
5368 }
5369
5370 static int
do_eval_topolayer_geom(struct gaia_topology * topo,gaiaGeomCollPtr geom,sqlite3_stmt * stmt_node,sqlite3_stmt * stmt_edge,sqlite3_stmt * stmt_face,sqlite3_stmt * stmt_rels,sqlite3_int64 topolayer_id,sqlite3_int64 fid)5371 do_eval_topolayer_geom (struct gaia_topology *topo, gaiaGeomCollPtr geom,
5372 sqlite3_stmt * stmt_node, sqlite3_stmt * stmt_edge,
5373 sqlite3_stmt * stmt_face, sqlite3_stmt * stmt_rels,
5374 sqlite3_int64 topolayer_id, sqlite3_int64 fid)
5375 {
5376 /* retrieving Features via matching Seeds/Geometries */
5377 gaiaPointPtr pt;
5378 gaiaLinestringPtr ln;
5379 gaiaPolygonPtr pg;
5380 int ret;
5381
5382 /* processing all Points */
5383 pt = geom->FirstPoint;
5384 while (pt != NULL)
5385 {
5386 gaiaPointPtr next = pt->Next;
5387 gaiaGeomCollPtr reference = (gaiaGeomCollPtr)
5388 auxtopo_make_geom_from_point (topo->srid, topo->has_z, pt);
5389 ret =
5390 do_eval_topolayer_point (topo, reference, stmt_node, stmt_rels,
5391 topolayer_id, fid);
5392 auxtopo_destroy_geom_from (reference);
5393 pt->Next = next;
5394 if (ret == 0)
5395 return 0;
5396 pt = pt->Next;
5397 }
5398
5399 /* processing all Linestrings */
5400 ln = geom->FirstLinestring;
5401 while (ln != NULL)
5402 {
5403 gaiaLinestringPtr next = ln->Next;
5404 gaiaGeomCollPtr reference = (gaiaGeomCollPtr)
5405 auxtopo_make_geom_from_line (topo->srid, ln);
5406 ret =
5407 do_eval_topolayer_line (topo, reference, stmt_edge, stmt_rels,
5408 topolayer_id, fid);
5409 auxtopo_destroy_geom_from (reference);
5410 ln->Next = next;
5411 if (ret == 0)
5412 return 0;
5413 ln = ln->Next;
5414 }
5415
5416 /* processing all Polygons */
5417 pg = geom->FirstPolygon;
5418 while (pg != NULL)
5419 {
5420 gaiaPolygonPtr next = pg->Next;
5421 gaiaGeomCollPtr reference = make_geom_from_polyg (topo->srid, pg);
5422 ret = do_eval_topolayer_polyg (topo, reference, stmt_face, stmt_rels,
5423 topolayer_id, fid);
5424 auxtopo_destroy_geom_from (reference);
5425 pg->Next = next;
5426 if (ret == 0)
5427 return 0;
5428 pg = pg->Next;
5429 }
5430
5431 return 1;
5432 }
5433
5434 static int
do_eval_topolayer_seeds(struct gaia_topology * topo,sqlite3_stmt * stmt_ref,sqlite3_stmt * stmt_ins,sqlite3_stmt * stmt_rels,sqlite3_stmt * stmt_node,sqlite3_stmt * stmt_edge,sqlite3_stmt * stmt_face,sqlite3_int64 topolayer_id)5435 do_eval_topolayer_seeds (struct gaia_topology *topo, sqlite3_stmt * stmt_ref,
5436 sqlite3_stmt * stmt_ins, sqlite3_stmt * stmt_rels,
5437 sqlite3_stmt * stmt_node, sqlite3_stmt * stmt_edge,
5438 sqlite3_stmt * stmt_face, sqlite3_int64 topolayer_id)
5439 {
5440 /* querying the ref-table */
5441 int ret;
5442
5443 sqlite3_reset (stmt_ref);
5444 sqlite3_clear_bindings (stmt_ref);
5445 while (1)
5446 {
5447 /* scrolling the result set rows */
5448 gaiaGeomCollPtr geom = NULL;
5449 sqlite3_int64 fid;
5450 ret = sqlite3_step (stmt_ref);
5451 if (ret == SQLITE_DONE)
5452 break; /* end of result set */
5453 if (ret == SQLITE_ROW)
5454 {
5455 int icol;
5456 int ncol = sqlite3_column_count (stmt_ref);
5457 sqlite3_reset (stmt_ins);
5458 sqlite3_clear_bindings (stmt_ins);
5459 for (icol = 0; icol < ncol; icol++)
5460 {
5461 int col_type = sqlite3_column_type (stmt_ref, icol);
5462 if (icol == ncol - 1)
5463 {
5464 /* the last column is always expected to be the geometry column */
5465 const unsigned char *blob =
5466 sqlite3_column_blob (stmt_ref, icol);
5467 int blob_sz = sqlite3_column_bytes (stmt_ref, icol);
5468 geom = gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
5469 continue;
5470 }
5471 switch (col_type)
5472 {
5473 case SQLITE_INTEGER:
5474 sqlite3_bind_int64 (stmt_ins, icol + 1,
5475 sqlite3_column_int64 (stmt_ref,
5476 icol));
5477 break;
5478 case SQLITE_FLOAT:
5479 sqlite3_bind_double (stmt_ins, icol + 1,
5480 sqlite3_column_double
5481 (stmt_ref, icol));
5482 break;
5483 case SQLITE_TEXT:
5484 sqlite3_bind_text (stmt_ins, icol + 1,
5485 (const char *)
5486 sqlite3_column_text (stmt_ref,
5487 icol),
5488 sqlite3_column_bytes (stmt_ref,
5489 icol),
5490 SQLITE_STATIC);
5491 break;
5492 case SQLITE_BLOB:
5493 sqlite3_bind_blob (stmt_ins, icol + 1,
5494 sqlite3_column_blob (stmt_ref,
5495 icol),
5496 sqlite3_column_bytes (stmt_ref,
5497 icol),
5498 SQLITE_STATIC);
5499 break;
5500 default:
5501 sqlite3_bind_null (stmt_ins, icol + 1);
5502 break;
5503 };
5504 }
5505 ret = sqlite3_step (stmt_ins);
5506 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
5507 ;
5508 else
5509 {
5510 char *msg =
5511 sqlite3_mprintf
5512 ("TopoGeo_CreateTopoLayer() error: \"%s\"",
5513 sqlite3_errmsg (topo->db_handle));
5514 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr)
5515 topo, msg);
5516 sqlite3_free (msg);
5517 return 0;
5518 }
5519 fid = sqlite3_last_insert_rowid (topo->db_handle);
5520 /* evaluating the feature's geometry */
5521 if (geom != NULL)
5522 {
5523 ret =
5524 do_eval_topolayer_geom (topo, geom, stmt_node,
5525 stmt_edge, stmt_face,
5526 stmt_rels, topolayer_id, fid);
5527 gaiaFreeGeomColl (geom);
5528 if (ret == 0)
5529 return 0;
5530 }
5531 }
5532 else
5533 {
5534 char *msg =
5535 sqlite3_mprintf ("TopoGeo_CreateTopoLayer() error: \"%s\"",
5536 sqlite3_errmsg (topo->db_handle));
5537 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
5538 msg);
5539 sqlite3_free (msg);
5540 return 0;
5541 }
5542 }
5543
5544 return 1;
5545 }
5546
5547 GAIATOPO_DECLARE int
gaiaTopoGeo_CreateTopoLayer(GaiaTopologyAccessorPtr accessor,const char * db_prefix,const char * ref_table,const char * ref_column,const char * topolayer_name)5548 gaiaTopoGeo_CreateTopoLayer (GaiaTopologyAccessorPtr accessor,
5549 const char *db_prefix, const char *ref_table,
5550 const char *ref_column, const char *topolayer_name)
5551 {
5552 /* attempting to create a TopoLayer */
5553 sqlite3_int64 topolayer_id;
5554 sqlite3_stmt *stmt_ref = NULL;
5555 sqlite3_stmt *stmt_ins = NULL;
5556 sqlite3_stmt *stmt_rels = NULL;
5557 sqlite3_stmt *stmt_node = NULL;
5558 sqlite3_stmt *stmt_edge = NULL;
5559 sqlite3_stmt *stmt_face = NULL;
5560 int ret;
5561 char *sql;
5562 char *create;
5563 char *select;
5564 char *insert;
5565 char *xprefix;
5566 char *table;
5567 char *xtable;
5568 char *errMsg;
5569 struct gaia_topology *topo = (struct gaia_topology *) accessor;
5570
5571 if (topo == NULL)
5572 return 0;
5573
5574 /* attempting to register a new TopoLayer */
5575 if (!do_register_topolayer (topo, topolayer_name, &topolayer_id))
5576 return 0;
5577
5578 /* incrementally updating all Topology Seeds */
5579 if (!gaiaTopoGeoUpdateSeeds (accessor, 1))
5580 return 0;
5581
5582 /* composing the CREATE TABLE feature-table statement */
5583 if (!auxtopo_create_features_sql
5584 (topo->db_handle, db_prefix, ref_table, ref_column, topo->topology_name,
5585 topolayer_id, &create, &select, &insert))
5586 goto error;
5587
5588 /* creating the feature-table */
5589 ret = sqlite3_exec (topo->db_handle, create, NULL, NULL, &errMsg);
5590 sqlite3_free (create);
5591 create = NULL;
5592 if (ret != SQLITE_OK)
5593 {
5594 char *msg =
5595 sqlite3_mprintf ("TopoGeo_CreateTopoLayer() error: \"%s\"",
5596 errMsg);
5597 sqlite3_free (errMsg);
5598 gaiatopo_set_last_error_msg (accessor, msg);
5599 sqlite3_free (msg);
5600 goto error;
5601 }
5602
5603 /* preparing the "SELECT * FROM ref-table" query */
5604 ret =
5605 sqlite3_prepare_v2 (topo->db_handle, select, strlen (select), &stmt_ref,
5606 NULL);
5607 sqlite3_free (select);
5608 select = NULL;
5609 if (ret != SQLITE_OK)
5610 {
5611 char *msg =
5612 sqlite3_mprintf ("TopoGeo_CreateTopoLayer() error: \"%s\"",
5613 sqlite3_errmsg (topo->db_handle));
5614 gaiatopo_set_last_error_msg (accessor, msg);
5615 sqlite3_free (msg);
5616 goto error;
5617 }
5618
5619 /* preparing the "INSERT INTO features-table" query */
5620 ret =
5621 sqlite3_prepare_v2 (topo->db_handle, insert, strlen (insert), &stmt_ins,
5622 NULL);
5623 sqlite3_free (insert);
5624 insert = NULL;
5625 if (ret != SQLITE_OK)
5626 {
5627 char *msg =
5628 sqlite3_mprintf ("TopoGeo_CreateTopoLayer() error: \"%s\"",
5629 sqlite3_errmsg (topo->db_handle));
5630 gaiatopo_set_last_error_msg (accessor, msg);
5631 sqlite3_free (msg);
5632 goto error;
5633 }
5634
5635 /* preparing the "INSERT INTO features-ref" query */
5636 table = sqlite3_mprintf ("%s_topofeatures", topo->topology_name);
5637 xtable = gaiaDoubleQuotedSql (table);
5638 sqlite3_free (table);
5639 sql =
5640 sqlite3_mprintf
5641 ("INSERT INTO \"%s\" (node_id, edge_id, face_id, topolayer_id, fid) "
5642 "VALUES (?, ?, ?, ?, ?)", xtable);
5643 free (xtable);
5644 ret =
5645 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_rels,
5646 NULL);
5647 sqlite3_free (sql);
5648 sql = NULL;
5649 if (ret != SQLITE_OK)
5650 {
5651 char *msg =
5652 sqlite3_mprintf ("TopoGeo_CreateTopoLayer() error: \"%s\"",
5653 sqlite3_errmsg (topo->db_handle));
5654 gaiatopo_set_last_error_msg (accessor, msg);
5655 sqlite3_free (msg);
5656 goto error;
5657 }
5658
5659 /* preparing the Topo-Seed-Edges query */
5660 xprefix = sqlite3_mprintf ("%s_seeds", topo->topology_name);
5661 xtable = gaiaDoubleQuotedSql (xprefix);
5662 sql = sqlite3_mprintf ("SELECT edge_id FROM MAIN.\"%s\" "
5663 "WHERE edge_id IS NOT NULL AND ST_Intersects(geom, ?) = 1 AND ROWID IN ("
5664 "SELECT ROWID FROM SpatialIndex WHERE f_table_name = %Q AND search_frame = ?)",
5665 xtable, xprefix);
5666 free (xtable);
5667 sqlite3_free (xprefix);
5668 ret =
5669 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_edge,
5670 NULL);
5671 sqlite3_free (sql);
5672 if (ret != SQLITE_OK)
5673 {
5674 char *msg =
5675 sqlite3_mprintf ("TopoGeo_CreateTopoLayer() error: \"%s\"",
5676 sqlite3_errmsg (topo->db_handle));
5677 gaiatopo_set_last_error_msg (accessor, msg);
5678 sqlite3_free (msg);
5679 goto error;
5680 }
5681
5682 /* preparing the Topo-Seed-Faces query */
5683 xprefix = sqlite3_mprintf ("%s_seeds", topo->topology_name);
5684 xtable = gaiaDoubleQuotedSql (xprefix);
5685 sql = sqlite3_mprintf ("SELECT face_id FROM MAIN.\"%s\" "
5686 "WHERE face_id IS NOT NULL AND ST_Intersects(geom, ?) = 1 AND ROWID IN ("
5687 "SELECT ROWID FROM SpatialIndex WHERE f_table_name = %Q AND search_frame = ?)",
5688 xtable, xprefix);
5689 free (xtable);
5690 sqlite3_free (xprefix);
5691 ret =
5692 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_face,
5693 NULL);
5694 sqlite3_free (sql);
5695 if (ret != SQLITE_OK)
5696 {
5697 char *msg =
5698 sqlite3_mprintf ("TopoGeo_CreateTopoLayer() error: \"%s\"",
5699 sqlite3_errmsg (topo->db_handle));
5700 gaiatopo_set_last_error_msg (accessor, msg);
5701 sqlite3_free (msg);
5702 goto error;
5703 }
5704
5705 /* preparing the Topo-Nodes query */
5706 xprefix = sqlite3_mprintf ("%s_node", topo->topology_name);
5707 xtable = gaiaDoubleQuotedSql (xprefix);
5708 sql = sqlite3_mprintf ("SELECT node_id FROM MAIN.\"%s\" "
5709 "WHERE ST_Intersects(geom, ?) = 1 AND ROWID IN ("
5710 "SELECT ROWID FROM SpatialIndex WHERE f_table_name = %Q AND search_frame = ?)",
5711 xtable, xprefix);
5712 free (xtable);
5713 sqlite3_free (xprefix);
5714 ret =
5715 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_node,
5716 NULL);
5717 sqlite3_free (sql);
5718 if (ret != SQLITE_OK)
5719 {
5720 char *msg =
5721 sqlite3_mprintf ("TopoGeo_CreateTopoLayer() error: \"%s\"",
5722 sqlite3_errmsg (topo->db_handle));
5723 gaiatopo_set_last_error_msg (accessor, msg);
5724 sqlite3_free (msg);
5725 goto error;
5726 }
5727
5728 /* evaluating feature/topology matching via coincident topo-seeds */
5729 if (!do_eval_topolayer_seeds
5730 (topo, stmt_ref, stmt_ins, stmt_rels, stmt_node, stmt_edge, stmt_face,
5731 topolayer_id))
5732 goto error;
5733
5734 sqlite3_finalize (stmt_ref);
5735 sqlite3_finalize (stmt_ins);
5736 sqlite3_finalize (stmt_rels);
5737 sqlite3_finalize (stmt_node);
5738 sqlite3_finalize (stmt_edge);
5739 sqlite3_finalize (stmt_face);
5740 return 1;
5741
5742 error:
5743 if (create != NULL)
5744 sqlite3_free (create);
5745 if (select != NULL)
5746 sqlite3_free (select);
5747 if (insert != NULL)
5748 sqlite3_free (insert);
5749 if (stmt_ref != NULL)
5750 sqlite3_finalize (stmt_ref);
5751 if (stmt_ins != NULL)
5752 sqlite3_finalize (stmt_ins);
5753 if (stmt_rels != NULL)
5754 sqlite3_finalize (stmt_rels);
5755 if (stmt_node != NULL)
5756 sqlite3_finalize (stmt_node);
5757 if (stmt_edge != NULL)
5758 sqlite3_finalize (stmt_edge);
5759 if (stmt_face != NULL)
5760 sqlite3_finalize (stmt_face);
5761 return 0;
5762 }
5763
5764 static int
do_populate_topolayer(struct gaia_topology * topo,sqlite3_stmt * stmt_ref,sqlite3_stmt * stmt_ins)5765 do_populate_topolayer (struct gaia_topology *topo, sqlite3_stmt * stmt_ref,
5766 sqlite3_stmt * stmt_ins)
5767 {
5768 /* querying the ref-table */
5769 int ret;
5770
5771 sqlite3_reset (stmt_ref);
5772 sqlite3_clear_bindings (stmt_ref);
5773 while (1)
5774 {
5775 /* scrolling the result set rows */
5776 ret = sqlite3_step (stmt_ref);
5777 if (ret == SQLITE_DONE)
5778 break; /* end of result set */
5779 if (ret == SQLITE_ROW)
5780 {
5781 int icol;
5782 int ncol = sqlite3_column_count (stmt_ref);
5783 sqlite3_reset (stmt_ins);
5784 sqlite3_clear_bindings (stmt_ins);
5785 for (icol = 0; icol < ncol; icol++)
5786 {
5787 int col_type = sqlite3_column_type (stmt_ref, icol);
5788 switch (col_type)
5789 {
5790 case SQLITE_INTEGER:
5791 sqlite3_bind_int64 (stmt_ins, icol + 1,
5792 sqlite3_column_int64 (stmt_ref,
5793 icol));
5794 break;
5795 case SQLITE_FLOAT:
5796 sqlite3_bind_double (stmt_ins, icol + 1,
5797 sqlite3_column_double
5798 (stmt_ref, icol));
5799 break;
5800 case SQLITE_TEXT:
5801 sqlite3_bind_text (stmt_ins, icol + 1,
5802 (const char *)
5803 sqlite3_column_text (stmt_ref,
5804 icol),
5805 sqlite3_column_bytes (stmt_ref,
5806 icol),
5807 SQLITE_STATIC);
5808 break;
5809 case SQLITE_BLOB:
5810 sqlite3_bind_blob (stmt_ins, icol + 1,
5811 sqlite3_column_blob (stmt_ref,
5812 icol),
5813 sqlite3_column_bytes (stmt_ref,
5814 icol),
5815 SQLITE_STATIC);
5816 break;
5817 default:
5818 sqlite3_bind_null (stmt_ins, icol + 1);
5819 break;
5820 };
5821 }
5822 ret = sqlite3_step (stmt_ins);
5823 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
5824 ;
5825 else
5826 {
5827 char *msg =
5828 sqlite3_mprintf
5829 ("TopoGeo_InitTopoLayer() error: \"%s\"",
5830 sqlite3_errmsg (topo->db_handle));
5831 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr)
5832 topo, msg);
5833 sqlite3_free (msg);
5834 return 0;
5835 }
5836 }
5837 else
5838 {
5839 char *msg =
5840 sqlite3_mprintf ("TopoGeo_InitTopoLayer() error: \"%s\"",
5841 sqlite3_errmsg (topo->db_handle));
5842 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
5843 msg);
5844 sqlite3_free (msg);
5845 return 0;
5846 }
5847 }
5848
5849 return 1;
5850 }
5851
5852 GAIATOPO_DECLARE int
gaiaTopoGeo_InitTopoLayer(GaiaTopologyAccessorPtr accessor,const char * db_prefix,const char * ref_table,const char * topolayer_name)5853 gaiaTopoGeo_InitTopoLayer (GaiaTopologyAccessorPtr accessor,
5854 const char *db_prefix, const char *ref_table,
5855 const char *topolayer_name)
5856 {
5857 /* attempting to create a TopoLayer */
5858 sqlite3_int64 topolayer_id;
5859 sqlite3_stmt *stmt_ref = NULL;
5860 sqlite3_stmt *stmt_ins = NULL;
5861 int ret;
5862 char *create;
5863 char *select;
5864 char *insert;
5865 char *errMsg;
5866 struct gaia_topology *topo = (struct gaia_topology *) accessor;
5867
5868 if (topo == NULL)
5869 return 0;
5870
5871 /* attempting to register a new TopoLayer */
5872 if (!do_register_topolayer (topo, topolayer_name, &topolayer_id))
5873 return 0;
5874
5875 /* composing the CREATE TABLE feature-table statement */
5876 if (!auxtopo_create_features_sql
5877 (topo->db_handle, db_prefix, ref_table, NULL, topo->topology_name,
5878 topolayer_id, &create, &select, &insert))
5879 goto error;
5880
5881 /* creating the feature-table */
5882 ret = sqlite3_exec (topo->db_handle, create, NULL, NULL, &errMsg);
5883 sqlite3_free (create);
5884 create = NULL;
5885 if (ret != SQLITE_OK)
5886 {
5887 char *msg = sqlite3_mprintf ("TopoGeo_InitTopoLayer() error: \"%s\"",
5888 errMsg);
5889 sqlite3_free (errMsg);
5890 gaiatopo_set_last_error_msg (accessor, msg);
5891 sqlite3_free (msg);
5892 goto error;
5893 }
5894
5895 /* preparing the "SELECT * FROM ref-table" query */
5896 ret =
5897 sqlite3_prepare_v2 (topo->db_handle, select, strlen (select), &stmt_ref,
5898 NULL);
5899 sqlite3_free (select);
5900 select = NULL;
5901 if (ret != SQLITE_OK)
5902 {
5903 char *msg =
5904 sqlite3_mprintf ("TopoGeo_CreateTopoLayer() error: \"%s\"",
5905 sqlite3_errmsg (topo->db_handle));
5906 gaiatopo_set_last_error_msg (accessor, msg);
5907 sqlite3_free (msg);
5908 goto error;
5909 }
5910
5911 /* preparing the "INSERT INTO features-table" query */
5912 ret =
5913 sqlite3_prepare_v2 (topo->db_handle, insert, strlen (insert), &stmt_ins,
5914 NULL);
5915 sqlite3_free (insert);
5916 insert = NULL;
5917 if (ret != SQLITE_OK)
5918 {
5919 char *msg =
5920 sqlite3_mprintf ("TopoGeo_CreateTopoLayer() error: \"%s\"",
5921 sqlite3_errmsg (topo->db_handle));
5922 gaiatopo_set_last_error_msg (accessor, msg);
5923 sqlite3_free (msg);
5924 goto error;
5925 }
5926
5927 /* populating the TopoFeatures table */
5928 if (!do_populate_topolayer (topo, stmt_ref, stmt_ins))
5929 goto error;
5930
5931 sqlite3_finalize (stmt_ref);
5932 sqlite3_finalize (stmt_ins);
5933 return 1;
5934
5935 error:
5936 if (create != NULL)
5937 sqlite3_free (create);
5938 if (select != NULL)
5939 sqlite3_free (select);
5940 if (insert != NULL)
5941 sqlite3_free (insert);
5942 if (stmt_ref != NULL)
5943 sqlite3_finalize (stmt_ref);
5944 if (stmt_ins != NULL)
5945 sqlite3_finalize (stmt_ins);
5946 return 0;
5947 }
5948
5949 static int
check_topolayer(struct gaia_topology * topo,const char * topolayer_name,sqlite3_int64 * topolayer_id)5950 check_topolayer (struct gaia_topology *topo, const char *topolayer_name,
5951 sqlite3_int64 * topolayer_id)
5952 {
5953 /* checking if a TopoLayer do really exist */
5954 char *table;
5955 char *xtable;
5956 char *sql;
5957 int ret;
5958 int found = 0;
5959 sqlite3_stmt *stmt = NULL;
5960
5961 /* creating the SQL statement - SELECT */
5962 table = sqlite3_mprintf ("%s_topolayers", topo->topology_name);
5963 xtable = gaiaDoubleQuotedSql (table);
5964 sqlite3_free (table);
5965 sql =
5966 sqlite3_mprintf
5967 ("SELECT topolayer_id FROM \"%s\" WHERE topolayer_name = Lower(%Q)",
5968 xtable, topolayer_name);
5969 free (xtable);
5970 ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
5971 sqlite3_free (sql);
5972 if (ret != SQLITE_OK)
5973 {
5974 char *msg = sqlite3_mprintf ("Check_TopoLayer() error: \"%s\"",
5975 sqlite3_errmsg (topo->db_handle));
5976 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
5977 sqlite3_free (msg);
5978 goto error;
5979 }
5980
5981 /* retrieving the TopoLayer ID */
5982 sqlite3_reset (stmt);
5983 sqlite3_clear_bindings (stmt);
5984 while (1)
5985 {
5986 /* scrolling the result set rows */
5987 ret = sqlite3_step (stmt);
5988 if (ret == SQLITE_DONE)
5989 break; /* end of result set */
5990 if (ret == SQLITE_ROW)
5991 {
5992 *topolayer_id = sqlite3_column_int64 (stmt, 0);
5993 found = 1;
5994 }
5995 else
5996 {
5997 char *msg = sqlite3_mprintf ("Check_TopoLayer() error: \"%s\"",
5998 sqlite3_errmsg (topo->db_handle));
5999 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
6000 msg);
6001 sqlite3_free (msg);
6002 goto error;
6003 }
6004 }
6005 if (!found)
6006 goto error;
6007
6008 sqlite3_finalize (stmt);
6009 return 1;
6010
6011 error:
6012 if (stmt != NULL)
6013 sqlite3_finalize (stmt);
6014 return 0;
6015 }
6016
6017 static int
do_unregister_topolayer(struct gaia_topology * topo,const char * topolayer_name,sqlite3_int64 * topolayer_id)6018 do_unregister_topolayer (struct gaia_topology *topo, const char *topolayer_name,
6019 sqlite3_int64 * topolayer_id)
6020 {
6021 /* attempting to unregister a existing TopoLayer */
6022 char *table;
6023 char *xtable;
6024 char *sql;
6025 int ret;
6026 sqlite3_int64 id;
6027 sqlite3_stmt *stmt = NULL;
6028
6029 if (!check_topolayer (topo, topolayer_name, &id))
6030 return 0;
6031
6032 /* creating the first SQL statement - DELETE */
6033 table = sqlite3_mprintf ("%s_topolayers", topo->topology_name);
6034 xtable = gaiaDoubleQuotedSql (table);
6035 sqlite3_free (table);
6036 sql = sqlite3_mprintf ("DELETE FROM \"%s\" WHERE topolayer_id = ?", xtable);
6037 free (xtable);
6038 ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
6039 create_all_topo_prepared_stmts (topo->cache); /* recreating prepared stsms */
6040 sqlite3_free (sql);
6041 if (ret != SQLITE_OK)
6042 {
6043 char *msg =
6044 sqlite3_mprintf ("TopoGeo_RemoveTopoLayer() error: \"%s\"",
6045 sqlite3_errmsg (topo->db_handle));
6046 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
6047 sqlite3_free (msg);
6048 goto error;
6049 }
6050
6051 /* deleting the TopoLayer */
6052 sqlite3_reset (stmt);
6053 sqlite3_clear_bindings (stmt);
6054 sqlite3_bind_int64 (stmt, 1, id);
6055 ret = sqlite3_step (stmt);
6056 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
6057 ;
6058 else
6059 {
6060 char *msg =
6061 sqlite3_mprintf ("TopoGeo_RemoveTopoLayer() error: \"%s\"",
6062 sqlite3_errmsg (topo->db_handle));
6063 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
6064 sqlite3_free (msg);
6065 goto error;
6066 }
6067
6068 *topolayer_id = id;
6069 sqlite3_finalize (stmt);
6070 return 1;
6071
6072 error:
6073 if (stmt != NULL)
6074 sqlite3_finalize (stmt);
6075 return 0;
6076 }
6077
6078 GAIATOPO_DECLARE int
gaiaTopoGeo_RemoveTopoLayer(GaiaTopologyAccessorPtr accessor,const char * topolayer_name)6079 gaiaTopoGeo_RemoveTopoLayer (GaiaTopologyAccessorPtr accessor,
6080 const char *topolayer_name)
6081 {
6082 /* attempting to remove a TopoLayer */
6083 sqlite3_int64 topolayer_id;
6084 int ret;
6085 char *sql;
6086 char *errMsg;
6087 char *table;
6088 char *xtable;
6089 char *xtable2;
6090 char dummy[64];
6091 struct gaia_topology *topo = (struct gaia_topology *) accessor;
6092
6093 if (topo == NULL)
6094 return 0;
6095
6096 /* deleting all Feature relations */
6097 table = sqlite3_mprintf ("%s_topofeatures", topo->topology_name);
6098 xtable = gaiaDoubleQuotedSql (table);
6099 sqlite3_free (table);
6100 table = sqlite3_mprintf ("%s_topolayers", topo->topology_name);
6101 xtable2 = gaiaDoubleQuotedSql (table);
6102 sqlite3_free (table);
6103 sql = sqlite3_mprintf ("DELETE FROM \"%s\" WHERE topolayer_id = "
6104 "(SELECT topolayer_id FROM \"%s\" WHERE topolayer_name = Lower(%Q))",
6105 xtable, xtable2, topolayer_name);
6106 free (xtable);
6107 free (xtable2);
6108 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
6109 sqlite3_free (sql);
6110 if (ret != SQLITE_OK)
6111 {
6112 char *msg = sqlite3_mprintf ("TopoGeo_RemoveTopoLayer() error: %s\n",
6113 errMsg);
6114 sqlite3_free (errMsg);
6115 gaiatopo_set_last_error_msg (accessor, msg);
6116 sqlite3_free (msg);
6117 return 0;
6118 }
6119
6120 /* unregistering the TopoLayer */
6121 if (!do_unregister_topolayer (topo, topolayer_name, &topolayer_id))
6122 return 0;
6123
6124 /* finalizing all prepared Statements */
6125 finalize_all_topo_prepared_stmts (topo->cache);
6126
6127 /* dropping the TopoFeatures Table */
6128 sprintf (dummy, "%lld", topolayer_id);
6129 table = sqlite3_mprintf ("%s_topofeatures_%s", topo->topology_name, dummy);
6130 xtable = gaiaDoubleQuotedSql (table);
6131 sqlite3_free (table);
6132 sql = sqlite3_mprintf ("DROP TABLE \"%s\"", xtable);
6133 free (xtable);
6134 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
6135 create_all_topo_prepared_stmts (topo->cache); /* recreating prepared stsms */
6136 sqlite3_free (sql);
6137 if (ret != SQLITE_OK)
6138 {
6139 char *msg = sqlite3_mprintf ("TopoGeo_RemoveTopoLayer() error: %s\n",
6140 errMsg);
6141 sqlite3_free (errMsg);
6142 gaiatopo_set_last_error_msg (accessor, msg);
6143 sqlite3_free (msg);
6144 return 0;
6145 }
6146
6147 return 1;
6148 }
6149
6150 static int
is_unique_geom_name(sqlite3 * sqlite,const char * table,const char * geom)6151 is_unique_geom_name (sqlite3 * sqlite, const char *table, const char *geom)
6152 {
6153 /* checking for duplicate names */
6154 char *xtable;
6155 char *sql;
6156 int ret;
6157 int i;
6158 char **results;
6159 int rows;
6160 int columns;
6161 const char *name;
6162
6163 xtable = gaiaDoubleQuotedSql (table);
6164 sql = sqlite3_mprintf ("PRAGMA MAIN.table_info(\"%s\")", xtable);
6165 free (xtable);
6166 ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, NULL);
6167 sqlite3_free (sql);
6168 if (ret != SQLITE_OK)
6169 return 0;
6170 if (rows < 1)
6171 ;
6172 else
6173 {
6174 for (i = 1; i <= rows; i++)
6175 {
6176 name = results[(i * columns) + 1];
6177 if (strcasecmp (name, geom) == 0)
6178 continue;
6179 }
6180 }
6181 sqlite3_free_table (results);
6182
6183 return 1;
6184 }
6185
6186 static int
auxtopo_create_export_sql(struct gaia_topology * topo,const char * topolayer_name,const char * out_table,char ** xcreate,char ** xselect,char ** xinsert,char ** geometry,sqlite3_int64 * topolayer_id)6187 auxtopo_create_export_sql (struct gaia_topology *topo,
6188 const char *topolayer_name, const char *out_table,
6189 char **xcreate, char **xselect, char **xinsert,
6190 char **geometry, sqlite3_int64 * topolayer_id)
6191 {
6192 /* composing the CREATE TABLE export-table statement */
6193 char *create = NULL;
6194 char *select = NULL;
6195 char *insert = NULL;
6196 char *prev;
6197 char *sql;
6198 char *table;
6199 char *xtable;
6200 char *xprefix;
6201 char dummy[64];
6202 int i;
6203 char **results;
6204 int rows;
6205 int columns;
6206 const char *name;
6207 const char *type;
6208 int notnull;
6209 int ret;
6210 int first_select = 1;
6211 int first_insert = 1;
6212 int ncols = 0;
6213 int icol;
6214 int ref_col = 0;
6215 char *geometry_name;
6216 int geom_alias = 0;
6217
6218 *xcreate = NULL;
6219 *xselect = NULL;
6220 *xinsert = NULL;
6221
6222 /* checking the TopoLayer */
6223 if (!check_topolayer (topo, topolayer_name, topolayer_id))
6224 return 0;
6225
6226 xtable = gaiaDoubleQuotedSql (out_table);
6227 create =
6228 sqlite3_mprintf
6229 ("CREATE TABLE MAIN.\"%s\" (\n\tfid INTEGER PRIMARY KEY", xtable);
6230 select = sqlite3_mprintf ("SELECT fid, ");
6231 insert = sqlite3_mprintf ("INSERT INTO MAIN.\"%s\" (fid, ", xtable);
6232 free (xtable);
6233 sprintf (dummy, "%lld", *topolayer_id);
6234 table = sqlite3_mprintf ("%s_topofeatures_%s", topo->topology_name, dummy);
6235 xtable = gaiaDoubleQuotedSql (table);
6236 sqlite3_free (table);
6237 sql = sqlite3_mprintf ("PRAGMA MAIN.table_info(\"%s\")", xtable);
6238 free (xtable);
6239 ret =
6240 sqlite3_get_table (topo->db_handle, sql, &results, &rows, &columns,
6241 NULL);
6242 sqlite3_free (sql);
6243 if (ret != SQLITE_OK)
6244 goto error;
6245 if (rows < 1)
6246 ;
6247 else
6248 {
6249 for (i = 1; i <= rows; i++)
6250 {
6251 name = results[(i * columns) + 1];
6252 if (strcmp (name, "fid") == 0)
6253 continue;
6254 type = results[(i * columns) + 2];
6255 notnull = atoi (results[(i * columns) + 3]);
6256 /* SELECT: adding a column */
6257 xprefix = gaiaDoubleQuotedSql (name);
6258 prev = select;
6259 if (first_select)
6260 select = sqlite3_mprintf ("%s\"%s\"", prev, xprefix);
6261 else
6262 select = sqlite3_mprintf ("%s, \"%s\"", prev, xprefix);
6263 first_select = 0;
6264 free (xprefix);
6265 sqlite3_free (prev);
6266 ref_col++;
6267 /* INSERT: adding a column */
6268 xprefix = gaiaDoubleQuotedSql (name);
6269 prev = insert;
6270 if (first_insert)
6271 insert = sqlite3_mprintf ("%s\"%s\"", prev, xprefix);
6272 else
6273 insert = sqlite3_mprintf ("%s, \"%s\"", prev, xprefix);
6274 first_insert = 0;
6275 free (xprefix);
6276 sqlite3_free (prev);
6277 ncols++;
6278 /* CREATE: adding a column definition */
6279 prev = create;
6280 xprefix = gaiaDoubleQuotedSql (name);
6281 if (notnull)
6282 create =
6283 sqlite3_mprintf ("%s,\n\t\"%s\" %s NOT NULL",
6284 prev, xprefix, type);
6285 else
6286 create =
6287 sqlite3_mprintf ("%s,\n\t\"%s\" %s", prev,
6288 xprefix, type);
6289 free (xprefix);
6290 sqlite3_free (prev);
6291 }
6292 }
6293 sqlite3_free_table (results);
6294
6295 geometry_name = malloc (strlen ("geometry") + 1);
6296 strcpy (geometry_name, "geometry");
6297 sprintf (dummy, "%lld", *topolayer_id);
6298 table = sqlite3_mprintf ("%s_topofeatures_%s", topo->topology_name, dummy);
6299 while (1)
6300 {
6301 /* searching an unique Geometry name */
6302 if (is_unique_geom_name (topo->db_handle, table, geometry_name))
6303 break;
6304 sprintf (dummy, "geom_%d", ++geom_alias);
6305 free (geometry_name);
6306 geometry_name = malloc (strlen (dummy) + 1);
6307 strcpy (geometry_name, dummy);
6308 }
6309 sqlite3_free (table);
6310
6311 /* completing the SQL statements */
6312 prev = create;
6313 create = sqlite3_mprintf ("%s)", prev);
6314 sqlite3_free (prev);
6315 prev = select;
6316 sprintf (dummy, "%lld", *topolayer_id);
6317 table = sqlite3_mprintf ("%s_topofeatures_%s", topo->topology_name, dummy);
6318 xtable = gaiaDoubleQuotedSql (table);
6319 sqlite3_free (table);
6320 select = sqlite3_mprintf ("%s FROM MAIN.\"%s\"", prev, xtable);
6321 free (xtable);
6322 sqlite3_free (prev);
6323 prev = insert;
6324 insert = sqlite3_mprintf ("%s, \"%s\") VALUES (?, ", prev, geometry_name);
6325 sqlite3_free (prev);
6326 for (icol = 0; icol < ncols; icol++)
6327 {
6328 prev = insert;
6329 if (icol == 0)
6330 insert = sqlite3_mprintf ("%s?", prev);
6331 else
6332 insert = sqlite3_mprintf ("%s, ?", prev);
6333 sqlite3_free (prev);
6334 }
6335 prev = insert;
6336 insert = sqlite3_mprintf ("%s, ?)", prev);
6337 sqlite3_free (prev);
6338
6339 *xcreate = create;
6340 *xselect = select;
6341 *xinsert = insert;
6342 *geometry = geometry_name;
6343 return 1;
6344
6345 error:
6346 if (create != NULL)
6347 sqlite3_free (create);
6348 if (select != NULL)
6349 sqlite3_free (select);
6350 if (insert != NULL)
6351 sqlite3_free (insert);
6352 return 0;
6353 }
6354
6355 static int
auxtopo_retrieve_export_geometry_type(struct gaia_topology * topo,const char * topolayer_name,int * ref_type)6356 auxtopo_retrieve_export_geometry_type (struct gaia_topology *topo,
6357 const char *topolayer_name,
6358 int *ref_type)
6359 {
6360 /* determining the Geometry Type for Export TopoLayer */
6361 char *table;
6362 char *xtable;
6363 char *xtable2;
6364 char *sql;
6365 int ret;
6366 int i;
6367 char **results;
6368 int rows;
6369 int columns;
6370 int nodes;
6371 int edges;
6372 int faces;
6373
6374 table = sqlite3_mprintf ("%s_topolayers", topo->topology_name);
6375 xtable = gaiaDoubleQuotedSql (table);
6376 sqlite3_free (table);
6377 table = sqlite3_mprintf ("%s_topofeatures", topo->topology_name);
6378 xtable2 = gaiaDoubleQuotedSql (table);
6379 sqlite3_free (table);
6380 sql =
6381 sqlite3_mprintf
6382 ("SELECT Count(f.node_id), Count(f.edge_id), Count(f.face_id) "
6383 "FROM \"%s\" AS l JOIN \"%s\" AS f ON (l.topolayer_id = f.topolayer_id) "
6384 "WHERE l.topolayer_name = Lower(%Q)", xtable, xtable2, topolayer_name);
6385 free (xtable);
6386 free (xtable2);
6387 ret =
6388 sqlite3_get_table (topo->db_handle, sql, &results, &rows, &columns,
6389 NULL);
6390 sqlite3_free (sql);
6391 if (ret != SQLITE_OK)
6392 return 0;
6393 if (rows < 1)
6394 ;
6395 else
6396 {
6397 for (i = 1; i <= rows; i++)
6398 {
6399 nodes = atoi (results[(i * columns) + 0]);
6400 edges = atoi (results[(i * columns) + 1]);
6401 faces = atoi (results[(i * columns) + 2]);
6402 }
6403 }
6404 sqlite3_free_table (results);
6405
6406 *ref_type = GAIA_UNKNOWN;
6407 if (nodes && !edges && !faces)
6408 *ref_type = GAIA_POINT;
6409 if (!nodes && edges && !faces)
6410 *ref_type = GAIA_LINESTRING;
6411 if (!nodes && !edges && faces)
6412 *ref_type = GAIA_POLYGON;
6413
6414 return 1;
6415 }
6416
6417 static void
do_eval_topo_node(struct gaia_topology * topo,sqlite3_stmt * stmt_node,sqlite3_int64 node_id,gaiaGeomCollPtr result)6418 do_eval_topo_node (struct gaia_topology *topo, sqlite3_stmt * stmt_node,
6419 sqlite3_int64 node_id, gaiaGeomCollPtr result)
6420 {
6421 /* retrieving Points from Topology Nodes */
6422 int ret;
6423
6424 /* initializing the Topo-Node query */
6425 sqlite3_reset (stmt_node);
6426 sqlite3_clear_bindings (stmt_node);
6427 sqlite3_bind_int64 (stmt_node, 1, node_id);
6428
6429 while (1)
6430 {
6431 /* scrolling the result set rows */
6432 ret = sqlite3_step (stmt_node);
6433 if (ret == SQLITE_DONE)
6434 break; /* end of result set */
6435 if (ret == SQLITE_ROW)
6436 {
6437 const unsigned char *blob = sqlite3_column_blob (stmt_node, 0);
6438 int blob_sz = sqlite3_column_bytes (stmt_node, 0);
6439 gaiaGeomCollPtr geom =
6440 gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
6441 if (geom != NULL)
6442 {
6443 gaiaPointPtr pt = geom->FirstPoint;
6444 while (pt != NULL)
6445 {
6446 /* copying all Points into the result Geometry */
6447 if (topo->has_z)
6448 gaiaAddPointToGeomCollXYZ (result, pt->X, pt->Y,
6449 pt->Z);
6450 else
6451 gaiaAddPointToGeomColl (result, pt->X, pt->Y);
6452 pt = pt->Next;
6453 }
6454 gaiaFreeGeomColl (geom);
6455 }
6456 }
6457 else
6458 {
6459 char *msg =
6460 sqlite3_mprintf
6461 ("TopoGeo_FeatureFromTopoLayer error: \"%s\"",
6462 sqlite3_errmsg (topo->db_handle));
6463 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
6464 msg);
6465 sqlite3_free (msg);
6466 return;
6467 }
6468 }
6469 }
6470
6471 static void
do_eval_topo_edge(struct gaia_topology * topo,sqlite3_stmt * stmt_edge,sqlite3_int64 edge_id,gaiaGeomCollPtr result)6472 do_eval_topo_edge (struct gaia_topology *topo, sqlite3_stmt * stmt_edge,
6473 sqlite3_int64 edge_id, gaiaGeomCollPtr result)
6474 {
6475 /* retrieving Linestrings from Topology Edges */
6476 int ret;
6477
6478 /* initializing the Topo-Edge query */
6479 sqlite3_reset (stmt_edge);
6480 sqlite3_clear_bindings (stmt_edge);
6481 sqlite3_bind_int64 (stmt_edge, 1, edge_id);
6482
6483 while (1)
6484 {
6485 /* scrolling the result set rows */
6486 ret = sqlite3_step (stmt_edge);
6487 if (ret == SQLITE_DONE)
6488 break; /* end of result set */
6489 if (ret == SQLITE_ROW)
6490 {
6491 const unsigned char *blob = sqlite3_column_blob (stmt_edge, 0);
6492 int blob_sz = sqlite3_column_bytes (stmt_edge, 0);
6493 gaiaGeomCollPtr geom =
6494 gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
6495 if (geom != NULL)
6496 {
6497 gaiaLinestringPtr ln = geom->FirstLinestring;
6498 while (ln != NULL)
6499 {
6500 /* copying all Linestrings into the result Geometry */
6501 if (topo->has_z)
6502 auxtopo_copy_linestring3d (ln, result);
6503 else
6504 auxtopo_copy_linestring (ln, result);
6505 ln = ln->Next;
6506 }
6507 gaiaFreeGeomColl (geom);
6508 }
6509 }
6510 else
6511 {
6512 char *msg =
6513 sqlite3_mprintf
6514 ("TopoGeo_FeatureFromTopoLayer error: \"%s\"",
6515 sqlite3_errmsg (topo->db_handle));
6516 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
6517 msg);
6518 sqlite3_free (msg);
6519 return;
6520 }
6521 }
6522 }
6523
6524 static gaiaGeomCollPtr
do_eval_topo_geometry(struct gaia_topology * topo,sqlite3_stmt * stmt_rels,sqlite3_stmt * stmt_node,sqlite3_stmt * stmt_edge,sqlite3_stmt * stmt_face,sqlite3_int64 fid,sqlite3_int64 topolayer_id,int out_type)6525 do_eval_topo_geometry (struct gaia_topology *topo, sqlite3_stmt * stmt_rels,
6526 sqlite3_stmt * stmt_node, sqlite3_stmt * stmt_edge,
6527 sqlite3_stmt * stmt_face, sqlite3_int64 fid,
6528 sqlite3_int64 topolayer_id, int out_type)
6529 {
6530 /* materializing a Geometry out of Topology */
6531 int ret;
6532 gaiaGeomCollPtr geom;
6533 gaiaGeomCollPtr sparse_lines;
6534 struct face_edges *list =
6535 auxtopo_create_face_edges (topo->has_z, topo->srid);
6536
6537 if (topo->has_z)
6538 {
6539 geom = gaiaAllocGeomCollXYZ ();
6540 sparse_lines = gaiaAllocGeomCollXYZ ();
6541 }
6542 else
6543 {
6544 geom = gaiaAllocGeomColl ();
6545 sparse_lines = gaiaAllocGeomColl ();
6546 }
6547 geom->Srid = topo->srid;
6548 geom->DeclaredType = out_type;
6549
6550 sqlite3_reset (stmt_rels);
6551 sqlite3_clear_bindings (stmt_rels);
6552 sqlite3_bind_int64 (stmt_rels, 1, topolayer_id);
6553 sqlite3_bind_int64 (stmt_rels, 2, fid);
6554 while (1)
6555 {
6556 /* scrolling the result set rows */
6557 sqlite3_int64 id;
6558 ret = sqlite3_step (stmt_rels);
6559 if (ret == SQLITE_DONE)
6560 break; /* end of result set */
6561 if (ret == SQLITE_ROW)
6562 {
6563 if (sqlite3_column_type (stmt_rels, 0) != SQLITE_NULL)
6564 {
6565 id = sqlite3_column_int64 (stmt_rels, 0);
6566 do_eval_topo_node (topo, stmt_node, id, geom);
6567 }
6568 if (sqlite3_column_type (stmt_rels, 1) != SQLITE_NULL)
6569 {
6570 id = sqlite3_column_int64 (stmt_rels, 1);
6571 do_eval_topo_edge (topo, stmt_edge, id, sparse_lines);
6572 }
6573 if (sqlite3_column_type (stmt_rels, 2) != SQLITE_NULL)
6574 {
6575 id = sqlite3_column_int64 (stmt_rels, 2);
6576 do_explode_topo_face (topo, list, stmt_face, id);
6577 }
6578 }
6579 else
6580 {
6581 char *msg =
6582 sqlite3_mprintf
6583 ("TopoGeo_FeatureFromTopoLayer() error: \"%s\"",
6584 sqlite3_errmsg (topo->db_handle));
6585 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
6586 msg);
6587 sqlite3_free (msg);
6588 goto error;
6589 }
6590 }
6591
6592
6593 if (sparse_lines->FirstLinestring != NULL)
6594 {
6595 /* attempting to better rearrange sparse lines */
6596 gaiaGeomCollPtr rearranged =
6597 gaiaLineMerge_r (topo->cache, sparse_lines);
6598 gaiaFreeGeomColl (sparse_lines);
6599 if (rearranged != NULL)
6600 {
6601 gaiaLinestringPtr ln = rearranged->FirstLinestring;
6602 while (ln != NULL)
6603 {
6604 if (topo->has_z)
6605 auxtopo_copy_linestring3d (ln, geom);
6606 else
6607 auxtopo_copy_linestring (ln, geom);
6608 ln = ln->Next;
6609 }
6610 gaiaFreeGeomColl (rearranged);
6611 }
6612 }
6613 else
6614 gaiaFreeGeomColl (sparse_lines);
6615 sparse_lines = NULL;
6616
6617 if (list->first_edge != NULL)
6618 {
6619 /* attempting to rearrange sparse lines into Polygons */
6620 gaiaGeomCollPtr rearranged;
6621 auxtopo_select_valid_face_edges (list);
6622 rearranged = auxtopo_polygonize_face_edges (list, topo->cache);
6623 auxtopo_free_face_edges (list);
6624 list = NULL;
6625 if (rearranged != NULL)
6626 {
6627 gaiaPolygonPtr pg = rearranged->FirstPolygon;
6628 while (pg != NULL)
6629 {
6630 if (topo->has_z)
6631 do_copy_polygon3d (pg, geom);
6632 else
6633 do_copy_polygon (pg, geom);
6634 pg = pg->Next;
6635 }
6636 gaiaFreeGeomColl (rearranged);
6637 }
6638 }
6639
6640 if (geom->FirstPoint == NULL && geom->FirstLinestring == NULL
6641 && geom->FirstPolygon == NULL)
6642 goto error;
6643 auxtopo_free_face_edges (list);
6644 return geom;
6645
6646 error:
6647 gaiaFreeGeomColl (geom);
6648 if (sparse_lines != NULL)
6649 gaiaFreeGeomColl (sparse_lines);
6650 if (list != NULL)
6651 auxtopo_free_face_edges (list);
6652 return NULL;
6653 }
6654
6655 static int
do_eval_topogeo_features(struct gaia_topology * topo,sqlite3_stmt * stmt_ref,sqlite3_stmt * stmt_ins,sqlite3_stmt * stmt_rels,sqlite3_stmt * stmt_node,sqlite3_stmt * stmt_edge,sqlite3_stmt * stmt_face,sqlite3_int64 topolayer_id,int out_type)6656 do_eval_topogeo_features (struct gaia_topology *topo, sqlite3_stmt * stmt_ref,
6657 sqlite3_stmt * stmt_ins, sqlite3_stmt * stmt_rels,
6658 sqlite3_stmt * stmt_node, sqlite3_stmt * stmt_edge,
6659 sqlite3_stmt * stmt_face, sqlite3_int64 topolayer_id,
6660 int out_type)
6661 {
6662 /* querying the ref-table */
6663 int ret;
6664
6665 sqlite3_reset (stmt_ref);
6666 sqlite3_clear_bindings (stmt_ref);
6667 while (1)
6668 {
6669 /* scrolling the result set rows */
6670 gaiaGeomCollPtr geom = NULL;
6671 sqlite3_int64 fid;
6672 ret = sqlite3_step (stmt_ref);
6673 if (ret == SQLITE_DONE)
6674 break; /* end of result set */
6675 if (ret == SQLITE_ROW)
6676 {
6677 int icol;
6678 int ncol = sqlite3_column_count (stmt_ref);
6679 fid = sqlite3_column_int64 (stmt_ref, 0);
6680 sqlite3_reset (stmt_ins);
6681 sqlite3_clear_bindings (stmt_ins);
6682 for (icol = 0; icol < ncol; icol++)
6683 {
6684 int col_type = sqlite3_column_type (stmt_ref, icol);
6685 switch (col_type)
6686 {
6687 case SQLITE_INTEGER:
6688 sqlite3_bind_int64 (stmt_ins, icol + 1,
6689 sqlite3_column_int64 (stmt_ref,
6690 icol));
6691 break;
6692 case SQLITE_FLOAT:
6693 sqlite3_bind_double (stmt_ins, icol + 1,
6694 sqlite3_column_double
6695 (stmt_ref, icol));
6696 break;
6697 case SQLITE_TEXT:
6698 sqlite3_bind_text (stmt_ins, icol + 1,
6699 (const char *)
6700 sqlite3_column_text (stmt_ref,
6701 icol),
6702 sqlite3_column_bytes (stmt_ref,
6703 icol),
6704 SQLITE_STATIC);
6705 break;
6706 case SQLITE_BLOB:
6707 sqlite3_bind_blob (stmt_ins, icol + 1,
6708 sqlite3_column_blob (stmt_ref,
6709 icol),
6710 sqlite3_column_bytes (stmt_ref,
6711 icol),
6712 SQLITE_STATIC);
6713 break;
6714 default:
6715 sqlite3_bind_null (stmt_ins, icol + 1);
6716 break;
6717 };
6718 }
6719 /* the Geometry column */
6720 ncol = sqlite3_bind_parameter_count (stmt_ins);
6721 geom =
6722 do_eval_topo_geometry (topo, stmt_rels, stmt_node,
6723 stmt_edge, stmt_face, fid,
6724 topolayer_id, out_type);
6725 if (geom != NULL)
6726 {
6727 unsigned char *p_blob;
6728 int n_bytes;
6729 gaiaToSpatiaLiteBlobWkb (geom, &p_blob, &n_bytes);
6730 sqlite3_bind_blob (stmt_ins, ncol, p_blob, n_bytes,
6731 SQLITE_TRANSIENT);
6732 free (p_blob);
6733 gaiaFreeGeomColl (geom);
6734 }
6735 else
6736 sqlite3_bind_null (stmt_ins, ncol);
6737 ret = sqlite3_step (stmt_ins);
6738 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
6739 ;
6740 else
6741 {
6742 char *msg =
6743 sqlite3_mprintf
6744 ("TopoGeo_ExportTopoLayer() error: \"%s\"",
6745 sqlite3_errmsg (topo->db_handle));
6746 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr)
6747 topo, msg);
6748 sqlite3_free (msg);
6749 return 0;
6750 }
6751 }
6752 else
6753 {
6754 char *msg =
6755 sqlite3_mprintf ("TopoGeo_ExportTopoLayer() error: \"%s\"",
6756 sqlite3_errmsg (topo->db_handle));
6757 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
6758 msg);
6759 sqlite3_free (msg);
6760 return 0;
6761 }
6762 }
6763
6764 return 1;
6765 }
6766
6767 GAIATOPO_DECLARE int
gaiaTopoGeo_ExportTopoLayer(GaiaTopologyAccessorPtr accessor,const char * topolayer_name,const char * out_table,int with_spatial_index,int create_only)6768 gaiaTopoGeo_ExportTopoLayer (GaiaTopologyAccessorPtr accessor,
6769 const char *topolayer_name, const char *out_table,
6770 int with_spatial_index, int create_only)
6771 {
6772 /* attempting to export a full TopoLayer */
6773 struct gaia_topology *topo = (struct gaia_topology *) accessor;
6774 sqlite3_stmt *stmt_ref = NULL;
6775 sqlite3_stmt *stmt_ins = NULL;
6776 sqlite3_stmt *stmt_rels = NULL;
6777 sqlite3_stmt *stmt_node = NULL;
6778 sqlite3_stmt *stmt_edge = NULL;
6779 sqlite3_stmt *stmt_face = NULL;
6780 int ret;
6781 char *create = NULL;
6782 char *select = NULL;
6783 char *insert;
6784 char *geometry_name;
6785 char *sql;
6786 char *errMsg;
6787 char *xprefix;
6788 char *table;
6789 char *xtable;
6790 int ref_type;
6791 const char *type;
6792 int out_type;
6793 sqlite3_int64 topolayer_id;
6794 if (topo == NULL)
6795 return 0;
6796
6797 /* composing the CREATE TABLE output-table statement */
6798 if (!auxtopo_create_export_sql
6799 (topo, topolayer_name, out_table, &create,
6800 &select, &insert, &geometry_name, &topolayer_id))
6801 goto error;
6802
6803 /* creating the output-table */
6804 ret = sqlite3_exec (topo->db_handle, create, NULL, NULL, &errMsg);
6805 sqlite3_free (create);
6806 create = NULL;
6807 if (ret != SQLITE_OK)
6808 {
6809 char *msg =
6810 sqlite3_mprintf ("TopoGeo_ExportTopoLayer() error: \"%s\"",
6811 errMsg);
6812 sqlite3_free (errMsg);
6813 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
6814 sqlite3_free (msg);
6815 goto error;
6816 }
6817
6818 /* checking the Geometry Type */
6819 if (!auxtopo_retrieve_export_geometry_type
6820 (topo, topolayer_name, &ref_type))
6821 goto error;
6822 switch (ref_type)
6823 {
6824 case GAIA_POINT:
6825 type = "MULTIPOINT";
6826 out_type = GAIA_MULTIPOINT;
6827 break;
6828 case GAIA_LINESTRING:
6829 type = "MULTILINESTRING";
6830 out_type = GAIA_MULTILINESTRING;
6831 break;
6832 case GAIA_POLYGON:
6833 type = "MULTIPOLYGON";
6834 out_type = GAIA_MULTIPOLYGON;
6835 break;
6836 case GAIA_GEOMETRYCOLLECTION:
6837 type = "GEOMETRYCOLLECTION";
6838 out_type = GAIA_GEOMETRYCOLLECTION;
6839 break;
6840 default:
6841 type = "GEOMETRY";
6842 out_type = GAIA_UNKNOWN;
6843 break;
6844 };
6845
6846 /* creating the output Geometry Column */
6847 sql =
6848 sqlite3_mprintf
6849 ("SELECT AddGeometryColumn(Lower(%Q), %Q, %d, '%s', '%s')",
6850 out_table, geometry_name, topo->srid, type,
6851 (topo->has_z == 0) ? "XY" : "XYZ");
6852 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
6853 sqlite3_free (sql);
6854 if (ret != SQLITE_OK)
6855 {
6856 char *msg =
6857 sqlite3_mprintf ("TopoGeo_ExportTopoLayer() error: \"%s\"",
6858 errMsg);
6859 sqlite3_free (errMsg);
6860 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
6861 sqlite3_free (msg);
6862 goto error;
6863 }
6864
6865 if (with_spatial_index)
6866 {
6867 /* creating a Spatial Index supporting the Geometry Column */
6868 sql =
6869 sqlite3_mprintf
6870 ("SELECT CreateSpatialIndex(Lower(%Q), %Q)",
6871 out_table, geometry_name);
6872 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
6873 sqlite3_free (sql);
6874 if (ret != SQLITE_OK)
6875 {
6876 char *msg =
6877 sqlite3_mprintf ("TopoGeo_ExportTopoLayer() error: \"%s\"",
6878 errMsg);
6879 sqlite3_free (errMsg);
6880 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
6881 msg);
6882 sqlite3_free (msg);
6883 goto error;
6884 }
6885 }
6886 free (geometry_name);
6887 if (create_only)
6888 {
6889 sqlite3_free (select);
6890 sqlite3_free (insert);
6891 return 1;
6892 }
6893
6894 /* preparing the "SELECT * FROM topo-features-table" query */
6895 ret =
6896 sqlite3_prepare_v2 (topo->db_handle, select, strlen (select), &stmt_ref,
6897 NULL);
6898 sqlite3_free (select);
6899 select = NULL;
6900 if (ret != SQLITE_OK)
6901 {
6902 char *msg =
6903 sqlite3_mprintf ("TopoGeo_ExportTopoLayer() error: \"%s\"",
6904 sqlite3_errmsg (topo->db_handle));
6905 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
6906 sqlite3_free (msg);
6907 goto error;
6908 }
6909
6910 /* preparing the "INSERT INTO out-table" query */
6911 ret =
6912 sqlite3_prepare_v2 (topo->db_handle, insert, strlen (insert), &stmt_ins,
6913 NULL);
6914 sqlite3_free (insert);
6915 insert = NULL;
6916 if (ret != SQLITE_OK)
6917 {
6918 char *msg =
6919 sqlite3_mprintf ("TopoGeo_ExportTopoLayer() error: \"%s\"",
6920 sqlite3_errmsg (topo->db_handle));
6921 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
6922 sqlite3_free (msg);
6923 goto error;
6924 }
6925
6926 /* preparing the "SELECT * FROM topo-features" query */
6927 table = sqlite3_mprintf ("%s_topofeatures", topo->topology_name);
6928 xtable = gaiaDoubleQuotedSql (table);
6929 sqlite3_free (table);
6930 sql = sqlite3_mprintf ("SELECT node_id, edge_id, face_id FROM \"%s\" "
6931 "WHERE topolayer_id = ? AND fid = ?", xtable);
6932 free (xtable);
6933 ret =
6934 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_rels,
6935 NULL);
6936 sqlite3_free (sql);
6937 select = NULL;
6938 if (ret != SQLITE_OK)
6939 {
6940 char *msg =
6941 sqlite3_mprintf ("TopoGeo_ExportTopoLayer() error: \"%s\"",
6942 sqlite3_errmsg (topo->db_handle));
6943 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
6944 sqlite3_free (msg);
6945 goto error;
6946 }
6947
6948 /* preparing the Topo-Nodes query */
6949 xprefix = sqlite3_mprintf ("%s_node", topo->topology_name);
6950 xtable = gaiaDoubleQuotedSql (xprefix);
6951 sql = sqlite3_mprintf ("SELECT geom FROM MAIN.\"%s\" WHERE node_id = ?",
6952 xtable, xprefix);
6953 free (xtable);
6954 sqlite3_free (xprefix);
6955 ret =
6956 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_node,
6957 NULL);
6958 sqlite3_free (sql);
6959 if (ret != SQLITE_OK)
6960 {
6961 char *msg =
6962 sqlite3_mprintf ("TopoGeo_ExportTopoLayer() error: \"%s\"",
6963 sqlite3_errmsg (topo->db_handle));
6964 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
6965 sqlite3_free (msg);
6966 goto error;
6967 }
6968
6969 /* preparing the Topo-Edges query */
6970 xprefix = sqlite3_mprintf ("%s_edge", topo->topology_name);
6971 xtable = gaiaDoubleQuotedSql (xprefix);
6972 sql = sqlite3_mprintf ("SELECT geom FROM MAIN.\"%s\" WHERE edge_id = ?",
6973 xtable, xprefix);
6974 free (xtable);
6975 sqlite3_free (xprefix);
6976 ret =
6977 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_edge,
6978 NULL);
6979 sqlite3_free (sql);
6980 if (ret != SQLITE_OK)
6981 {
6982 char *msg =
6983 sqlite3_mprintf ("TopoGeo_ExportTopoLayer() error: \"%s\"",
6984 sqlite3_errmsg (topo->db_handle));
6985 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
6986 sqlite3_free (msg);
6987 goto error;
6988 }
6989
6990 /* preparing the Topo-Faces query */
6991 xprefix = sqlite3_mprintf ("%s_edge", topo->topology_name);
6992 xtable = gaiaDoubleQuotedSql (xprefix);
6993 sql =
6994 sqlite3_mprintf
6995 ("SELECT edge_id, left_face, right_face, geom FROM MAIN.\"%s\" "
6996 "WHERE left_face = ? OR right_face = ?", xtable);
6997 free (xtable);
6998 sqlite3_free (xprefix);
6999 ret =
7000 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_face,
7001 NULL);
7002 sqlite3_free (sql);
7003 if (ret != SQLITE_OK)
7004 {
7005 char *msg =
7006 sqlite3_mprintf ("TopoGeo_ExportTopoLayer() error: \"%s\"",
7007 sqlite3_errmsg (topo->db_handle));
7008 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
7009 sqlite3_free (msg);
7010 goto error;
7011 }
7012
7013 /* evaluating TopoLayer's Features */
7014 if (!do_eval_topogeo_features
7015 (topo, stmt_ref, stmt_ins, stmt_rels, stmt_node, stmt_edge, stmt_face,
7016 topolayer_id, out_type))
7017 goto error;
7018
7019 sqlite3_finalize (stmt_ref);
7020 sqlite3_finalize (stmt_ins);
7021 sqlite3_finalize (stmt_rels);
7022 sqlite3_finalize (stmt_node);
7023 sqlite3_finalize (stmt_edge);
7024 sqlite3_finalize (stmt_face);
7025 return 1;
7026
7027 error:
7028 if (create != NULL)
7029 sqlite3_free (create);
7030 if (select != NULL)
7031 sqlite3_free (select);
7032 if (insert != NULL)
7033 sqlite3_free (insert);
7034 if (stmt_ref != NULL)
7035 sqlite3_finalize (stmt_ref);
7036 if (stmt_ins != NULL)
7037 sqlite3_finalize (stmt_ins);
7038 if (stmt_rels != NULL)
7039 sqlite3_finalize (stmt_rels);
7040 if (stmt_node != NULL)
7041 sqlite3_finalize (stmt_node);
7042 if (stmt_edge != NULL)
7043 sqlite3_finalize (stmt_edge);
7044 if (stmt_face != NULL)
7045 sqlite3_finalize (stmt_face);
7046 return 0;
7047 }
7048
7049 static int
check_output_table(struct gaia_topology * topo,const char * out_table,int * out_type)7050 check_output_table (struct gaia_topology *topo, const char *out_table,
7051 int *out_type)
7052 {
7053 /* checking the output table */
7054 char *sql;
7055 int ret;
7056 int i;
7057 char **results;
7058 int rows;
7059 int columns;
7060 int count = 0;
7061 int type;
7062
7063 sql =
7064 sqlite3_mprintf
7065 ("SELECT geometry_type FROM MAIN.geometry_columns WHERE f_table_name = Lower(%Q)",
7066 out_table);
7067 ret =
7068 sqlite3_get_table (topo->db_handle, sql, &results, &rows, &columns,
7069 NULL);
7070 sqlite3_free (sql);
7071 if (ret != SQLITE_OK)
7072 return 0;
7073 if (rows < 1)
7074 ;
7075 else
7076 {
7077 for (i = 1; i <= rows; i++)
7078 {
7079 type = atoi (results[(i * columns) + 0]);
7080 count++;
7081 }
7082 }
7083 sqlite3_free_table (results);
7084
7085 if (count != 1)
7086 return 0;
7087
7088 switch (type)
7089 {
7090 case GAIA_POINT:
7091 case GAIA_POINTZ:
7092 case GAIA_POINTM:
7093 case GAIA_POINTZM:
7094 *out_type = GAIA_POINT;
7095 break;
7096 case GAIA_MULTIPOINT:
7097 case GAIA_MULTIPOINTZ:
7098 case GAIA_MULTIPOINTM:
7099 case GAIA_MULTIPOINTZM:
7100 *out_type = GAIA_MULTIPOINT;
7101 break;
7102 case GAIA_LINESTRING:
7103 case GAIA_LINESTRINGZ:
7104 case GAIA_LINESTRINGM:
7105 case GAIA_LINESTRINGZM:
7106 case GAIA_MULTILINESTRING:
7107 case GAIA_MULTILINESTRINGZ:
7108 case GAIA_MULTILINESTRINGM:
7109 case GAIA_MULTILINESTRINGZM:
7110 *out_type = GAIA_MULTILINESTRING;
7111 break;
7112 case GAIA_POLYGON:
7113 case GAIA_POLYGONZ:
7114 case GAIA_POLYGONM:
7115 case GAIA_POLYGONZM:
7116 case GAIA_MULTIPOLYGON:
7117 case GAIA_MULTIPOLYGONZ:
7118 case GAIA_MULTIPOLYGONM:
7119 case GAIA_MULTIPOLYGONZM:
7120 *out_type = GAIA_MULTIPOLYGON;
7121 break;
7122 case GAIA_GEOMETRYCOLLECTION:
7123 case GAIA_GEOMETRYCOLLECTIONZ:
7124 case GAIA_GEOMETRYCOLLECTIONM:
7125 case GAIA_GEOMETRYCOLLECTIONZM:
7126 *out_type = GAIA_GEOMETRYCOLLECTION;
7127 break;
7128 default:
7129 *out_type = GAIA_UNKNOWN;
7130 break;
7131 };
7132 return 1;
7133 }
7134
7135 static int
auxtopo_export_feature_sql(struct gaia_topology * topo,const char * topolayer_name,const char * out_table,char ** xselect,char ** xinsert,sqlite3_int64 * topolayer_id,int * out_type)7136 auxtopo_export_feature_sql (struct gaia_topology *topo,
7137 const char *topolayer_name, const char *out_table,
7138 char **xselect, char **xinsert,
7139 sqlite3_int64 * topolayer_id, int *out_type)
7140 {
7141 /* composing the CREATE TABLE insert-feature statement */
7142 char *select = NULL;
7143 char *insert = NULL;
7144 char *prev;
7145 char *sql;
7146 char *table;
7147 char *xtable;
7148 char *xprefix;
7149 char dummy[64];
7150 int i;
7151 char **results;
7152 int rows;
7153 int columns;
7154 const char *name;
7155 int ret;
7156 int first_select = 1;
7157 int first_insert = 1;
7158 int ncols = 0;
7159 int icol;
7160 int ref_col = 0;
7161 char *geometry_name = NULL;
7162 int geom_alias = 0;
7163
7164 *xselect = NULL;
7165 *xinsert = NULL;
7166
7167 /* checking the TopoLayer */
7168 if (!check_topolayer (topo, topolayer_name, topolayer_id))
7169 return 0;
7170
7171 /* checking the output table */
7172 if (!check_output_table (topo, out_table, out_type))
7173 return 0;
7174
7175 xtable = gaiaDoubleQuotedSql (out_table);
7176 select = sqlite3_mprintf ("SELECT fid, ");
7177 insert = sqlite3_mprintf ("INSERT INTO MAIN.\"%s\" (fid, ", xtable);
7178 free (xtable);
7179 sprintf (dummy, "%lld", *topolayer_id);
7180 table = sqlite3_mprintf ("%s_topofeatures_%s", topo->topology_name, dummy);
7181 xtable = gaiaDoubleQuotedSql (table);
7182 sqlite3_free (table);
7183 sql = sqlite3_mprintf ("PRAGMA MAIN.table_info(\"%s\")", xtable);
7184 free (xtable);
7185 ret =
7186 sqlite3_get_table (topo->db_handle, sql, &results, &rows, &columns,
7187 NULL);
7188 sqlite3_free (sql);
7189 if (ret != SQLITE_OK)
7190 goto error;
7191 if (rows < 1)
7192 ;
7193 else
7194 {
7195 for (i = 1; i <= rows; i++)
7196 {
7197 name = results[(i * columns) + 1];
7198 if (strcmp (name, "fid") == 0)
7199 continue;
7200 /* SELECT: adding a column */
7201 xprefix = gaiaDoubleQuotedSql (name);
7202 prev = select;
7203 if (first_select)
7204 select = sqlite3_mprintf ("%s\"%s\"", prev, xprefix);
7205 else
7206 select = sqlite3_mprintf ("%s, \"%s\"", prev, xprefix);
7207 first_select = 0;
7208 free (xprefix);
7209 sqlite3_free (prev);
7210 ref_col++;
7211 /* INSERT: adding a column */
7212 xprefix = gaiaDoubleQuotedSql (name);
7213 prev = insert;
7214 if (first_insert)
7215 insert = sqlite3_mprintf ("%s\"%s\"", prev, xprefix);
7216 else
7217 insert = sqlite3_mprintf ("%s, \"%s\"", prev, xprefix);
7218 first_insert = 0;
7219 free (xprefix);
7220 sqlite3_free (prev);
7221 ncols++;
7222 }
7223 }
7224 sqlite3_free_table (results);
7225
7226 geometry_name = malloc (strlen ("geometry") + 1);
7227 strcpy (geometry_name, "geometry");
7228 sprintf (dummy, "%lld", *topolayer_id);
7229 table = sqlite3_mprintf ("%s_topofeatures_%s", topo->topology_name, dummy);
7230 while (1)
7231 {
7232 /* searching an unique Geometry name */
7233 if (is_unique_geom_name (topo->db_handle, table, geometry_name))
7234 break;
7235 sprintf (dummy, "geom_%d", ++geom_alias);
7236 free (geometry_name);
7237 geometry_name = malloc (strlen (dummy) + 1);
7238 strcpy (geometry_name, dummy);
7239 }
7240 sqlite3_free (table);
7241
7242 /* completing the SQL statements */
7243 prev = select;
7244 sprintf (dummy, "%lld", *topolayer_id);
7245 table = sqlite3_mprintf ("%s_topofeatures_%s", topo->topology_name, dummy);
7246 xtable = gaiaDoubleQuotedSql (table);
7247 sqlite3_free (table);
7248 select =
7249 sqlite3_mprintf ("%s FROM MAIN.\"%s\" WHERE fid = ?", prev, xtable);
7250 free (xtable);
7251 sqlite3_free (prev);
7252 prev = insert;
7253 insert = sqlite3_mprintf ("%s, \"%s\") VALUES (?, ", prev, geometry_name);
7254 sqlite3_free (prev);
7255 for (icol = 0; icol < ncols; icol++)
7256 {
7257 prev = insert;
7258 if (icol == 0)
7259 insert = sqlite3_mprintf ("%s?", prev);
7260 else
7261 insert = sqlite3_mprintf ("%s, ?", prev);
7262 sqlite3_free (prev);
7263 }
7264 prev = insert;
7265 insert = sqlite3_mprintf ("%s, ?)", prev);
7266 sqlite3_free (prev);
7267
7268 free (geometry_name);
7269 *xselect = select;
7270 *xinsert = insert;
7271 return 1;
7272
7273 error:
7274 if (geometry_name != NULL)
7275 free (geometry_name);
7276 if (select != NULL)
7277 sqlite3_free (select);
7278 if (insert != NULL)
7279 sqlite3_free (insert);
7280 return 0;
7281 }
7282
7283 static int
do_eval_topogeo_single_feature(struct gaia_topology * topo,sqlite3_stmt * stmt_ref,sqlite3_stmt * stmt_ins,sqlite3_stmt * stmt_rels,sqlite3_stmt * stmt_node,sqlite3_stmt * stmt_edge,sqlite3_stmt * stmt_face,sqlite3_int64 topolayer_id,int out_type,sqlite3_int64 fid)7284 do_eval_topogeo_single_feature (struct gaia_topology *topo,
7285 sqlite3_stmt * stmt_ref,
7286 sqlite3_stmt * stmt_ins,
7287 sqlite3_stmt * stmt_rels,
7288 sqlite3_stmt * stmt_node,
7289 sqlite3_stmt * stmt_edge,
7290 sqlite3_stmt * stmt_face,
7291 sqlite3_int64 topolayer_id, int out_type,
7292 sqlite3_int64 fid)
7293 {
7294 /* querying the ref-table */
7295 int ret;
7296 int count = 0;
7297
7298 sqlite3_reset (stmt_ref);
7299 sqlite3_clear_bindings (stmt_ref);
7300 sqlite3_bind_int64 (stmt_ref, 1, fid);
7301 while (1)
7302 {
7303 /* scrolling the result set rows */
7304 gaiaGeomCollPtr geom = NULL;
7305 ret = sqlite3_step (stmt_ref);
7306 if (ret == SQLITE_DONE)
7307 break; /* end of result set */
7308 if (ret == SQLITE_ROW)
7309 {
7310 int icol;
7311 int ncol = sqlite3_column_count (stmt_ref);
7312 sqlite3_reset (stmt_ins);
7313 sqlite3_clear_bindings (stmt_ins);
7314 for (icol = 0; icol < ncol; icol++)
7315 {
7316 int col_type = sqlite3_column_type (stmt_ref, icol);
7317 switch (col_type)
7318 {
7319 case SQLITE_INTEGER:
7320 sqlite3_bind_int64 (stmt_ins, icol + 1,
7321 sqlite3_column_int64 (stmt_ref,
7322 icol));
7323 break;
7324 case SQLITE_FLOAT:
7325 sqlite3_bind_double (stmt_ins, icol + 1,
7326 sqlite3_column_double
7327 (stmt_ref, icol));
7328 break;
7329 case SQLITE_TEXT:
7330 sqlite3_bind_text (stmt_ins, icol + 1,
7331 (const char *)
7332 sqlite3_column_text (stmt_ref,
7333 icol),
7334 sqlite3_column_bytes (stmt_ref,
7335 icol),
7336 SQLITE_STATIC);
7337 break;
7338 case SQLITE_BLOB:
7339 sqlite3_bind_blob (stmt_ins, icol + 1,
7340 sqlite3_column_blob (stmt_ref,
7341 icol),
7342 sqlite3_column_bytes (stmt_ref,
7343 icol),
7344 SQLITE_STATIC);
7345 break;
7346 default:
7347 sqlite3_bind_null (stmt_ins, icol + 1);
7348 break;
7349 };
7350 }
7351 /* the Geometry column */
7352 ncol = sqlite3_bind_parameter_count (stmt_ins);
7353 geom =
7354 do_eval_topo_geometry (topo, stmt_rels, stmt_node,
7355 stmt_edge, stmt_face, fid,
7356 topolayer_id, out_type);
7357 if (geom != NULL)
7358 {
7359 unsigned char *p_blob;
7360 int n_bytes;
7361 gaiaToSpatiaLiteBlobWkb (geom, &p_blob, &n_bytes);
7362 sqlite3_bind_blob (stmt_ins, ncol, p_blob, n_bytes,
7363 SQLITE_TRANSIENT);
7364 free (p_blob);
7365 gaiaFreeGeomColl (geom);
7366 }
7367 else
7368 sqlite3_bind_null (stmt_ins, ncol);
7369 ret = sqlite3_step (stmt_ins);
7370 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
7371 ;
7372 else
7373 {
7374 char *msg =
7375 sqlite3_mprintf
7376 ("InsertFeatureFromTopoLayer() error: \"%s\"",
7377 sqlite3_errmsg (topo->db_handle));
7378 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr)
7379 topo, msg);
7380 sqlite3_free (msg);
7381 return 0;
7382 }
7383 count++;
7384 }
7385 else
7386 {
7387 char *msg =
7388 sqlite3_mprintf
7389 ("InsertFeatureFromTopoLayer() error: \"%s\"",
7390 sqlite3_errmsg (topo->db_handle));
7391 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
7392 msg);
7393 sqlite3_free (msg);
7394 return 0;
7395 }
7396 }
7397
7398 if (count <= 0)
7399 {
7400 char *msg =
7401 sqlite3_mprintf
7402 ("InsertFeatureFromTopoLayer(): not existing TopoFeature");
7403 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
7404 sqlite3_free (msg);
7405 return 0;
7406 }
7407 return 1;
7408 }
7409
7410 GAIATOPO_DECLARE int
gaiaTopoGeo_InsertFeatureFromTopoLayer(GaiaTopologyAccessorPtr accessor,const char * topolayer_name,const char * out_table,sqlite3_int64 fid)7411 gaiaTopoGeo_InsertFeatureFromTopoLayer (GaiaTopologyAccessorPtr accessor,
7412 const char *topolayer_name,
7413 const char *out_table,
7414 sqlite3_int64 fid)
7415 {
7416 /* attempting to insert a single TopoLayer's Feature into the output GeoTable */
7417 struct gaia_topology *topo = (struct gaia_topology *) accessor;
7418 sqlite3_stmt *stmt_ref = NULL;
7419 sqlite3_stmt *stmt_ins = NULL;
7420 sqlite3_stmt *stmt_rels = NULL;
7421 sqlite3_stmt *stmt_node = NULL;
7422 sqlite3_stmt *stmt_edge = NULL;
7423 sqlite3_stmt *stmt_face = NULL;
7424 int ret;
7425 char *select;
7426 char *insert;
7427 char *sql;
7428 char *xprefix;
7429 char *table;
7430 char *xtable;
7431 int out_type;
7432 sqlite3_int64 topolayer_id;
7433 if (topo == NULL)
7434 return 0;
7435
7436 /* composing the SQL statements */
7437 if (!auxtopo_export_feature_sql
7438 (topo, topolayer_name, out_table, &select, &insert, &topolayer_id,
7439 &out_type))
7440 goto error;
7441
7442 /* preparing the "SELECT * FROM topo-features-table" query */
7443 ret =
7444 sqlite3_prepare_v2 (topo->db_handle, select, strlen (select), &stmt_ref,
7445 NULL);
7446 sqlite3_free (select);
7447 select = NULL;
7448 if (ret != SQLITE_OK)
7449 {
7450 char *msg =
7451 sqlite3_mprintf ("InsertFeatureFromTopoLayer() error: \"%s\"",
7452 sqlite3_errmsg (topo->db_handle));
7453 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
7454 sqlite3_free (msg);
7455 goto error;
7456 }
7457
7458 /* preparing the "INSERT INTO out-table" query */
7459 ret =
7460 sqlite3_prepare_v2 (topo->db_handle, insert, strlen (insert), &stmt_ins,
7461 NULL);
7462 sqlite3_free (insert);
7463 insert = NULL;
7464 if (ret != SQLITE_OK)
7465 {
7466 char *msg =
7467 sqlite3_mprintf ("InsertFeatureFromTopoLayer() error: \"%s\"",
7468 sqlite3_errmsg (topo->db_handle));
7469 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
7470 goto error;
7471 }
7472
7473 /* preparing the "SELECT * FROM topo-features" query */
7474 table = sqlite3_mprintf ("%s_topofeatures", topo->topology_name);
7475 xtable = gaiaDoubleQuotedSql (table);
7476 sqlite3_free (table);
7477 sql = sqlite3_mprintf ("SELECT node_id, edge_id, face_id FROM \"%s\" "
7478 "WHERE topolayer_id = ? AND fid = ?", xtable);
7479 free (xtable);
7480 ret =
7481 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_rels,
7482 NULL);
7483 sqlite3_free (sql);
7484 select = NULL;
7485 if (ret != SQLITE_OK)
7486 {
7487 char *msg =
7488 sqlite3_mprintf ("InsertFeatureFromTopoLayer() error: \"%s\"",
7489 sqlite3_errmsg (topo->db_handle));
7490 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
7491 sqlite3_free (msg);
7492 goto error;
7493 }
7494
7495 /* preparing the Topo-Nodes query */
7496 xprefix = sqlite3_mprintf ("%s_node", topo->topology_name);
7497 xtable = gaiaDoubleQuotedSql (xprefix);
7498 sql = sqlite3_mprintf ("SELECT geom FROM MAIN.\"%s\" WHERE node_id = ?",
7499 xtable, xprefix);
7500 free (xtable);
7501 sqlite3_free (xprefix);
7502 ret =
7503 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_node,
7504 NULL);
7505 sqlite3_free (sql);
7506 if (ret != SQLITE_OK)
7507 {
7508 char *msg =
7509 sqlite3_mprintf ("InsertFeatureFromTopoLayer() error: \"%s\"",
7510 sqlite3_errmsg (topo->db_handle));
7511 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
7512 sqlite3_free (msg);
7513 goto error;
7514 }
7515
7516 /* preparing the Topo-Edges query */
7517 xprefix = sqlite3_mprintf ("%s_edge", topo->topology_name);
7518 xtable = gaiaDoubleQuotedSql (xprefix);
7519 sql = sqlite3_mprintf ("SELECT geom FROM MAIN.\"%s\" WHERE edge_id = ?",
7520 xtable, xprefix);
7521 free (xtable);
7522 sqlite3_free (xprefix);
7523 ret =
7524 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_edge,
7525 NULL);
7526 sqlite3_free (sql);
7527 if (ret != SQLITE_OK)
7528 {
7529 char *msg =
7530 sqlite3_mprintf ("InsertFeatureFromTopoLayer() error: \"%s\"",
7531 sqlite3_errmsg (topo->db_handle));
7532 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
7533 sqlite3_free (msg);
7534 goto error;
7535 }
7536
7537 /* preparing the Topo-Faces query */
7538 xprefix = sqlite3_mprintf ("%s_edge", topo->topology_name);
7539 xtable = gaiaDoubleQuotedSql (xprefix);
7540 sql =
7541 sqlite3_mprintf
7542 ("SELECT edge_id, left_face, right_face, geom FROM MAIN.\"%s\" "
7543 "WHERE left_face = ? OR right_face = ?", xtable);
7544 free (xtable);
7545 sqlite3_free (xprefix);
7546 ret =
7547 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_face,
7548 NULL);
7549 sqlite3_free (sql);
7550 if (ret != SQLITE_OK)
7551 {
7552 char *msg =
7553 sqlite3_mprintf ("InsertFeatureFromTopoLayer() error: \"%s\"",
7554 sqlite3_errmsg (topo->db_handle));
7555 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
7556 sqlite3_free (msg);
7557 goto error;
7558 }
7559
7560 /* evaluating TopoLayer's Features */
7561 if (!do_eval_topogeo_single_feature
7562 (topo, stmt_ref, stmt_ins, stmt_rels, stmt_node, stmt_edge, stmt_face,
7563 topolayer_id, out_type, fid))
7564 goto error;
7565
7566 sqlite3_finalize (stmt_ref);
7567 sqlite3_finalize (stmt_ins);
7568 sqlite3_finalize (stmt_rels);
7569 sqlite3_finalize (stmt_node);
7570 sqlite3_finalize (stmt_edge);
7571 sqlite3_finalize (stmt_face);
7572 return 1;
7573
7574 error:
7575 if (select != NULL)
7576 sqlite3_free (select);
7577 if (insert != NULL)
7578 sqlite3_free (insert);
7579 if (stmt_ref != NULL)
7580 sqlite3_finalize (stmt_ref);
7581 if (stmt_ins != NULL)
7582 sqlite3_finalize (stmt_ins);
7583 if (stmt_rels != NULL)
7584 sqlite3_finalize (stmt_rels);
7585 if (stmt_node != NULL)
7586 sqlite3_finalize (stmt_node);
7587 if (stmt_edge != NULL)
7588 sqlite3_finalize (stmt_edge);
7589 if (stmt_face != NULL)
7590 sqlite3_finalize (stmt_face);
7591 return 0;
7592 }
7593
7594 static int
do_topo_snap(struct gaia_topology * topo,int geom_col,int geo_type,double tolerance_snap,double tolerance_removal,int iterate,sqlite3_stmt * stmt_in,sqlite3_stmt * stmt_out)7595 do_topo_snap (struct gaia_topology *topo, int geom_col, int geo_type,
7596 double tolerance_snap, double tolerance_removal, int iterate,
7597 sqlite3_stmt * stmt_in, sqlite3_stmt * stmt_out)
7598 {
7599 /* snapping geometries againt Topology */
7600 int ret;
7601
7602 sqlite3_reset (stmt_in);
7603 sqlite3_clear_bindings (stmt_in);
7604 while (1)
7605 {
7606 /* scrolling the result set rows */
7607 ret = sqlite3_step (stmt_in);
7608 if (ret == SQLITE_DONE)
7609 break; /* end of result set */
7610 if (ret == SQLITE_ROW)
7611 {
7612 int icol;
7613 int ncol = sqlite3_column_count (stmt_in);
7614 sqlite3_reset (stmt_out);
7615 sqlite3_clear_bindings (stmt_out);
7616 for (icol = 0; icol < ncol; icol++)
7617 {
7618 int col_type = sqlite3_column_type (stmt_in, icol);
7619 if (icol == geom_col)
7620 {
7621 /* the geometry column */
7622 const unsigned char *blob =
7623 sqlite3_column_blob (stmt_in, icol);
7624 int blob_sz = sqlite3_column_bytes (stmt_in, icol);
7625 gaiaGeomCollPtr geom =
7626 gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
7627 if (geom != NULL)
7628 {
7629 gaiaGeomCollPtr result;
7630 unsigned char *p_blob;
7631 int n_bytes;
7632 int gpkg_mode = 0;
7633 int tiny_point = 0;
7634 if (topo->cache != NULL)
7635 {
7636 struct splite_internal_cache *cache =
7637 (struct splite_internal_cache
7638 *) (topo->cache);
7639 gpkg_mode = cache->gpkg_mode;
7640 tiny_point = cache->tinyPointEnabled;
7641 }
7642 result =
7643 gaiaTopoSnap ((GaiaTopologyAccessorPtr)
7644 topo, geom, tolerance_snap,
7645 tolerance_removal, iterate);
7646 gaiaFreeGeomColl (geom);
7647 if (result != NULL)
7648 {
7649 result->DeclaredType = geo_type;
7650 gaiaToSpatiaLiteBlobWkbEx2 (result,
7651 &p_blob,
7652 &n_bytes,
7653 gpkg_mode,
7654 tiny_point);
7655 gaiaFreeGeomColl (result);
7656 sqlite3_bind_blob (stmt_out, icol + 1,
7657 p_blob, n_bytes,
7658 free);
7659 }
7660 else
7661 sqlite3_bind_null (stmt_out, icol + 1);
7662 }
7663 else
7664 sqlite3_bind_null (stmt_out, icol + 1);
7665 continue;
7666 }
7667 switch (col_type)
7668 {
7669 case SQLITE_INTEGER:
7670 sqlite3_bind_int64 (stmt_out, icol + 1,
7671 sqlite3_column_int64 (stmt_in,
7672 icol));
7673 break;
7674 case SQLITE_FLOAT:
7675 sqlite3_bind_double (stmt_out, icol + 1,
7676 sqlite3_column_double
7677 (stmt_in, icol));
7678 break;
7679 case SQLITE_TEXT:
7680 sqlite3_bind_text (stmt_out, icol + 1,
7681 (const char *)
7682 sqlite3_column_text (stmt_in,
7683 icol),
7684 sqlite3_column_bytes (stmt_in,
7685 icol),
7686 SQLITE_STATIC);
7687 break;
7688 case SQLITE_BLOB:
7689 sqlite3_bind_blob (stmt_out, icol + 1,
7690 sqlite3_column_blob (stmt_in,
7691 icol),
7692 sqlite3_column_bytes (stmt_in,
7693 icol),
7694 SQLITE_STATIC);
7695 break;
7696 default:
7697 sqlite3_bind_null (stmt_out, icol + 1);
7698 break;
7699 };
7700 }
7701 ret = sqlite3_step (stmt_out);
7702 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
7703 ;
7704 else
7705 {
7706 char *msg =
7707 sqlite3_mprintf
7708 ("TopoGeo_SnappedGeoTable() error: \"%s\"",
7709 sqlite3_errmsg (topo->db_handle));
7710 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr)
7711 topo, msg);
7712 sqlite3_free (msg);
7713 return 0;
7714 }
7715 }
7716 else
7717 {
7718 char *msg =
7719 sqlite3_mprintf ("TopoGeo_SnappedGeoTable() error: \"%s\"",
7720 sqlite3_errmsg (topo->db_handle));
7721 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
7722 msg);
7723 sqlite3_free (msg);
7724 return 0;
7725 }
7726 }
7727 return 1;
7728 }
7729
7730 GAIATOPO_DECLARE int
gaiaTopoGeo_SnappedGeoTable(GaiaTopologyAccessorPtr accessor,const char * db_prefix,const char * table,const char * column,const char * out_table,double tolerance_snap,double tolerance_removal,int iterate)7731 gaiaTopoGeo_SnappedGeoTable (GaiaTopologyAccessorPtr accessor,
7732 const char *db_prefix, const char *table,
7733 const char *column, const char *out_table,
7734 double tolerance_snap, double tolerance_removal,
7735 int iterate)
7736 {
7737 /*
7738 / attempting to create and populate a new GeoTable by snapping all Geometries
7739 / contained into another GeoTable against a given Topology
7740 */
7741 struct gaia_topology *topo = (struct gaia_topology *) accessor;
7742 sqlite3_stmt *stmt_in = NULL;
7743 sqlite3_stmt *stmt_out = NULL;
7744 int ret;
7745 char *create;
7746 char *select;
7747 char *insert;
7748 char *sql;
7749 char *errMsg;
7750 int geo_type;
7751 const char *type;
7752 int geom_col;
7753 if (topo == NULL)
7754 return 0;
7755
7756 /* composing the CREATE TABLE output-table statement */
7757 if (!auxtopo_create_togeotable_sql
7758 (topo->db_handle, db_prefix, table, column, out_table, &create,
7759 &select, &insert, &geom_col))
7760 goto error;
7761
7762 /* creating the output-table */
7763 ret = sqlite3_exec (topo->db_handle, create, NULL, NULL, &errMsg);
7764 sqlite3_free (create);
7765 create = NULL;
7766 if (ret != SQLITE_OK)
7767 {
7768 char *msg =
7769 sqlite3_mprintf ("TopoGeo_SnappedGeoTable() error: \"%s\"",
7770 errMsg);
7771 sqlite3_free (errMsg);
7772 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
7773 sqlite3_free (msg);
7774 goto error;
7775 }
7776
7777 /* checking the Geometry Type */
7778 if (!auxtopo_retrieve_geometry_type
7779 (topo->db_handle, db_prefix, table, column, &geo_type))
7780 goto error;
7781 switch (geo_type)
7782 {
7783 case GAIA_POINT:
7784 case GAIA_POINTZ:
7785 case GAIA_POINTM:
7786 case GAIA_POINTZM:
7787 type = "POINT";
7788 break;
7789 case GAIA_MULTIPOINT:
7790 case GAIA_MULTIPOINTZ:
7791 case GAIA_MULTIPOINTM:
7792 case GAIA_MULTIPOINTZM:
7793 type = "MULTIPOINT";
7794 break;
7795 case GAIA_LINESTRING:
7796 case GAIA_LINESTRINGZ:
7797 case GAIA_LINESTRINGM:
7798 case GAIA_LINESTRINGZM:
7799 type = "LINESTRING";
7800 break;
7801 case GAIA_MULTILINESTRING:
7802 case GAIA_MULTILINESTRINGZ:
7803 case GAIA_MULTILINESTRINGM:
7804 case GAIA_MULTILINESTRINGZM:
7805 type = "MULTILINESTRING";
7806 break;
7807 case GAIA_POLYGON:
7808 case GAIA_POLYGONZ:
7809 case GAIA_POLYGONM:
7810 case GAIA_POLYGONZM:
7811 type = "POLYGON";
7812 break;
7813 case GAIA_MULTIPOLYGON:
7814 case GAIA_MULTIPOLYGONZ:
7815 case GAIA_MULTIPOLYGONM:
7816 case GAIA_MULTIPOLYGONZM:
7817 type = "MULTIPOLYGON";
7818 break;
7819 case GAIA_GEOMETRYCOLLECTION:
7820 case GAIA_GEOMETRYCOLLECTIONZ:
7821 case GAIA_GEOMETRYCOLLECTIONM:
7822 case GAIA_GEOMETRYCOLLECTIONZM:
7823 type = "GEOMETRYCOLLECTION";
7824 break;
7825 default:
7826 type = "GEOMETRY";
7827 break;
7828 };
7829
7830 /* creating the output Geometry Column */
7831 sql =
7832 sqlite3_mprintf
7833 ("SELECT AddGeometryColumn(Lower(%Q), Lower(%Q), %d, '%s', '%s')",
7834 out_table, column, topo->srid, type,
7835 (topo->has_z == 0) ? "XY" : "XYZ");
7836 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
7837 sqlite3_free (sql);
7838 if (ret != SQLITE_OK)
7839 {
7840 char *msg =
7841 sqlite3_mprintf ("TopoGeo_SnappedGeoTable() error: \"%s\"",
7842 errMsg);
7843 sqlite3_free (errMsg);
7844 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
7845 sqlite3_free (msg);
7846 goto error;
7847 }
7848
7849 /* preparing the "SELECT * FROM ref-table" query */
7850 ret =
7851 sqlite3_prepare_v2 (topo->db_handle, select, strlen (select), &stmt_in,
7852 NULL);
7853 sqlite3_free (select);
7854 select = NULL;
7855 if (ret != SQLITE_OK)
7856 {
7857 char *msg =
7858 sqlite3_mprintf ("TopoGeo_SnappedGeoTable() error: \"%s\"",
7859 sqlite3_errmsg (topo->db_handle));
7860 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
7861 sqlite3_free (msg);
7862 goto error;
7863 }
7864
7865 /* preparing the "INSERT INTO out-table" query */
7866 ret =
7867 sqlite3_prepare_v2 (topo->db_handle, insert, strlen (insert), &stmt_out,
7868 NULL);
7869 sqlite3_free (insert);
7870 insert = NULL;
7871 if (ret != SQLITE_OK)
7872 {
7873 char *msg =
7874 sqlite3_mprintf ("TopoGeo_SnappedGeoTable() error: \"%s\"",
7875 sqlite3_errmsg (topo->db_handle));
7876 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
7877 sqlite3_free (msg);
7878 goto error;
7879 }
7880
7881 /* snapping all Geometries against the Topology */
7882 if (!do_topo_snap
7883 (topo, geom_col, geo_type, tolerance_snap, tolerance_removal, iterate,
7884 stmt_in, stmt_out))
7885 goto error;
7886
7887 sqlite3_finalize (stmt_in);
7888 sqlite3_finalize (stmt_out);
7889 return 1;
7890
7891 error:
7892 if (create != NULL)
7893 sqlite3_free (create);
7894 if (select != NULL)
7895 sqlite3_free (select);
7896 if (insert != NULL)
7897 sqlite3_free (insert);
7898 if (stmt_in != NULL)
7899 sqlite3_finalize (stmt_in);
7900 if (stmt_out != NULL)
7901 sqlite3_finalize (stmt_out);
7902 return 0;
7903 }
7904
7905 SPATIALITE_PRIVATE int
test_inconsistent_topology(const void * handle)7906 test_inconsistent_topology (const void *handle)
7907 {
7908 /* testing for a Topology presenting an inconsistent state */
7909 struct gaia_topology *topo = (struct gaia_topology *) handle;
7910 int ret;
7911 char *errMsg = NULL;
7912 int count = 0;
7913 int i;
7914 char **results;
7915 int rows;
7916 int columns;
7917 char *sql;
7918 char *table;
7919 char *xtable;
7920
7921 table = sqlite3_mprintf ("%s_edge", topo->topology_name);
7922 xtable = gaiaDoubleQuotedSql (table);
7923 sqlite3_free (table);
7924 sql =
7925 sqlite3_mprintf ("SELECT Count(*) FROM \"%s\" WHERE left_face IS NULL "
7926 "OR right_face IS NULL", xtable);
7927 free (xtable);
7928 ret =
7929 sqlite3_get_table (topo->db_handle, sql, &results, &rows, &columns,
7930 &errMsg);
7931 sqlite3_free (sql);
7932 if (ret != SQLITE_OK)
7933 {
7934 spatialite_e ("test_inconsistent_topology error: %s\n", errMsg);
7935 sqlite3_free (errMsg);
7936 return -1;
7937 }
7938 for (i = 1; i <= rows; i++)
7939 count = atoi (results[(i * columns) + 0]);
7940 sqlite3_free_table (results);
7941 return count;
7942 }
7943
7944 static int
topoGeo_EdgeHeal_common(GaiaTopologyAccessorPtr accessor,int mode_new)7945 topoGeo_EdgeHeal_common (GaiaTopologyAccessorPtr accessor, int mode_new)
7946 {
7947 /* common implementation of GeoTable EdgeHeal */
7948 struct gaia_topology *topo = (struct gaia_topology *) accessor;
7949 int ret;
7950 char *sql;
7951 char *node;
7952 char *xnode;
7953 char *edge;
7954 char *xedge;
7955 int loop = 1;
7956 int loop_count;
7957 sqlite3_stmt *stmt1 = NULL;
7958 sqlite3_stmt *stmt2 = NULL;
7959 sqlite3_stmt *stmt3 = NULL;
7960 if (topo == NULL)
7961 return 0;
7962
7963 ret = test_inconsistent_topology (accessor);
7964 if (ret != 0)
7965 return 0;
7966
7967 /* preparing the SQL query identifying all Nodes of cardinality = 2 */
7968 node = sqlite3_mprintf ("%s_node", topo->topology_name);
7969 xnode = gaiaDoubleQuotedSql (node);
7970 sqlite3_free (node);
7971 edge = sqlite3_mprintf ("%s_edge", topo->topology_name);
7972 xedge = gaiaDoubleQuotedSql (edge);
7973 sqlite3_free (edge);
7974 sql =
7975 sqlite3_mprintf ("SELECT n.node_id, Count(*) AS cnt FROM \"%s\" AS n "
7976 "JOIN \"%s\" AS e ON (n.node_id = e.start_node OR n.node_id = e.end_node) "
7977 "GROUP BY n.node_id HAVING cnt = 2", xnode, xedge);
7978 free (xnode);
7979 free (xedge);
7980 ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt1, NULL);
7981 sqlite3_free (sql);
7982 if (ret != SQLITE_OK)
7983 {
7984 char *msg = sqlite3_mprintf ("TopoGeo_%sEdgeHeal error: \"%s\"",
7985 mode_new ? "New" : "Mod",
7986 sqlite3_errmsg (topo->db_handle));
7987 gaiatopo_set_last_error_msg (accessor, msg);
7988 sqlite3_free (msg);
7989 goto error;
7990 }
7991
7992 /* preparing the SQL query identifying a couple of Edges to be Healed */
7993 node = sqlite3_mprintf ("%s_node", topo->topology_name);
7994 xnode = gaiaDoubleQuotedSql (node);
7995 sqlite3_free (node);
7996 edge = sqlite3_mprintf ("%s_edge", topo->topology_name);
7997 xedge = gaiaDoubleQuotedSql (edge);
7998 sqlite3_free (edge);
7999 sql =
8000 sqlite3_mprintf ("SELECT e.edge_id FROM \"%s\" AS n "
8001 "JOIN \"%s\" AS e ON (n.node_id = e.start_node OR n.node_id = e.end_node) "
8002 "WHERE n.node_id = ? AND e.start_node <> e.end_node",
8003 xnode, xedge);
8004 free (xnode);
8005 free (xedge);
8006 ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt2, NULL);
8007 sqlite3_free (sql);
8008 if (ret != SQLITE_OK)
8009 {
8010 char *msg = sqlite3_mprintf ("TopoGeo_%sEdgeHeal error: \"%s\"",
8011 mode_new ? "New" : "Mod",
8012 sqlite3_errmsg (topo->db_handle));
8013 gaiatopo_set_last_error_msg (accessor, msg);
8014 sqlite3_free (msg);
8015 goto error;
8016 }
8017
8018 /* preparing the SQL query Healing a couple of Edges */
8019 sql =
8020 sqlite3_mprintf ("SELECT ST_%sEdgeHeal(%Q, ?, ?)",
8021 mode_new ? "New" : "Mod", topo->topology_name);
8022 ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt3, NULL);
8023 sqlite3_free (sql);
8024 if (ret != SQLITE_OK)
8025 {
8026 char *msg = sqlite3_mprintf ("TopoGeo_%sEdgeHeal error: \"%s\"",
8027 mode_new ? "New" : "Mod",
8028 sqlite3_errmsg (topo->db_handle));
8029 gaiatopo_set_last_error_msg (accessor, msg);
8030 sqlite3_free (msg);
8031 goto error;
8032 }
8033
8034 while (loop)
8035 {
8036 /* looping until all possible Edges have been healed */
8037 sqlite3_reset (stmt1);
8038 sqlite3_clear_bindings (stmt1);
8039 loop = 0;
8040
8041 while (1)
8042 {
8043 /* scrolling the result set rows */
8044 sqlite3_int64 edge_1_id = -1;
8045 sqlite3_int64 edge_2_id = -1;
8046 ret = sqlite3_step (stmt1);
8047 if (ret == SQLITE_DONE)
8048 break; /* end of result set */
8049 if (ret == SQLITE_ROW)
8050 {
8051 sqlite3_reset (stmt2);
8052 sqlite3_clear_bindings (stmt2);
8053 sqlite3_bind_int64 (stmt2, 1,
8054 sqlite3_column_int64 (stmt1, 0));
8055
8056 loop_count = 0;
8057 while (1)
8058 {
8059 /* scrolling the result set rows */
8060 ret = sqlite3_step (stmt2);
8061 if (ret == SQLITE_DONE)
8062 break; /* end of result set */
8063 if (ret == SQLITE_ROW)
8064 {
8065 loop_count++;
8066 if (loop_count == 1)
8067 edge_1_id =
8068 sqlite3_column_int64 (stmt2, 0);
8069 else if (loop_count == 2)
8070 edge_2_id =
8071 sqlite3_column_int64 (stmt2, 0);
8072 else
8073 {
8074 char *msg =
8075 sqlite3_mprintf
8076 ("TopoGeo_%sEdgeHeal error: \"Unexpected loop_count > 2\"",
8077 mode_new ? "New" : "Mod");
8078 gaiatopo_set_last_error_msg (accessor,
8079 msg);
8080 sqlite3_free (msg);
8081 goto error;
8082 }
8083 }
8084 else
8085 {
8086 char *msg =
8087 sqlite3_mprintf
8088 ("TopoGeo_%sEdgeHeal error: \"%s\"",
8089 mode_new ? "New" : "Mod",
8090 sqlite3_errmsg (topo->db_handle));
8091 gaiatopo_set_last_error_msg (accessor, msg);
8092 sqlite3_free (msg);
8093 goto error;
8094 }
8095 }
8096 if (loop_count != 2 || edge_1_id < 0 || edge_2_id < 0)
8097 {
8098 /* discarding invalid Edges */
8099 edge_1_id = -1;
8100 edge_2_id = -1;
8101 loop_count = 0;
8102 continue;
8103 }
8104 if (edge_1_id == edge_2_id)
8105 {
8106 /* can't Heal - dog chasing its tail */
8107 edge_1_id = -1;
8108 edge_2_id = -1;
8109 loop_count = 0;
8110 continue;
8111 }
8112
8113 /* healing a couple of Edges */
8114 sqlite3_reset (stmt3);
8115 sqlite3_clear_bindings (stmt3);
8116 sqlite3_bind_int64 (stmt3, 1, edge_1_id);
8117 sqlite3_bind_int64 (stmt3, 2, edge_2_id);
8118 ret = sqlite3_step (stmt3);
8119 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
8120 {
8121 loop = 1;
8122 break;
8123 }
8124 else
8125 {
8126 char *msg =
8127 sqlite3_mprintf
8128 ("TopoGeo_%sEdgeHeal error: \"%s\"",
8129 mode_new ? "New" : "Mod",
8130 sqlite3_errmsg (topo->db_handle));
8131 gaiatopo_set_last_error_msg (accessor, msg);
8132 sqlite3_free (msg);
8133 goto error;
8134 }
8135 }
8136 }
8137 }
8138
8139 sqlite3_finalize (stmt1);
8140 sqlite3_finalize (stmt2);
8141 sqlite3_finalize (stmt3);
8142 return 1;
8143
8144 error:
8145 if (stmt1 != NULL)
8146 sqlite3_finalize (stmt1);
8147 if (stmt2 != NULL)
8148 sqlite3_finalize (stmt2);
8149 if (stmt3 != NULL)
8150 sqlite3_finalize (stmt3);
8151 return 0;
8152 }
8153
8154 GAIATOPO_DECLARE int
gaiaTopoGeo_NewEdgeHeal(GaiaTopologyAccessorPtr ptr)8155 gaiaTopoGeo_NewEdgeHeal (GaiaTopologyAccessorPtr ptr)
8156 {
8157 return topoGeo_EdgeHeal_common (ptr, 1);
8158 }
8159
8160 GAIATOPO_DECLARE int
gaiaTopoGeo_ModEdgeHeal(GaiaTopologyAccessorPtr ptr)8161 gaiaTopoGeo_ModEdgeHeal (GaiaTopologyAccessorPtr ptr)
8162 {
8163 return topoGeo_EdgeHeal_common (ptr, 0);
8164 }
8165
8166 static int
do_split_edge(GaiaTopologyAccessorPtr accessor,sqlite3 * sqlite,sqlite3_stmt * stmt,sqlite3_int64 edge_id,gaiaGeomCollPtr geom,int line_max_points,double max_length,int * count)8167 do_split_edge (GaiaTopologyAccessorPtr accessor, sqlite3 * sqlite,
8168 sqlite3_stmt * stmt, sqlite3_int64 edge_id, gaiaGeomCollPtr geom,
8169 int line_max_points, double max_length, int *count)
8170 {
8171 /* attempting to split an Edge in two halves */
8172 int nlns = 0;
8173 char *msg;
8174 double x;
8175 double y;
8176 double z;
8177 int last;
8178 unsigned char *blob = NULL;
8179 int blob_size = 0;
8180 int ret;
8181 gaiaLinestringPtr ln;
8182 gaiaGeomCollPtr point = NULL;
8183 gaiaGeomCollPtr split =
8184 gaiaTopoGeo_SubdivideLines (geom, line_max_points, max_length);
8185
8186 ln = split->FirstLinestring;
8187 while (ln != NULL)
8188 {
8189 nlns++;
8190 ln = ln->Next;
8191 }
8192 if (nlns < 2)
8193 return 1; /* Edge not requiring to be split */
8194
8195 ln = split->FirstLinestring;
8196 last = ln->Points - 1;
8197 if (split->DimensionModel == GAIA_XY_Z)
8198 {
8199 /* 3D topology */
8200 point = gaiaAllocGeomCollXYZ ();
8201 point->Srid = geom->Srid;
8202 gaiaGetPointXYZ (ln->Coords, last, &x, &y, &z);
8203 gaiaAddPointToGeomCollXYZ (point, x, y, z);
8204 }
8205 else
8206 {
8207 /* 2D topology */
8208 point = gaiaAllocGeomColl ();
8209 point->Srid = geom->Srid;
8210 gaiaGetPoint (ln->Coords, last, &x, &y);
8211 gaiaAddPointToGeomColl (point, x, y);
8212 }
8213
8214 /* splitting the Edge */
8215 sqlite3_reset (stmt);
8216 sqlite3_clear_bindings (stmt);
8217 sqlite3_bind_int64 (stmt, 1, edge_id);
8218 gaiaToSpatiaLiteBlobWkb (point, &blob, &blob_size);
8219 sqlite3_bind_blob (stmt, 2, blob, blob_size, free);
8220 ret = sqlite3_step (stmt);
8221 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
8222 {
8223 *count += 1;
8224 return 1;
8225 }
8226
8227 /* some unexpected error occurred */
8228 msg = sqlite3_mprintf ("Edge Split error: \"%s\"", sqlite3_errmsg (sqlite));
8229 gaiatopo_set_last_error_msg (accessor, msg);
8230 sqlite3_free (msg);
8231 return 0;
8232 }
8233
8234 static int
topoGeo_EdgeSplit_common(GaiaTopologyAccessorPtr accessor,int mode_new,int line_max_points,double max_length)8235 topoGeo_EdgeSplit_common (GaiaTopologyAccessorPtr accessor, int mode_new,
8236 int line_max_points, double max_length)
8237 {
8238 /* common implementation of GeoTable EdgeSplit */
8239 struct gaia_topology *topo = (struct gaia_topology *) accessor;
8240 int ret;
8241 char *sql;
8242 char *edge;
8243 char *xedge;
8244 sqlite3_stmt *stmt1 = NULL;
8245 sqlite3_stmt *stmt2 = NULL;
8246 if (topo == NULL)
8247 return 0;
8248
8249 ret = test_inconsistent_topology (accessor);
8250 if (ret != 0)
8251 return 0;
8252
8253 /* preparing the SQL query identifying all Edges */
8254 edge = sqlite3_mprintf ("%s_edge", topo->topology_name);
8255 xedge = gaiaDoubleQuotedSql (edge);
8256 sqlite3_free (edge);
8257 sql =
8258 sqlite3_mprintf ("SELECT edge_id, geom FROM \"%s\" ORDER BY edge_id",
8259 xedge);
8260 free (xedge);
8261 ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt1, NULL);
8262 sqlite3_free (sql);
8263 if (ret != SQLITE_OK)
8264 {
8265 char *msg = sqlite3_mprintf ("TopoGeo_%sSplit error: \"%s\"",
8266 mode_new ? "NewEdges" : "ModEdge",
8267 sqlite3_errmsg (topo->db_handle));
8268 gaiatopo_set_last_error_msg (accessor, msg);
8269 sqlite3_free (msg);
8270 goto error;
8271 }
8272
8273 /* preparing the SQL query splitting an Edge in two halves */
8274 sql =
8275 sqlite3_mprintf ("SELECT ST_%sSplit(%Q, ?, ?)",
8276 mode_new ? "NewEdges" : "ModEdge",
8277 topo->topology_name);
8278 ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt2, NULL);
8279 sqlite3_free (sql);
8280 if (ret != SQLITE_OK)
8281 {
8282 char *msg = sqlite3_mprintf ("TopoGeo_%sSplit error: \"%s\"",
8283 mode_new ? "NewEdges" : "ModEdge",
8284 sqlite3_errmsg (topo->db_handle));
8285 gaiatopo_set_last_error_msg (accessor, msg);
8286 sqlite3_free (msg);
8287 goto error;
8288 }
8289
8290 while (1)
8291 {
8292 /* repeatedly looping on all Edges */
8293 int count = 0;
8294 sqlite3_reset (stmt1);
8295 sqlite3_clear_bindings (stmt1);
8296
8297 while (1)
8298 {
8299 /* scrolling the result set rows */
8300 ret = sqlite3_step (stmt1);
8301 if (ret == SQLITE_DONE)
8302 break; /* end of result set */
8303 if (ret == SQLITE_ROW)
8304 {
8305 sqlite3_int64 edge_id = sqlite3_column_int64 (stmt1, 0);
8306 if (sqlite3_column_type (stmt1, 1) == SQLITE_BLOB)
8307 {
8308 const unsigned char *blob =
8309 sqlite3_column_blob (stmt1, 1);
8310 int blob_sz = sqlite3_column_bytes (stmt1, 1);
8311 gaiaGeomCollPtr geom =
8312 gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
8313 if (geom != NULL)
8314 {
8315 if (!do_split_edge
8316 (accessor, topo->db_handle, stmt2,
8317 edge_id, geom, line_max_points,
8318 max_length, &count))
8319 {
8320 gaiaFreeGeomColl (geom);
8321 goto error;
8322 }
8323 }
8324 gaiaFreeGeomColl (geom);
8325 }
8326 }
8327 else
8328 {
8329 char *msg =
8330 sqlite3_mprintf ("TopoGeo_%sSplit error: \"%s\"",
8331 mode_new ? "NewEdges" : "ModEdge",
8332 sqlite3_errmsg (topo->db_handle));
8333 gaiatopo_set_last_error_msg (accessor, msg);
8334 sqlite3_free (msg);
8335 goto error;
8336 }
8337 }
8338 if (count == 0)
8339 break;
8340 }
8341
8342 sqlite3_finalize (stmt1);
8343 sqlite3_finalize (stmt2);
8344 return 1;
8345
8346 error:
8347 if (stmt1 != NULL)
8348 sqlite3_finalize (stmt1);
8349 if (stmt2 != NULL)
8350 sqlite3_finalize (stmt2);
8351 return 0;
8352 }
8353
8354 GAIATOPO_DECLARE int
gaiaTopoGeo_NewEdgesSplit(GaiaTopologyAccessorPtr ptr,int line_max_points,double max_length)8355 gaiaTopoGeo_NewEdgesSplit (GaiaTopologyAccessorPtr ptr, int line_max_points,
8356 double max_length)
8357 {
8358 return topoGeo_EdgeSplit_common (ptr, 1, line_max_points, max_length);
8359 }
8360
8361 GAIATOPO_DECLARE int
gaiaTopoGeo_ModEdgeSplit(GaiaTopologyAccessorPtr ptr,int line_max_points,double max_length)8362 gaiaTopoGeo_ModEdgeSplit (GaiaTopologyAccessorPtr ptr, int line_max_points,
8363 double max_length)
8364 {
8365 return topoGeo_EdgeSplit_common (ptr, 0, line_max_points, max_length);
8366 }
8367
8368 static gaiaGeomCollPtr
do_interpolate_middlepoint(gaiaGeomCollPtr geom)8369 do_interpolate_middlepoint (gaiaGeomCollPtr geom)
8370 {
8371 /* building a three-point segment */
8372 gaiaGeomCollPtr newg;
8373 gaiaLinestringPtr old_ln;
8374 gaiaLinestringPtr new_ln;
8375 double x0;
8376 double y0;
8377 double z0;
8378 double x1;
8379 double y1;
8380 double z1;
8381 double mx;
8382 double my;
8383 double mz;
8384
8385 if (geom == NULL)
8386 return NULL;
8387 if (geom->FirstPoint != NULL || geom->FirstPolygon != NULL)
8388 return NULL;
8389 if (geom->FirstLinestring != geom->LastLinestring)
8390 return NULL;
8391 old_ln = geom->FirstLinestring;
8392 if (old_ln == NULL)
8393 return NULL;
8394 if (old_ln->Points != 2)
8395 return NULL;
8396
8397 if (geom->DimensionModel == GAIA_XY_Z)
8398 {
8399 gaiaGetPointXYZ (old_ln->Coords, 0, &x0, &y0, &z0);
8400 gaiaGetPointXYZ (old_ln->Coords, 1, &x1, &y1, &z1);
8401 newg = gaiaAllocGeomCollXYZ ();
8402 }
8403 else
8404 {
8405 gaiaGetPoint (old_ln->Coords, 0, &x0, &y0);
8406 gaiaGetPoint (old_ln->Coords, 1, &x1, &y1);
8407 newg = gaiaAllocGeomColl ();
8408 }
8409 newg->Srid = geom->Srid;
8410
8411 if (x0 > x1)
8412 mx = x1 + ((x0 - x1) / 2.0);
8413 else
8414 mx = x0 + ((x1 - x0) / 2.0);
8415 if (y0 > y1)
8416 my = y1 + ((y0 - y1) / 2.0);
8417 else
8418 my = y0 + ((y1 - y0) / 2.0);
8419 if (geom->DimensionModel == GAIA_XY_Z)
8420 {
8421 if (z0 > z1)
8422 mz = z1 + ((z0 - z1) / 2.0);
8423 else
8424 mz = z0 + ((z1 - z0) / 2.0);
8425 }
8426
8427 new_ln = gaiaAddLinestringToGeomColl (newg, 3);
8428 if (newg->DimensionModel == GAIA_XY_Z)
8429 {
8430 gaiaSetPointXYZ (new_ln->Coords, 0, x0, y0, z0);
8431 gaiaSetPointXYZ (new_ln->Coords, 1, mx, my, mz);
8432 gaiaSetPointXYZ (new_ln->Coords, 2, x1, y1, z1);
8433 }
8434 else
8435 {
8436 gaiaSetPoint (new_ln->Coords, 0, x0, y0);
8437 gaiaSetPoint (new_ln->Coords, 1, mx, my);
8438 gaiaSetPoint (new_ln->Coords, 2, x1, y1);
8439 }
8440
8441 return newg;
8442 }
8443
8444 GAIATOPO_DECLARE int
gaiaTopoGeo_DisambiguateSegmentEdges(GaiaTopologyAccessorPtr accessor)8445 gaiaTopoGeo_DisambiguateSegmentEdges (GaiaTopologyAccessorPtr accessor)
8446 {
8447 /*
8448 / Ensures that all Edges on a Topology-Geometry will have not less
8449 / than three vertices; for all Edges found beign simple two-points
8450 / segments a third intermediate point will be interpolated.
8451 */
8452 struct gaia_topology *topo = (struct gaia_topology *) accessor;
8453 int ret;
8454 char *sql;
8455 char *edge;
8456 char *xedge;
8457 sqlite3_stmt *stmt_in = NULL;
8458 sqlite3_stmt *stmt_out = NULL;
8459 int count = 0;
8460 if (topo == NULL)
8461 return -1;
8462
8463 /* preparing the SQL query identifying all two-points Edges */
8464 edge = sqlite3_mprintf ("%s_edge", topo->topology_name);
8465 xedge = gaiaDoubleQuotedSql (edge);
8466 sqlite3_free (edge);
8467 sql =
8468 sqlite3_mprintf
8469 ("SELECT edge_id, geom FROM \"%s\" WHERE ST_NumPoints(geom) = 2 "
8470 "ORDER BY edge_id", xedge);
8471 free (xedge);
8472 ret =
8473 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
8474 sqlite3_free (sql);
8475 if (ret != SQLITE_OK)
8476 {
8477 char *msg =
8478 sqlite3_mprintf ("TopoGeo_DisambiguateSegmentEdges error: \"%s\"",
8479 sqlite3_errmsg (topo->db_handle));
8480 gaiatopo_set_last_error_msg (accessor, msg);
8481 sqlite3_free (msg);
8482 goto error;
8483 }
8484
8485 /* preparing the UPDATE SQL query */
8486 sql =
8487 sqlite3_mprintf ("SELECT ST_ChangeEdgeGeom(%Q, ?, ?)",
8488 topo->topology_name);
8489 ret =
8490 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_out,
8491 NULL);
8492 sqlite3_free (sql);
8493 if (ret != SQLITE_OK)
8494 {
8495 char *msg =
8496 sqlite3_mprintf ("TopoGeo_DisambiguateSegmentEdges error: \"%s\"",
8497 sqlite3_errmsg (topo->db_handle));
8498 gaiatopo_set_last_error_msg (accessor, msg);
8499 sqlite3_free (msg);
8500 goto error;
8501 }
8502
8503 while (1)
8504 {
8505 /* scrolling the result set rows */
8506 ret = sqlite3_step (stmt_in);
8507 if (ret == SQLITE_DONE)
8508 break; /* end of result set */
8509 if (ret == SQLITE_ROW)
8510 {
8511 sqlite3_int64 edge_id = sqlite3_column_int64 (stmt_in, 0);
8512 if (sqlite3_column_type (stmt_in, 1) == SQLITE_BLOB)
8513 {
8514 const unsigned char *blob =
8515 sqlite3_column_blob (stmt_in, 1);
8516 int blob_sz = sqlite3_column_bytes (stmt_in, 1);
8517 gaiaGeomCollPtr geom =
8518 gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
8519 if (geom != NULL)
8520 {
8521 gaiaGeomCollPtr newg =
8522 do_interpolate_middlepoint (geom);
8523 gaiaFreeGeomColl (geom);
8524 if (newg != NULL)
8525 {
8526 unsigned char *outblob = NULL;
8527 int outblob_size = 0;
8528 sqlite3_reset (stmt_out);
8529 sqlite3_clear_bindings (stmt_out);
8530 sqlite3_bind_int64 (stmt_out, 1, edge_id);
8531 gaiaToSpatiaLiteBlobWkb (newg, &outblob,
8532 &outblob_size);
8533 gaiaFreeGeomColl (newg);
8534 if (blob == NULL)
8535 continue;
8536 else
8537 sqlite3_bind_blob (stmt_out, 2, outblob,
8538 outblob_size, free);
8539 /* updating the Edges table */
8540 ret = sqlite3_step (stmt_out);
8541 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
8542 count++;
8543 else
8544 {
8545 char *msg =
8546 sqlite3_mprintf
8547 ("TopoGeo_DisambiguateSegmentEdges() error: \"%s\"",
8548 sqlite3_errmsg (topo->db_handle));
8549 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo, msg);
8550 sqlite3_free (msg);
8551 goto error;
8552 }
8553 }
8554 }
8555 }
8556 }
8557 else
8558 {
8559 char *msg =
8560 sqlite3_mprintf
8561 ("TopoGeo_DisambiguateSegmentEdges error: \"%s\"",
8562 sqlite3_errmsg (topo->db_handle));
8563 gaiatopo_set_last_error_msg (accessor, msg);
8564 sqlite3_free (msg);
8565 goto error;
8566 }
8567 }
8568
8569 sqlite3_finalize (stmt_in);
8570 sqlite3_finalize (stmt_out);
8571 return count;
8572
8573 error:
8574 if (stmt_out != NULL)
8575 sqlite3_finalize (stmt_in);
8576 if (stmt_out != NULL)
8577 sqlite3_finalize (stmt_out);
8578 return -1;
8579 }
8580
8581 #endif /* end ENABLE_RTTOPO conditionals */
8582