1 /*
2
3 gaia_auxtopo.c -- implementation of the Topology module methods
4
5 version 5.0, 2020 August 1
6
7 Author: Sandro Furieri a.furieri@lqt.it
8
9 -----------------------------------------------------------------------------
10
11 Version: MPL 1.1/GPL 2.0/LGPL 2.1
12
13 The contents of this file are subject to the Mozilla Public License Version
14 1.1 (the "License"); you may not use this file except in compliance with
15 the License. You may obtain a copy of the License at
16 http://www.mozilla.org/MPL/
17
18 Software distributed under the License is distributed on an "AS IS" basis,
19 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
20 for the specific language governing rights and limitations under the
21 License.
22
23 The Original Code is the SpatiaLite library
24
25 The Initial Developer of the Original Code is Alessandro Furieri
26
27 Portions created by the Initial Developer are Copyright (C) 2015-2021
28 the Initial Developer. All Rights Reserved.
29
30 Contributor(s):
31
32 Alternatively, the contents of this file may be used under the terms of
33 either the GNU General Public License Version 2 or later (the "GPL"), or
34 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
35 in which case the provisions of the GPL or the LGPL are applicable instead
36 of those above. If you wish to allow use of your version of this file only
37 under the terms of either the GPL or the LGPL, and not to allow others to
38 use your version of this file under the terms of the MPL, indicate your
39 decision by deleting the provisions above and replace them with the notice
40 and other provisions required by the GPL or the LGPL. If you do not delete
41 the provisions above, a recipient may use your version of this file under
42 the terms of any one of the MPL, the GPL or the LGPL.
43
44 */
45
46 /*
47
48 CREDITS:
49
50 this module has been completely funded by:
51 Regione Toscana - Settore Sistema Informativo Territoriale ed Ambientale
52 (Topology support)
53
54 CIG: 6038019AE5
55
56 */
57
58 #include <stdlib.h>
59 #include <stdio.h>
60 #include <string.h>
61 #include <float.h>
62 #include <math.h>
63
64 #if defined(_WIN32) && !defined(__MINGW32__)
65 #include "process.h"
66 #else
67 #include "unistd.h"
68 #endif
69
70 #if defined(_WIN32) && !defined(__MINGW32__)
71 #include "config-msvc.h"
72 #else
73 #include "config.h"
74 #endif
75
76 #include <spatialite_private.h>
77
78 #ifdef ENABLE_RTTOPO /* only if RTTOPO is enabled */
79
80 #include <spatialite/sqlite.h>
81 #include <spatialite/debug.h>
82 #include <spatialite/gaiageo.h>
83 #include <spatialite/gaia_topology.h>
84 #include <spatialite/gaia_network.h>
85 #include <spatialite/gaiaaux.h>
86
87 #include <spatialite.h>
88
89 #include <librttopo.h>
90
91 #include <lwn_network.h>
92
93 #include "topology_private.h"
94 #include "network_private.h"
95
96 #ifdef _WIN32
97 #define strcasecmp _stricmp
98 #endif /* not WIN32 */
99
100 #define GAIA_UNUSED() if (argc || argv) argc = argc;
101
102 SPATIALITE_PRIVATE void
free_internal_cache_topologies(void * firstTopology)103 free_internal_cache_topologies (void *firstTopology)
104 {
105 /* destroying all Topologies registered into the Internal Connection Cache */
106 struct gaia_topology *p_topo = (struct gaia_topology *) firstTopology;
107 struct gaia_topology *p_topo_n;
108
109 while (p_topo != NULL)
110 {
111 p_topo_n = p_topo->next;
112 gaiaTopologyDestroy ((GaiaTopologyAccessorPtr) p_topo);
113 p_topo = p_topo_n;
114 }
115 }
116
117 SPATIALITE_PRIVATE void
drop_topologies_triggers(void * sqlite_handle)118 drop_topologies_triggers (void *sqlite_handle)
119 {
120 /* dropping all "topologies" triggers */
121 char *sql;
122 int ret;
123 char *err_msg = NULL;
124 char **results;
125 int rows;
126 int columns;
127 int i;
128 sqlite3 *sqlite = (sqlite3 *) sqlite_handle;
129
130 /* checking for existing tables */
131 sql =
132 "SELECT name FROM sqlite_master WHERE type = 'trigger' AND tbl_name = 'topologies'";
133 ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, &err_msg);
134 if (ret != SQLITE_OK)
135 {
136 spatialite_e ("SQL error: %s\n", err_msg);
137 sqlite3_free (err_msg);
138 return;
139 }
140 for (i = 1; i <= rows; i++)
141 {
142 const char *name = results[(i * columns) + 0];
143 sql = sqlite3_mprintf ("DROP TRIGGER %s", name);
144 ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
145 if (ret != SQLITE_OK)
146 {
147 spatialite_e ("SQL error: %s\n", err_msg);
148 sqlite3_free (err_msg);
149 return;
150 }
151 sqlite3_free (sql);
152 }
153 sqlite3_free_table (results);
154 }
155
156 SPATIALITE_PRIVATE int
do_create_topologies_triggers(void * sqlite_handle)157 do_create_topologies_triggers (void *sqlite_handle)
158 {
159 /* attempting to create the Topologies triggers */
160 const char *sql;
161 char *err_msg = NULL;
162 int ret;
163 char **results;
164 int rows;
165 int columns;
166 int i;
167 sqlite3 *handle = (sqlite3 *) sqlite_handle;
168 int ok_topologies = 0;
169
170 /* checking for existing tables */
171 sql =
172 "SELECT tbl_name FROM sqlite_master WHERE type = 'table' AND tbl_name = 'topologies'";
173 ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, &err_msg);
174 if (ret != SQLITE_OK)
175 {
176 spatialite_e ("SQL error: %s\n", err_msg);
177 sqlite3_free (err_msg);
178 return 0;
179 }
180 for (i = 1; i <= rows; i++)
181 {
182 const char *name = results[(i * columns) + 0];
183 if (strcasecmp (name, "topologies") == 0)
184 ok_topologies = 1;
185 }
186 sqlite3_free_table (results);
187
188 if (ok_topologies)
189 {
190 /* creating Topologies triggers */
191 sql = "CREATE TRIGGER IF NOT EXISTS topology_name_insert\n"
192 "BEFORE INSERT ON 'topologies'\nFOR EACH ROW BEGIN\n"
193 "SELECT RAISE(ABORT,'insert on topologies violates constraint: "
194 "topology_name value must not contain a single quote')\n"
195 "WHERE NEW.topology_name LIKE ('%''%');\n"
196 "SELECT RAISE(ABORT,'insert on topologies violates constraint: "
197 "topology_name value must not contain a double quote')\n"
198 "WHERE NEW.topology_name LIKE ('%\"%');\n"
199 "SELECT RAISE(ABORT,'insert on topologies violates constraint: "
200 "topology_name value must be lower case')\n"
201 "WHERE NEW.topology_name <> lower(NEW.topology_name);\nEND";
202 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
203 if (ret != SQLITE_OK)
204 {
205 spatialite_e ("SQL error: %s\n", err_msg);
206 sqlite3_free (err_msg);
207 return 0;
208 }
209 sql = "CREATE TRIGGER IF NOT EXISTS topology_name_update\n"
210 "BEFORE UPDATE OF 'topology_name' ON 'topologies'\nFOR EACH ROW BEGIN\n"
211 "SELECT RAISE(ABORT,'update on topologies violates constraint: "
212 "topology_name value must not contain a single quote')\n"
213 "WHERE NEW.topology_name LIKE ('%''%');\n"
214 "SELECT RAISE(ABORT,'update on topologies violates constraint: "
215 "topology_name value must not contain a double quote')\n"
216 "WHERE NEW.topology_name LIKE ('%\"%');\n"
217 "SELECT RAISE(ABORT,'update on topologies violates constraint: "
218 "topology_name value must be lower case')\n"
219 "WHERE NEW.topology_name <> lower(NEW.topology_name);\nEND";
220 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
221 if (ret != SQLITE_OK)
222 {
223 spatialite_e ("SQL error: %s\n", err_msg);
224 sqlite3_free (err_msg);
225 return 0;
226 }
227 }
228
229 return 1;
230 }
231
232 SPATIALITE_PRIVATE int
do_create_topologies(void * sqlite_handle)233 do_create_topologies (void *sqlite_handle)
234 {
235 /* attempting to create the Topologies table (if not already existing) */
236 const char *sql;
237 char *err_msg = NULL;
238 int ret;
239 sqlite3 *handle = (sqlite3 *) sqlite_handle;
240
241 sql = "CREATE TABLE IF NOT EXISTS topologies (\n"
242 "\ttopology_name TEXT NOT NULL PRIMARY KEY,\n"
243 "\tsrid INTEGER NOT NULL,\n"
244 "\ttolerance DOUBLE NOT NULL,\n"
245 "\thas_z INTEGER NOT NULL,\n"
246 "\tnext_edge_id INTEGER NOT NULL DEFAULT 1,\n"
247 "\tCONSTRAINT topo_srid_fk FOREIGN KEY (srid) "
248 "REFERENCES spatial_ref_sys (srid))";
249 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
250 if (ret != SQLITE_OK)
251 {
252 spatialite_e ("CREATE TABLE topologies - error: %s\n", err_msg);
253 sqlite3_free (err_msg);
254 return 0;
255 }
256
257 if (!do_create_topologies_triggers (handle))
258 return 0;
259 return 1;
260 }
261
262 static int
check_new_topology(sqlite3 * handle,const char * topo_name)263 check_new_topology (sqlite3 * handle, const char *topo_name)
264 {
265 /* testing if some already defined DB object forbids creating the new Topology */
266 char *sql;
267 char *prev;
268 char *table;
269 int ret;
270 int i;
271 char **results;
272 int rows;
273 int columns;
274 const char *value;
275 int error = 0;
276
277 /* testing if the same Topology is already defined */
278 sql = sqlite3_mprintf ("SELECT Count(*) FROM MAIN.topologies WHERE "
279 "Lower(topology_name) = Lower(%Q)", topo_name);
280 ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
281 sqlite3_free (sql);
282 if (ret != SQLITE_OK)
283 return 0;
284 if (rows < 1)
285 ;
286 else
287 {
288 for (i = 1; i <= rows; i++)
289 {
290 value = results[(i * columns) + 0];
291 if (atoi (value) != 0)
292 error = 1;
293 }
294 }
295 sqlite3_free_table (results);
296 if (error)
297 return 0;
298
299 /* testing if some table/geom is already defined in geometry_columns */
300 sql = sqlite3_mprintf ("SELECT Count(*) FROM geometry_columns WHERE");
301 prev = sql;
302 table = sqlite3_mprintf ("%s_face", topo_name);
303 sql =
304 sqlite3_mprintf
305 ("%s (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'mbr')",
306 prev, table);
307 sqlite3_free (table);
308 sqlite3_free (prev);
309 prev = sql;
310 table = sqlite3_mprintf ("%s_node", topo_name);
311 sql =
312 sqlite3_mprintf
313 ("%s OR (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'geom')",
314 prev, table);
315 sqlite3_free (table);
316 sqlite3_free (prev);
317 prev = sql;
318 table = sqlite3_mprintf ("%s_edge", topo_name);
319 sql =
320 sqlite3_mprintf
321 ("%s OR (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'geom')",
322 prev, table);
323 sqlite3_free (table);
324 sqlite3_free (prev);
325 prev = sql;
326 table = sqlite3_mprintf ("%s_seeds", topo_name);
327 sql =
328 sqlite3_mprintf
329 ("%s OR (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'geom')",
330 prev, table);
331 sqlite3_free (table);
332 sqlite3_free (prev);
333 ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
334 sqlite3_free (sql);
335 if (ret != SQLITE_OK)
336 return 0;
337 if (rows < 1)
338 ;
339 else
340 {
341 for (i = 1; i <= rows; i++)
342 {
343 value = results[(i * columns) + 0];
344 if (atoi (value) != 0)
345 error = 1;
346 }
347 }
348 sqlite3_free_table (results);
349 if (error)
350 return 0;
351
352 /* testing if some Spatial View is already defined in views_geometry_columns */
353 sql = sqlite3_mprintf ("SELECT Count(*) FROM views_geometry_columns WHERE");
354 prev = sql;
355 table = sqlite3_mprintf ("%s_face_geoms", topo_name);
356 sql =
357 sqlite3_mprintf
358 ("%s (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'mbr')",
359 prev, table);
360 sqlite3_free (table);
361 sqlite3_free (prev);
362 prev = sql;
363 table = sqlite3_mprintf ("%s_face_seeds", topo_name);
364 sql =
365 sqlite3_mprintf
366 ("%s OR (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'geom')",
367 prev, table);
368 sqlite3_free (table);
369 sqlite3_free (prev);
370 prev = sql;
371 table = sqlite3_mprintf ("%s_edge_seeds", topo_name);
372 sql =
373 sqlite3_mprintf
374 ("%s OR (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'geom')",
375 prev, table);
376 sqlite3_free (table);
377 sqlite3_free (prev);
378 ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
379 sqlite3_free (sql);
380 if (ret != SQLITE_OK)
381 return 0;
382 if (rows < 1)
383 ;
384 else
385 {
386 for (i = 1; i <= rows; i++)
387 {
388 value = results[(i * columns) + 0];
389 if (atoi (value) != 0)
390 error = 1;
391 }
392 }
393 sqlite3_free_table (results);
394 if (error)
395 return 0;
396
397 /* testing if some table is already defined */
398 sql = sqlite3_mprintf ("SELECT Count(*) FROM sqlite_master WHERE");
399 prev = sql;
400 table = sqlite3_mprintf ("%s_node", topo_name);
401 sql = sqlite3_mprintf ("%s Lower(name) = Lower(%Q)", prev, table);
402 sqlite3_free (table);
403 sqlite3_free (prev);
404 prev = sql;
405 table = sqlite3_mprintf ("%s_edge", topo_name);
406 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
407 sqlite3_free (table);
408 sqlite3_free (prev);
409 prev = sql;
410 table = sqlite3_mprintf ("%s_face", topo_name);
411 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
412 sqlite3_free (table);
413 sqlite3_free (prev);
414 prev = sql;
415 table = sqlite3_mprintf ("%s_seeds", topo_name);
416 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
417 sqlite3_free (table);
418 sqlite3_free (prev);
419 prev = sql;
420 table = sqlite3_mprintf ("%s_topolayers", topo_name);
421 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
422 sqlite3_free (table);
423 sqlite3_free (prev);
424 prev = sql;
425 table = sqlite3_mprintf ("%s_topofeatures", topo_name);
426 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
427 sqlite3_free (table);
428 sqlite3_free (prev);
429 prev = sql;
430 table = sqlite3_mprintf ("idx_%s_node_geom", topo_name);
431 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
432 sqlite3_free (table);
433 sqlite3_free (prev);
434 prev = sql;
435 table = sqlite3_mprintf ("idx_%s_edge_geom", topo_name);
436 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
437 sqlite3_free (table);
438 sqlite3_free (prev);
439 prev = sql;
440 table = sqlite3_mprintf ("idx_%s_face_mbr", topo_name);
441 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
442 sqlite3_free (table);
443 sqlite3_free (prev);
444 prev = sql;
445 table = sqlite3_mprintf ("idx_%s_seeds_geom", topo_name);
446 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
447 sqlite3_free (table);
448 sqlite3_free (prev);
449 prev = sql;
450 table = sqlite3_mprintf ("%s_face_geoms", topo_name);
451 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
452 sqlite3_free (table);
453 sqlite3_free (prev);
454 prev = sql;
455 table = sqlite3_mprintf ("%s_face_seeds", topo_name);
456 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
457 sqlite3_free (table);
458 sqlite3_free (prev);
459 prev = sql;
460 table = sqlite3_mprintf ("%s_edge_seeds", topo_name);
461 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
462 sqlite3_free (table);
463 sqlite3_free (prev);
464 ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
465 sqlite3_free (sql);
466 if (ret != SQLITE_OK)
467 return 0;
468 if (rows < 1)
469 ;
470 else
471 {
472 for (i = 1; i <= rows; i++)
473 {
474 value = results[(i * columns) + 0];
475 if (atoi (value) != 0)
476 error = 1;
477 }
478 }
479 sqlite3_free_table (results);
480 if (error)
481 return 0;
482
483 return 1;
484 }
485
486 static int
do_create_face(sqlite3 * handle,const char * topo_name,int srid)487 do_create_face (sqlite3 * handle, const char *topo_name, int srid)
488 {
489 /* attempting to create the Topology Face table */
490 char *sql;
491 char *table;
492 char *xtable;
493 char *err_msg = NULL;
494 int ret;
495
496 /* creating the main table */
497 table = sqlite3_mprintf ("%s_face", topo_name);
498 xtable = gaiaDoubleQuotedSql (table);
499 sqlite3_free (table);
500 sql = sqlite3_mprintf ("CREATE TABLE \"%s\" (\n"
501 "\tface_id INTEGER PRIMARY KEY AUTOINCREMENT)",
502 xtable);
503 free (xtable);
504 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
505 sqlite3_free (sql);
506 if (ret != SQLITE_OK)
507 {
508 spatialite_e ("CREATE TABLE topology-FACE - error: %s\n", err_msg);
509 sqlite3_free (err_msg);
510 return 0;
511 }
512
513 /* creating the Face BBOX Geometry */
514 table = sqlite3_mprintf ("%s_face", topo_name);
515 sql =
516 sqlite3_mprintf
517 ("SELECT AddGeometryColumn(%Q, 'mbr', %d, 'POLYGON', 'XY')",
518 table, srid);
519 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
520 sqlite3_free (table);
521 sqlite3_free (sql);
522 if (ret != SQLITE_OK)
523 {
524 spatialite_e
525 ("AddGeometryColumn topology-FACE - error: %s\n", err_msg);
526 sqlite3_free (err_msg);
527 return 0;
528 }
529
530 /* creating a Spatial Index supporting Face Geometry */
531 table = sqlite3_mprintf ("%s_face", topo_name);
532 sql = sqlite3_mprintf ("SELECT CreateSpatialIndex(%Q, 'mbr')", table);
533 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
534 sqlite3_free (table);
535 sqlite3_free (sql);
536 if (ret != SQLITE_OK)
537 {
538 spatialite_e
539 ("CreateSpatialIndex topology-FACE - error: %s\n", err_msg);
540 sqlite3_free (err_msg);
541 return 0;
542 }
543
544 /* inserting the default World Face */
545 table = sqlite3_mprintf ("%s_face", topo_name);
546 xtable = gaiaDoubleQuotedSql (table);
547 sqlite3_free (table);
548 sql = sqlite3_mprintf ("INSERT INTO MAIN.\"%s\" VALUES (0, NULL)", xtable);
549 free (xtable);
550 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
551 sqlite3_free (sql);
552 if (ret != SQLITE_OK)
553 {
554 spatialite_e ("INSERT WorldFACE - error: %s\n", err_msg);
555 sqlite3_free (err_msg);
556 return 0;
557 }
558
559 return 1;
560 }
561
562 static int
do_create_node(sqlite3 * handle,const char * topo_name,int srid,int has_z)563 do_create_node (sqlite3 * handle, const char *topo_name, int srid, int has_z)
564 {
565 /* attempting to create the Topology Node table */
566 char *sql;
567 char *table;
568 char *xtable;
569 char *xconstraint;
570 char *xmother;
571 char *err_msg = NULL;
572 int ret;
573
574 /* creating the main table */
575 table = sqlite3_mprintf ("%s_node", topo_name);
576 xtable = gaiaDoubleQuotedSql (table);
577 sqlite3_free (table);
578 table = sqlite3_mprintf ("%s_node_face_fk", topo_name);
579 xconstraint = gaiaDoubleQuotedSql (table);
580 sqlite3_free (table);
581 table = sqlite3_mprintf ("%s_face", topo_name);
582 xmother = gaiaDoubleQuotedSql (table);
583 sqlite3_free (table);
584 sql = sqlite3_mprintf ("CREATE TABLE \"%s\" (\n"
585 "\tnode_id INTEGER PRIMARY KEY AUTOINCREMENT,\n"
586 "\tcontaining_face INTEGER,\n"
587 "\tCONSTRAINT \"%s\" FOREIGN KEY (containing_face) "
588 "REFERENCES \"%s\" (face_id))", xtable, xconstraint,
589 xmother);
590 free (xtable);
591 free (xconstraint);
592 free (xmother);
593 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
594 sqlite3_free (sql);
595 if (ret != SQLITE_OK)
596 {
597 spatialite_e ("CREATE TABLE topology-NODE - error: %s\n", err_msg);
598 sqlite3_free (err_msg);
599 return 0;
600 }
601
602 /* creating the Node Geometry */
603 table = sqlite3_mprintf ("%s_node", topo_name);
604 sql =
605 sqlite3_mprintf
606 ("SELECT AddGeometryColumn(%Q, 'geom', %d, 'POINT', %Q, 1)", table,
607 srid, has_z ? "XYZ" : "XY");
608 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
609 sqlite3_free (table);
610 sqlite3_free (sql);
611 if (ret != SQLITE_OK)
612 {
613 spatialite_e
614 ("AddGeometryColumn topology-NODE - error: %s\n", err_msg);
615 sqlite3_free (err_msg);
616 return 0;
617 }
618
619 /* creating a Spatial Index supporting Node Geometry */
620 table = sqlite3_mprintf ("%s_node", topo_name);
621 sql = sqlite3_mprintf ("SELECT CreateSpatialIndex(%Q, 'geom')", table);
622 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
623 sqlite3_free (table);
624 sqlite3_free (sql);
625 if (ret != SQLITE_OK)
626 {
627 spatialite_e
628 ("CreateSpatialIndex topology-NODE - error: %s\n", err_msg);
629 sqlite3_free (err_msg);
630 return 0;
631 }
632
633 /* creating an Index supporting "containing_face" */
634 table = sqlite3_mprintf ("%s_node", topo_name);
635 xtable = gaiaDoubleQuotedSql (table);
636 sqlite3_free (table);
637 table = sqlite3_mprintf ("idx_%s_node_contface", topo_name);
638 xconstraint = gaiaDoubleQuotedSql (table);
639 sqlite3_free (table);
640 sql =
641 sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (containing_face)",
642 xconstraint, xtable);
643 free (xtable);
644 free (xconstraint);
645 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
646 sqlite3_free (sql);
647 if (ret != SQLITE_OK)
648 {
649 spatialite_e ("CREATE INDEX node-contface - error: %s\n", err_msg);
650 sqlite3_free (err_msg);
651 return 0;
652 }
653
654 return 1;
655 }
656
657 static int
do_create_edge(sqlite3 * handle,const char * topo_name,int srid,int has_z)658 do_create_edge (sqlite3 * handle, const char *topo_name, int srid, int has_z)
659 {
660 /* attempting to create the Topology Edge table */
661 char *sql;
662 char *table;
663 char *xtable;
664 char *xconstraint1;
665 char *xconstraint2;
666 char *xconstraint3;
667 char *xconstraint4;
668 char *xnodes;
669 char *xfaces;
670 char *trigger;
671 char *xtrigger;
672 char *err_msg = NULL;
673 int ret;
674
675 /* creating the main table */
676 table = sqlite3_mprintf ("%s_edge", topo_name);
677 xtable = gaiaDoubleQuotedSql (table);
678 sqlite3_free (table);
679 table = sqlite3_mprintf ("%s_edge_node_start_fk", topo_name);
680 xconstraint1 = gaiaDoubleQuotedSql (table);
681 sqlite3_free (table);
682 table = sqlite3_mprintf ("%s_edge_node_end_fk", topo_name);
683 xconstraint2 = gaiaDoubleQuotedSql (table);
684 sqlite3_free (table);
685 table = sqlite3_mprintf ("%s_edge_face_left_fk", topo_name);
686 xconstraint3 = gaiaDoubleQuotedSql (table);
687 sqlite3_free (table);
688 table = sqlite3_mprintf ("%s_edge_face_right_fk", topo_name);
689 xconstraint4 = gaiaDoubleQuotedSql (table);
690 sqlite3_free (table);
691 table = sqlite3_mprintf ("%s_node", topo_name);
692 xnodes = gaiaDoubleQuotedSql (table);
693 sqlite3_free (table);
694 table = sqlite3_mprintf ("%s_face", topo_name);
695 xfaces = gaiaDoubleQuotedSql (table);
696 sqlite3_free (table);
697 sql = sqlite3_mprintf ("CREATE TABLE \"%s\" (\n"
698 "\tedge_id INTEGER PRIMARY KEY AUTOINCREMENT,\n"
699 "\tstart_node INTEGER NOT NULL,\n"
700 "\tend_node INTEGER NOT NULL,\n"
701 "\tnext_left_edge INTEGER NOT NULL,\n"
702 "\tnext_right_edge INTEGER NOT NULL,\n"
703 "\tleft_face INTEGER,\n"
704 "\tright_face INTEGER,\n"
705 "\ttimestamp DATETIME,\n"
706 "\tCONSTRAINT \"%s\" FOREIGN KEY (start_node) "
707 "REFERENCES \"%s\" (node_id),\n"
708 "\tCONSTRAINT \"%s\" FOREIGN KEY (end_node) "
709 "REFERENCES \"%s\" (node_id),\n"
710 "\tCONSTRAINT \"%s\" FOREIGN KEY (left_face) "
711 "REFERENCES \"%s\" (face_id),\n"
712 "\tCONSTRAINT \"%s\" FOREIGN KEY (right_face) "
713 "REFERENCES \"%s\" (face_id))",
714 xtable, xconstraint1, xnodes, xconstraint2, xnodes,
715 xconstraint3, xfaces, xconstraint4, xfaces);
716 free (xtable);
717 free (xconstraint1);
718 free (xconstraint2);
719 free (xconstraint3);
720 free (xconstraint4);
721 free (xnodes);
722 free (xfaces);
723 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
724 sqlite3_free (sql);
725 if (ret != SQLITE_OK)
726 {
727 spatialite_e ("CREATE TABLE topology-EDGE - error: %s\n", err_msg);
728 sqlite3_free (err_msg);
729 return 0;
730 }
731
732 /* adding the "next_edge_ins" trigger */
733 trigger = sqlite3_mprintf ("%s_edge_next_ins", topo_name);
734 xtrigger = gaiaDoubleQuotedSql (trigger);
735 sqlite3_free (trigger);
736 table = sqlite3_mprintf ("%s_edge", topo_name);
737 xtable = gaiaDoubleQuotedSql (table);
738 sqlite3_free (table);
739 sql = sqlite3_mprintf ("CREATE TRIGGER \"%s\" AFTER INSERT ON \"%s\"\n"
740 "FOR EACH ROW BEGIN\n"
741 "\tUPDATE topologies SET next_edge_id = NEW.edge_id + 1 "
742 "WHERE Lower(topology_name) = Lower(%Q) AND next_edge_id < NEW.edge_id + 1;\n"
743 "\tUPDATE \"%s\" SET timestamp = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
744 "WHERE edge_id = NEW.edge_id;"
745 "END", xtrigger, xtable, topo_name, xtable);
746 free (xtrigger);
747 free (xtable);
748 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
749 sqlite3_free (sql);
750 if (ret != SQLITE_OK)
751 {
752 spatialite_e
753 ("CREATE TRIGGER topology-EDGE next INSERT - error: %s\n",
754 err_msg);
755 sqlite3_free (err_msg);
756 return 0;
757 }
758
759 /* adding the "edge_update" trigger */
760 trigger = sqlite3_mprintf ("%s_edge_update", topo_name);
761 xtrigger = gaiaDoubleQuotedSql (trigger);
762 sqlite3_free (trigger);
763 table = sqlite3_mprintf ("%s_edge", topo_name);
764 xtable = gaiaDoubleQuotedSql (table);
765 sqlite3_free (table);
766 sql = sqlite3_mprintf ("CREATE TRIGGER \"%s\" AFTER UPDATE ON \"%s\"\n"
767 "FOR EACH ROW BEGIN\n"
768 "\tUPDATE \"%s\" SET timestamp = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
769 "WHERE edge_id = NEW.edge_id;"
770 "END", xtrigger, xtable, xtable);
771 free (xtrigger);
772 free (xtable);
773 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
774 sqlite3_free (sql);
775 if (ret != SQLITE_OK)
776 {
777 spatialite_e
778 ("CREATE TRIGGER topology-EDGE next INSERT - error: %s\n",
779 err_msg);
780 sqlite3_free (err_msg);
781 return 0;
782 }
783
784 /* adding the "next_edge_upd" trigger */
785 trigger = sqlite3_mprintf ("%s_edge_next_upd", topo_name);
786 xtrigger = gaiaDoubleQuotedSql (trigger);
787 sqlite3_free (trigger);
788 table = sqlite3_mprintf ("%s_edge", topo_name);
789 xtable = gaiaDoubleQuotedSql (table);
790 sqlite3_free (table);
791 sql =
792 sqlite3_mprintf
793 ("CREATE TRIGGER \"%s\" AFTER UPDATE OF edge_id ON \"%s\"\n"
794 "FOR EACH ROW BEGIN\n"
795 "\tUPDATE topologies SET next_edge_id = NEW.edge_id + 1 "
796 "WHERE Lower(topology_name) = Lower(%Q) AND next_edge_id < NEW.edge_id + 1;\n"
797 "END", xtrigger, xtable, topo_name);
798 free (xtrigger);
799 free (xtable);
800 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
801 sqlite3_free (sql);
802 if (ret != SQLITE_OK)
803 {
804 spatialite_e
805 ("CREATE TRIGGER topology-EDGE next UPDATE - error: %s\n",
806 err_msg);
807 sqlite3_free (err_msg);
808 return 0;
809 }
810
811 /* creating the Edge Geometry */
812 table = sqlite3_mprintf ("%s_edge", topo_name);
813 sql =
814 sqlite3_mprintf
815 ("SELECT AddGeometryColumn(%Q, 'geom', %d, 'LINESTRING', %Q, 1)",
816 table, srid, has_z ? "XYZ" : "XY");
817 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
818 sqlite3_free (table);
819 sqlite3_free (sql);
820 if (ret != SQLITE_OK)
821 {
822 spatialite_e
823 ("AddGeometryColumn topology-EDGE - error: %s\n", err_msg);
824 sqlite3_free (err_msg);
825 return 0;
826 }
827
828 /* creating a Spatial Index supporting Edge Geometry */
829 table = sqlite3_mprintf ("%s_edge", topo_name);
830 sql = sqlite3_mprintf ("SELECT CreateSpatialIndex(%Q, 'geom')", table);
831 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
832 sqlite3_free (table);
833 sqlite3_free (sql);
834 if (ret != SQLITE_OK)
835 {
836 spatialite_e
837 ("CreateSpatialIndex topology-EDGE - error: %s\n", err_msg);
838 sqlite3_free (err_msg);
839 return 0;
840 }
841
842 /* creating an Index supporting "start_node" */
843 table = sqlite3_mprintf ("%s_edge", topo_name);
844 xtable = gaiaDoubleQuotedSql (table);
845 sqlite3_free (table);
846 table = sqlite3_mprintf ("idx_%s_start_node", topo_name);
847 xconstraint1 = gaiaDoubleQuotedSql (table);
848 sqlite3_free (table);
849 sql =
850 sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (start_node)",
851 xconstraint1, xtable);
852 free (xtable);
853 free (xconstraint1);
854 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
855 sqlite3_free (sql);
856 if (ret != SQLITE_OK)
857 {
858 spatialite_e ("CREATE INDEX edge-startnode - error: %s\n", err_msg);
859 sqlite3_free (err_msg);
860 return 0;
861 }
862
863 /* creating an Index supporting "end_node" */
864 table = sqlite3_mprintf ("%s_edge", topo_name);
865 xtable = gaiaDoubleQuotedSql (table);
866 sqlite3_free (table);
867 table = sqlite3_mprintf ("idx_%s_end_node", topo_name);
868 xconstraint1 = gaiaDoubleQuotedSql (table);
869 sqlite3_free (table);
870 sql =
871 sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (end_node)",
872 xconstraint1, xtable);
873 free (xtable);
874 free (xconstraint1);
875 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
876 sqlite3_free (sql);
877 if (ret != SQLITE_OK)
878 {
879 spatialite_e ("CREATE INDEX edge-endnode - error: %s\n", err_msg);
880 sqlite3_free (err_msg);
881 return 0;
882 }
883
884 /* creating an Index supporting "left_face" */
885 table = sqlite3_mprintf ("%s_edge", topo_name);
886 xtable = gaiaDoubleQuotedSql (table);
887 sqlite3_free (table);
888 table = sqlite3_mprintf ("idx_%s_edge_leftface", topo_name);
889 xconstraint1 = gaiaDoubleQuotedSql (table);
890 sqlite3_free (table);
891 sql =
892 sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (left_face)",
893 xconstraint1, xtable);
894 free (xtable);
895 free (xconstraint1);
896 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
897 sqlite3_free (sql);
898 if (ret != SQLITE_OK)
899 {
900 spatialite_e ("CREATE INDEX edge-leftface - error: %s\n", err_msg);
901 sqlite3_free (err_msg);
902 return 0;
903 }
904
905 /* creating an Index supporting "right_face" */
906 table = sqlite3_mprintf ("%s_edge", topo_name);
907 xtable = gaiaDoubleQuotedSql (table);
908 sqlite3_free (table);
909 table = sqlite3_mprintf ("idx_%s_edge_rightface", topo_name);
910 xconstraint1 = gaiaDoubleQuotedSql (table);
911 sqlite3_free (table);
912 sql =
913 sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (right_face)",
914 xconstraint1, xtable);
915 free (xtable);
916 free (xconstraint1);
917 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
918 sqlite3_free (sql);
919 if (ret != SQLITE_OK)
920 {
921 spatialite_e ("CREATE INDEX edge-rightface - error: %s\n", err_msg);
922 sqlite3_free (err_msg);
923 return 0;
924 }
925
926 /* creating an Index supporting "timestamp" */
927 table = sqlite3_mprintf ("%s_edge", topo_name);
928 xtable = gaiaDoubleQuotedSql (table);
929 sqlite3_free (table);
930 table = sqlite3_mprintf ("idx_%s_timestamp", topo_name);
931 xconstraint1 = gaiaDoubleQuotedSql (table);
932 sqlite3_free (table);
933 sql =
934 sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (timestamp)",
935 xconstraint1, xtable);
936 free (xtable);
937 free (xconstraint1);
938 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
939 sqlite3_free (sql);
940 if (ret != SQLITE_OK)
941 {
942 spatialite_e ("CREATE INDEX edge-timestamps - error: %s\n", err_msg);
943 sqlite3_free (err_msg);
944 return 0;
945 }
946
947 return 1;
948 }
949
950 static int
do_create_seeds(sqlite3 * handle,const char * topo_name,int srid,int has_z)951 do_create_seeds (sqlite3 * handle, const char *topo_name, int srid, int has_z)
952 {
953 /* attempting to create the Topology Seeds table */
954 char *sql;
955 char *table;
956 char *xtable;
957 char *xconstraint1;
958 char *xconstraint2;
959 char *xedges;
960 char *xfaces;
961 char *trigger;
962 char *xtrigger;
963 char *err_msg = NULL;
964 int ret;
965
966 /* creating the main table */
967 table = sqlite3_mprintf ("%s_seeds", topo_name);
968 xtable = gaiaDoubleQuotedSql (table);
969 sqlite3_free (table);
970 table = sqlite3_mprintf ("%s_seeds_edge_fk", topo_name);
971 xconstraint1 = gaiaDoubleQuotedSql (table);
972 sqlite3_free (table);
973 table = sqlite3_mprintf ("%s_seeds_face_fk", topo_name);
974 xconstraint2 = gaiaDoubleQuotedSql (table);
975 sqlite3_free (table);
976 table = sqlite3_mprintf ("%s_edge", topo_name);
977 xedges = gaiaDoubleQuotedSql (table);
978 sqlite3_free (table);
979 table = sqlite3_mprintf ("%s_face", topo_name);
980 xfaces = gaiaDoubleQuotedSql (table);
981 sqlite3_free (table);
982 sql = sqlite3_mprintf ("CREATE TABLE \"%s\" (\n"
983 "\tseed_id INTEGER PRIMARY KEY AUTOINCREMENT,\n"
984 "\tedge_id INTEGER,\n"
985 "\tface_id INTEGER,\n"
986 "\ttimestamp DATETIME,\n"
987 "\tCONSTRAINT \"%s\" FOREIGN KEY (edge_id) "
988 "REFERENCES \"%s\" (edge_id) ON DELETE CASCADE,\n"
989 "\tCONSTRAINT \"%s\" FOREIGN KEY (face_id) "
990 "REFERENCES \"%s\" (face_id) ON DELETE CASCADE)",
991 xtable, xconstraint1, xedges, xconstraint2, xfaces);
992 free (xtable);
993 free (xconstraint1);
994 free (xconstraint2);
995 free (xedges);
996 free (xfaces);
997 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
998 sqlite3_free (sql);
999 if (ret != SQLITE_OK)
1000 {
1001 spatialite_e ("CREATE TABLE topology-SEEDS - error: %s\n", err_msg);
1002 sqlite3_free (err_msg);
1003 return 0;
1004 }
1005
1006 /* adding the "seeds_ins" trigger */
1007 trigger = sqlite3_mprintf ("%s_seeds_ins", topo_name);
1008 xtrigger = gaiaDoubleQuotedSql (trigger);
1009 sqlite3_free (trigger);
1010 table = sqlite3_mprintf ("%s_seeds", topo_name);
1011 xtable = gaiaDoubleQuotedSql (table);
1012 sqlite3_free (table);
1013 sql = sqlite3_mprintf ("CREATE TRIGGER \"%s\" AFTER INSERT ON \"%s\"\n"
1014 "FOR EACH ROW BEGIN\n"
1015 "\tUPDATE \"%s\" SET timestamp = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
1016 "WHERE seed_id = NEW.seed_id;"
1017 "END", xtrigger, xtable, xtable);
1018 free (xtrigger);
1019 free (xtable);
1020 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1021 sqlite3_free (sql);
1022 if (ret != SQLITE_OK)
1023 {
1024 spatialite_e
1025 ("CREATE TRIGGER topology-SEEDS next INSERT - error: %s\n",
1026 err_msg);
1027 sqlite3_free (err_msg);
1028 return 0;
1029 }
1030
1031 /* adding the "seeds_update" trigger */
1032 trigger = sqlite3_mprintf ("%s_seeds_update", topo_name);
1033 xtrigger = gaiaDoubleQuotedSql (trigger);
1034 sqlite3_free (trigger);
1035 table = sqlite3_mprintf ("%s_seeds", topo_name);
1036 xtable = gaiaDoubleQuotedSql (table);
1037 sqlite3_free (table);
1038 sql = sqlite3_mprintf ("CREATE TRIGGER \"%s\" AFTER UPDATE ON \"%s\"\n"
1039 "FOR EACH ROW BEGIN\n"
1040 "\tUPDATE \"%s\" SET timestamp = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
1041 "WHERE seed_id = NEW.seed_id;"
1042 "END", xtrigger, xtable, xtable);
1043 free (xtrigger);
1044 free (xtable);
1045 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1046 sqlite3_free (sql);
1047 if (ret != SQLITE_OK)
1048 {
1049 spatialite_e
1050 ("CREATE TRIGGER topology-SEED next INSERT - error: %s\n",
1051 err_msg);
1052 sqlite3_free (err_msg);
1053 return 0;
1054 }
1055
1056 /* creating the Seeds Geometry */
1057 table = sqlite3_mprintf ("%s_seeds", topo_name);
1058 sql =
1059 sqlite3_mprintf
1060 ("SELECT AddGeometryColumn(%Q, 'geom', %d, 'POINT', %Q, 1)",
1061 table, srid, has_z ? "XYZ" : "XY");
1062 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1063 sqlite3_free (table);
1064 sqlite3_free (sql);
1065 if (ret != SQLITE_OK)
1066 {
1067 spatialite_e
1068 ("AddGeometryColumn topology-SEEDS - error: %s\n", err_msg);
1069 sqlite3_free (err_msg);
1070 return 0;
1071 }
1072
1073 /* creating a Spatial Index supporting Seeds Geometry */
1074 table = sqlite3_mprintf ("%s_seeds", topo_name);
1075 sql = sqlite3_mprintf ("SELECT CreateSpatialIndex(%Q, 'geom')", table);
1076 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1077 sqlite3_free (table);
1078 sqlite3_free (sql);
1079 if (ret != SQLITE_OK)
1080 {
1081 spatialite_e
1082 ("CreateSpatialIndex topology-SEEDS - error: %s\n", err_msg);
1083 sqlite3_free (err_msg);
1084 return 0;
1085 }
1086
1087 /* creating an Index supporting "edge_id" */
1088 table = sqlite3_mprintf ("%s_seeds", topo_name);
1089 xtable = gaiaDoubleQuotedSql (table);
1090 sqlite3_free (table);
1091 table = sqlite3_mprintf ("idx_%s_sdedge", topo_name);
1092 xconstraint1 = gaiaDoubleQuotedSql (table);
1093 sqlite3_free (table);
1094 sql =
1095 sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (edge_id)",
1096 xconstraint1, xtable);
1097 free (xtable);
1098 free (xconstraint1);
1099 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1100 sqlite3_free (sql);
1101 if (ret != SQLITE_OK)
1102 {
1103 spatialite_e ("CREATE INDEX seeds-edge - error: %s\n", err_msg);
1104 sqlite3_free (err_msg);
1105 return 0;
1106 }
1107
1108 /* creating an Index supporting "face_id" */
1109 table = sqlite3_mprintf ("%s_seeds", topo_name);
1110 xtable = gaiaDoubleQuotedSql (table);
1111 sqlite3_free (table);
1112 table = sqlite3_mprintf ("idx_%s_sdface", topo_name);
1113 xconstraint1 = gaiaDoubleQuotedSql (table);
1114 sqlite3_free (table);
1115 sql =
1116 sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (face_id)",
1117 xconstraint1, xtable);
1118 free (xtable);
1119 free (xconstraint1);
1120 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1121 sqlite3_free (sql);
1122 if (ret != SQLITE_OK)
1123 {
1124 spatialite_e ("CREATE INDEX seeds-face - error: %s\n", err_msg);
1125 sqlite3_free (err_msg);
1126 return 0;
1127 }
1128
1129 /* creating an Index supporting "timestamp" */
1130 table = sqlite3_mprintf ("%s_seeds", topo_name);
1131 xtable = gaiaDoubleQuotedSql (table);
1132 sqlite3_free (table);
1133 table = sqlite3_mprintf ("idx_%s_seeds_timestamp", topo_name);
1134 xconstraint1 = gaiaDoubleQuotedSql (table);
1135 sqlite3_free (table);
1136 sql =
1137 sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (timestamp)",
1138 xconstraint1, xtable);
1139 free (xtable);
1140 free (xconstraint1);
1141 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1142 sqlite3_free (sql);
1143 if (ret != SQLITE_OK)
1144 {
1145 spatialite_e ("CREATE INDEX seeds-timestamps - error: %s\n", err_msg);
1146 sqlite3_free (err_msg);
1147 return 0;
1148 }
1149
1150 return 1;
1151 }
1152
1153 static int
do_create_edge_seeds(sqlite3 * handle,const char * topo_name)1154 do_create_edge_seeds (sqlite3 * handle, const char *topo_name)
1155 {
1156 /* attempting to create the Edge Seeds view */
1157 char *sql;
1158 char *table;
1159 char *xtable;
1160 char *xview;
1161 char *err_msg = NULL;
1162 int ret;
1163
1164 /* creating the view */
1165 table = sqlite3_mprintf ("%s_edge_seeds", topo_name);
1166 xview = gaiaDoubleQuotedSql (table);
1167 sqlite3_free (table);
1168 table = sqlite3_mprintf ("%s_seeds", topo_name);
1169 xtable = gaiaDoubleQuotedSql (table);
1170 sqlite3_free (table);
1171 sql = sqlite3_mprintf ("CREATE VIEW \"%s\" AS\n"
1172 "SELECT seed_id AS rowid, edge_id AS edge_id, geom AS geom\n"
1173 "FROM \"%s\"\n"
1174 "WHERE edge_id IS NOT NULL", xview, xtable);
1175 free (xtable);
1176 free (xview);
1177 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1178 sqlite3_free (sql);
1179 if (ret != SQLITE_OK)
1180 {
1181 spatialite_e ("CREATE VIEW topology-EDGE-SEEDS - error: %s\n",
1182 err_msg);
1183 sqlite3_free (err_msg);
1184 return 0;
1185 }
1186
1187 /* registering a Spatial View */
1188 xview = sqlite3_mprintf ("%s_edge_seeds", topo_name);
1189 xtable = sqlite3_mprintf ("%s_seeds", topo_name);
1190 sql = sqlite3_mprintf ("INSERT INTO views_geometry_columns (view_name, "
1191 "view_geometry, view_rowid, f_table_name, f_geometry_column, read_only) "
1192 "VALUES (Lower(%Q), 'geom', 'rowid', Lower(%Q), 'geom', 1)",
1193 xview, xtable);
1194 sqlite3_free (xview);
1195 sqlite3_free (xtable);
1196 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1197 sqlite3_free (sql);
1198 if (ret != SQLITE_OK)
1199 {
1200 spatialite_e
1201 ("Registering Spatial VIEW topology-EDGE-SEEDS - error: %s\n",
1202 err_msg);
1203 sqlite3_free (err_msg);
1204 return 0;
1205 }
1206
1207 return 1;
1208 }
1209
1210 static int
do_create_face_seeds(sqlite3 * handle,const char * topo_name)1211 do_create_face_seeds (sqlite3 * handle, const char *topo_name)
1212 {
1213 /* attempting to create the Face Seeds view */
1214 char *sql;
1215 char *table;
1216 char *xtable;
1217 char *xview;
1218 char *err_msg = NULL;
1219 int ret;
1220
1221 /* creating the view */
1222 table = sqlite3_mprintf ("%s_face_seeds", topo_name);
1223 xview = gaiaDoubleQuotedSql (table);
1224 sqlite3_free (table);
1225 table = sqlite3_mprintf ("%s_seeds", topo_name);
1226 xtable = gaiaDoubleQuotedSql (table);
1227 sqlite3_free (table);
1228 sql = sqlite3_mprintf ("CREATE VIEW \"%s\" AS\n"
1229 "SELECT seed_id AS rowid, face_id AS face_id, geom AS geom\n"
1230 "FROM \"%s\"\n"
1231 "WHERE face_id IS NOT NULL", xview, xtable);
1232 free (xtable);
1233 free (xview);
1234 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1235 sqlite3_free (sql);
1236 if (ret != SQLITE_OK)
1237 {
1238 spatialite_e ("CREATE VIEW topology-FACE-SEEDS - error: %s\n",
1239 err_msg);
1240 sqlite3_free (err_msg);
1241 return 0;
1242 }
1243
1244 /* registering a Spatial View */
1245 xview = sqlite3_mprintf ("%s_face_seeds", topo_name);
1246 xtable = sqlite3_mprintf ("%s_seeds", topo_name);
1247 sql = sqlite3_mprintf ("INSERT INTO views_geometry_columns (view_name, "
1248 "view_geometry, view_rowid, f_table_name, f_geometry_column, read_only) "
1249 "VALUES (Lower(%Q), 'geom', 'rowid', Lower(%Q), 'geom', 1)",
1250 xview, xtable);
1251 sqlite3_free (xview);
1252 sqlite3_free (xtable);
1253 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1254 sqlite3_free (sql);
1255 if (ret != SQLITE_OK)
1256 {
1257 spatialite_e
1258 ("Registering Spatial VIEW topology-FACE-SEEDS - error: %s\n",
1259 err_msg);
1260 sqlite3_free (err_msg);
1261 return 0;
1262 }
1263
1264 return 1;
1265 }
1266
1267 static int
do_create_face_geoms(sqlite3 * handle,const char * topo_name)1268 do_create_face_geoms (sqlite3 * handle, const char *topo_name)
1269 {
1270 /* attempting to create the Face Geoms view */
1271 char *sql;
1272 char *table;
1273 char *xtable;
1274 char *xview;
1275 char *err_msg = NULL;
1276 int ret;
1277
1278 /* creating the view */
1279 table = sqlite3_mprintf ("%s_face_geoms", topo_name);
1280 xview = gaiaDoubleQuotedSql (table);
1281 sqlite3_free (table);
1282 table = sqlite3_mprintf ("%s_face", topo_name);
1283 xtable = gaiaDoubleQuotedSql (table);
1284 sqlite3_free (table);
1285 sql = sqlite3_mprintf ("CREATE VIEW \"%s\" AS\n"
1286 "SELECT face_id AS rowid, ST_GetFaceGeometry(%Q, face_id) AS geom\n"
1287 "FROM \"%s\"\n"
1288 "WHERE face_id <> 0", xview, topo_name, xtable);
1289 free (xtable);
1290 free (xview);
1291 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1292 sqlite3_free (sql);
1293 if (ret != SQLITE_OK)
1294 {
1295 spatialite_e ("CREATE VIEW topology-FACE-GEOMS - error: %s\n",
1296 err_msg);
1297 sqlite3_free (err_msg);
1298 return 0;
1299 }
1300
1301 /* registering a Spatial View */
1302 xview = sqlite3_mprintf ("%s_face_geoms", topo_name);
1303 xtable = sqlite3_mprintf ("%s_face", topo_name);
1304 sql = sqlite3_mprintf ("INSERT INTO views_geometry_columns (view_name, "
1305 "view_geometry, view_rowid, f_table_name, f_geometry_column, read_only) "
1306 "VALUES (Lower(%Q), 'geom', 'rowid', Lower(%Q), 'mbr', 1)",
1307 xview, xtable);
1308 sqlite3_free (xview);
1309 sqlite3_free (xtable);
1310 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1311 sqlite3_free (sql);
1312 if (ret != SQLITE_OK)
1313 {
1314 spatialite_e
1315 ("Registering Spatial VIEW topology-FACE-GEOMS - error: %s\n",
1316 err_msg);
1317 sqlite3_free (err_msg);
1318 return 0;
1319 }
1320
1321 return 1;
1322 }
1323
1324 static int
do_create_topolayers(sqlite3 * handle,const char * topo_name)1325 do_create_topolayers (sqlite3 * handle, const char *topo_name)
1326 {
1327 /* attempting to create the TopoLayers table */
1328 char *sql;
1329 char *table;
1330 char *xtable;
1331 char *xtrigger;
1332 char *err_msg = NULL;
1333 int ret;
1334
1335 /* creating the main table */
1336 table = sqlite3_mprintf ("%s_topolayers", topo_name);
1337 xtable = gaiaDoubleQuotedSql (table);
1338 sqlite3_free (table);
1339 sql = sqlite3_mprintf ("CREATE TABLE \"%s\" (\n"
1340 "\ttopolayer_id INTEGER PRIMARY KEY AUTOINCREMENT,\n"
1341 "\ttopolayer_name NOT NULL UNIQUE)", xtable);
1342 free (xtable);
1343 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1344 sqlite3_free (sql);
1345 if (ret != SQLITE_OK)
1346 {
1347 spatialite_e ("CREATE TABLE topology-TOPOLAYERS - error: %s\n",
1348 err_msg);
1349 sqlite3_free (err_msg);
1350 return 0;
1351 }
1352
1353 /* creating TopoLayers triggers */
1354 table = sqlite3_mprintf ("%s_topolayers", topo_name);
1355 xtable = gaiaDoubleQuotedSql (table);
1356 sqlite3_free (table);
1357 table = sqlite3_mprintf ("%s_topolayer_name_insert", topo_name);
1358 xtrigger = gaiaDoubleQuotedSql (table);
1359 sqlite3_free (table);
1360 sql = sqlite3_mprintf ("CREATE TRIGGER IF NOT EXISTS \"%s\"\n"
1361 "BEFORE INSERT ON \"%s\"\nFOR EACH ROW BEGIN\n"
1362 "SELECT RAISE(ABORT,'insert on topolayers violates constraint: "
1363 "topolayer_name value must not contain a single quote')\n"
1364 "WHERE NEW.topolayer_name LIKE ('%%''%%');\n"
1365 "SELECT RAISE(ABORT,'insert on topolayers violates constraint: "
1366 "topolayers_name value must not contain a double quote')\n"
1367 "WHERE NEW.topolayer_name LIKE ('%%\"%%');\n"
1368 "SELECT RAISE(ABORT,'insert on topolayers violates constraint: "
1369 "topolayer_name value must be lower case')\n"
1370 "WHERE NEW.topolayer_name <> lower(NEW.topolayer_name);\nEND",
1371 xtrigger, xtable);
1372 free (xtable);
1373 free (xtrigger);
1374 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1375 sqlite3_free (sql);
1376 if (ret != SQLITE_OK)
1377 {
1378 spatialite_e ("SQL error: %s\n", err_msg);
1379 sqlite3_free (err_msg);
1380 return 0;
1381 }
1382 table = sqlite3_mprintf ("%s_topolayers", topo_name);
1383 xtable = gaiaDoubleQuotedSql (table);
1384 sqlite3_free (table);
1385 table = sqlite3_mprintf ("%s_topolayer_name_update", topo_name);
1386 xtrigger = gaiaDoubleQuotedSql (table);
1387 sqlite3_free (table);
1388 sql = sqlite3_mprintf ("CREATE TRIGGER IF NOT EXISTS \"%s\"\n"
1389 "BEFORE UPDATE OF 'topolayer_name' ON \"%s\"\nFOR EACH ROW BEGIN\n"
1390 "SELECT RAISE(ABORT,'update on topolayers violates constraint: "
1391 "topolayer_name value must not contain a single quote')\n"
1392 "WHERE NEW.topolayer_name LIKE ('%%''%%');\n"
1393 "SELECT RAISE(ABORT,'update on topolayers violates constraint: "
1394 "topolayer_name value must not contain a double quote')\n"
1395 "WHERE NEW.topolayer_name LIKE ('%%\"%%');\n"
1396 "SELECT RAISE(ABORT,'update on topolayers violates constraint: "
1397 "topolayer_name value must be lower case')\n"
1398 "WHERE NEW.topolayer_name <> lower(NEW.topolayer_name);\nEND",
1399 xtrigger, xtable);
1400 free (xtable);
1401 free (xtrigger);
1402 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1403 sqlite3_free (sql);
1404 if (ret != SQLITE_OK)
1405 {
1406 spatialite_e ("SQL error: %s\n", err_msg);
1407 sqlite3_free (err_msg);
1408 return 0;
1409 }
1410
1411 return 1;
1412 }
1413
1414 static int
do_create_topofeatures(sqlite3 * handle,const char * topo_name)1415 do_create_topofeatures (sqlite3 * handle, const char *topo_name)
1416 {
1417 /* attempting to create the TopoFeatures table */
1418 char *sql;
1419 char *table;
1420 char *xtable;
1421 char *xtable1;
1422 char *xtable2;
1423 char *xtable3;
1424 char *xtable4;
1425 char *xconstraint1;
1426 char *xconstraint2;
1427 char *xconstraint3;
1428 char *xconstraint4;
1429 char *err_msg = NULL;
1430 int ret;
1431
1432 /* creating the main table */
1433 table = sqlite3_mprintf ("%s_topofeatures", topo_name);
1434 xtable = gaiaDoubleQuotedSql (table);
1435 sqlite3_free (table);
1436 table = sqlite3_mprintf ("%s_node", topo_name);
1437 xtable1 = gaiaDoubleQuotedSql (table);
1438 sqlite3_free (table);
1439 table = sqlite3_mprintf ("%s_edge", topo_name);
1440 xtable2 = gaiaDoubleQuotedSql (table);
1441 sqlite3_free (table);
1442 table = sqlite3_mprintf ("%s_face", topo_name);
1443 xtable3 = gaiaDoubleQuotedSql (table);
1444 sqlite3_free (table);
1445 table = sqlite3_mprintf ("%s_topolayers", topo_name);
1446 xtable4 = gaiaDoubleQuotedSql (table);
1447 sqlite3_free (table);
1448 table = sqlite3_mprintf ("fk_%s_ftnode", topo_name);
1449 xconstraint1 = gaiaDoubleQuotedSql (table);
1450 sqlite3_free (table);
1451 table = sqlite3_mprintf ("fk_%s_ftedge", topo_name);
1452 xconstraint2 = gaiaDoubleQuotedSql (table);
1453 sqlite3_free (table);
1454 table = sqlite3_mprintf ("fk_%s_ftface", topo_name);
1455 xconstraint3 = gaiaDoubleQuotedSql (table);
1456 sqlite3_free (table);
1457 table = sqlite3_mprintf ("fk_%s_topolayer", topo_name);
1458 xconstraint4 = gaiaDoubleQuotedSql (table);
1459 sqlite3_free (table);
1460 sql = sqlite3_mprintf ("CREATE TABLE \"%s\" (\n"
1461 "\tuid INTEGER PRIMARY KEY AUTOINCREMENT,\n"
1462 "\tnode_id INTEGER,\n\tedge_id INTEGER,\n"
1463 "\tface_id INTEGER,\n\ttopolayer_id INTEGER NOT NULL,\n"
1464 "\tfid INTEGER NOT NULL,\n"
1465 "\tCONSTRAINT \"%s\" FOREIGN KEY (node_id) "
1466 "REFERENCES \"%s\" (node_id) ON DELETE CASCADE,\n"
1467 "\tCONSTRAINT \"%s\" FOREIGN KEY (edge_id) "
1468 "REFERENCES \"%s\" (edge_id) ON DELETE CASCADE,\n"
1469 "\tCONSTRAINT \"%s\" FOREIGN KEY (face_id) "
1470 "REFERENCES \"%s\" (face_id) ON DELETE CASCADE,\n"
1471 "\tCONSTRAINT \"%s\" FOREIGN KEY (topolayer_id) "
1472 "REFERENCES \"%s\" (topolayer_id) ON DELETE CASCADE)",
1473 xtable, xconstraint1, xtable1, xconstraint2, xtable2,
1474 xconstraint3, xtable3, xconstraint4, xtable4);
1475 free (xtable);
1476 free (xtable1);
1477 free (xtable2);
1478 free (xtable3);
1479 free (xtable4);
1480 free (xconstraint1);
1481 free (xconstraint2);
1482 free (xconstraint3);
1483 free (xconstraint4);
1484 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1485 sqlite3_free (sql);
1486 if (ret != SQLITE_OK)
1487 {
1488 spatialite_e ("CREATE TABLE topology-TOPOFEATURES - error: %s\n",
1489 err_msg);
1490 sqlite3_free (err_msg);
1491 return 0;
1492 }
1493
1494 /* creating an Index supporting "node_id" */
1495 table = sqlite3_mprintf ("%s_topofeatures", topo_name);
1496 xtable = gaiaDoubleQuotedSql (table);
1497 sqlite3_free (table);
1498 table = sqlite3_mprintf ("idx_%s_ftnode", topo_name);
1499 xconstraint1 = gaiaDoubleQuotedSql (table);
1500 sqlite3_free (table);
1501 sql =
1502 sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (node_id)",
1503 xconstraint1, xtable);
1504 free (xtable);
1505 free (xconstraint1);
1506 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1507 sqlite3_free (sql);
1508 if (ret != SQLITE_OK)
1509 {
1510 spatialite_e ("CREATE INDEX topofeatures-node - error: %s\n",
1511 err_msg);
1512 sqlite3_free (err_msg);
1513 return 0;
1514 }
1515
1516 /* creating an Index supporting "edge_id" */
1517 table = sqlite3_mprintf ("%s_topofeatures", topo_name);
1518 xtable = gaiaDoubleQuotedSql (table);
1519 sqlite3_free (table);
1520 table = sqlite3_mprintf ("idx_%s_ftedge", topo_name);
1521 xconstraint1 = gaiaDoubleQuotedSql (table);
1522 sqlite3_free (table);
1523 sql =
1524 sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (edge_id)",
1525 xconstraint1, xtable);
1526 free (xtable);
1527 free (xconstraint1);
1528 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1529 sqlite3_free (sql);
1530 if (ret != SQLITE_OK)
1531 {
1532 spatialite_e ("CREATE INDEX topofeatures-edge - error: %s\n",
1533 err_msg);
1534 sqlite3_free (err_msg);
1535 return 0;
1536 }
1537
1538 /* creating an Index supporting "face_id" */
1539 table = sqlite3_mprintf ("%s_topofeatures", topo_name);
1540 xtable = gaiaDoubleQuotedSql (table);
1541 sqlite3_free (table);
1542 table = sqlite3_mprintf ("idx_%s_ftface", topo_name);
1543 xconstraint1 = gaiaDoubleQuotedSql (table);
1544 sqlite3_free (table);
1545 sql =
1546 sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (face_id)",
1547 xconstraint1, xtable);
1548 free (xtable);
1549 free (xconstraint1);
1550 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1551 sqlite3_free (sql);
1552 if (ret != SQLITE_OK)
1553 {
1554 spatialite_e ("CREATE INDEX topofeatures-face - error: %s\n",
1555 err_msg);
1556 sqlite3_free (err_msg);
1557 return 0;
1558 }
1559
1560 /* creating an Index supporting "topolayers_id" */
1561 table = sqlite3_mprintf ("%s_topofeatures", topo_name);
1562 xtable = gaiaDoubleQuotedSql (table);
1563 sqlite3_free (table);
1564 table = sqlite3_mprintf ("idx_%s_fttopolayers", topo_name);
1565 xconstraint1 = gaiaDoubleQuotedSql (table);
1566 sqlite3_free (table);
1567 sql =
1568 sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (topolayer_id, fid)",
1569 xconstraint1, xtable);
1570 free (xtable);
1571 free (xconstraint1);
1572 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1573 sqlite3_free (sql);
1574 if (ret != SQLITE_OK)
1575 {
1576 spatialite_e ("CREATE INDEX topofeatures-topolayers - error: %s\n",
1577 err_msg);
1578 sqlite3_free (err_msg);
1579 return 0;
1580 }
1581
1582 return 1;
1583 }
1584
1585 GAIATOPO_DECLARE int
gaiaTopologyCreate(sqlite3 * handle,const char * topo_name,int srid,double tolerance,int has_z)1586 gaiaTopologyCreate (sqlite3 * handle, const char *topo_name, int srid,
1587 double tolerance, int has_z)
1588 {
1589 /* attempting to create a new Topology */
1590 int ret;
1591 char *sql;
1592
1593 /* creating the Topologies table (just in case) */
1594 if (!do_create_topologies (handle))
1595 return 0;
1596
1597 /* testing for forbidding objects */
1598 if (!check_new_topology (handle, topo_name))
1599 return 0;
1600
1601 /* creating the Topology own Tables */
1602 if (!do_create_face (handle, topo_name, srid))
1603 goto error;
1604 if (!do_create_node (handle, topo_name, srid, has_z))
1605 goto error;
1606 if (!do_create_edge (handle, topo_name, srid, has_z))
1607 goto error;
1608 if (!do_create_seeds (handle, topo_name, srid, has_z))
1609 goto error;
1610 if (!do_create_edge_seeds (handle, topo_name))
1611 goto error;
1612 if (!do_create_face_seeds (handle, topo_name))
1613 goto error;
1614 if (!do_create_face_geoms (handle, topo_name))
1615 goto error;
1616 if (!do_create_topolayers (handle, topo_name))
1617 goto error;
1618 if (!do_create_topofeatures (handle, topo_name))
1619 goto error;
1620
1621 /* registering the Topology */
1622 sql = sqlite3_mprintf ("INSERT INTO MAIN.topologies (topology_name, "
1623 "srid, tolerance, has_z) VALUES (Lower(%Q), %d, %f, %d)",
1624 topo_name, srid, tolerance, has_z);
1625 ret = sqlite3_exec (handle, sql, NULL, NULL, NULL);
1626 sqlite3_free (sql);
1627 if (ret != SQLITE_OK)
1628 goto error;
1629
1630 return 1;
1631
1632 error:
1633 return 0;
1634 }
1635
1636 static int
check_existing_topology(sqlite3 * handle,const char * topo_name,int full_check)1637 check_existing_topology (sqlite3 * handle, const char *topo_name,
1638 int full_check)
1639 {
1640 /* testing if a Topology is already defined */
1641 char *sql;
1642 char *prev;
1643 char *table;
1644 int ret;
1645 int i;
1646 char **results;
1647 int rows;
1648 int columns;
1649 const char *value;
1650 int error = 0;
1651
1652 /* testing if the Topology is already defined */
1653 sql = sqlite3_mprintf ("SELECT Count(*) FROM MAIN.topologies WHERE "
1654 "Lower(topology_name) = Lower(%Q)", topo_name);
1655 ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
1656 sqlite3_free (sql);
1657 if (ret != SQLITE_OK)
1658 return 0;
1659 if (rows < 1)
1660 ;
1661 else
1662 {
1663 for (i = 1; i <= rows; i++)
1664 {
1665 value = results[(i * columns) + 0];
1666 if (atoi (value) != 1)
1667 error = 1;
1668 }
1669 }
1670 sqlite3_free_table (results);
1671 if (error)
1672 return 0;
1673 if (!full_check)
1674 return 1;
1675
1676 /* testing if all table/geom are correctly defined in geometry_columns */
1677 sql = sqlite3_mprintf ("SELECT Count(*) FROM geometry_columns WHERE");
1678 prev = sql;
1679 table = sqlite3_mprintf ("%s_node", topo_name);
1680 sql =
1681 sqlite3_mprintf
1682 ("%s (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'geom')",
1683 prev, table);
1684 sqlite3_free (table);
1685 sqlite3_free (prev);
1686 prev = sql;
1687 table = sqlite3_mprintf ("%s_edge", topo_name);
1688 sql =
1689 sqlite3_mprintf
1690 ("%s OR (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'geom')",
1691 prev, table);
1692 sqlite3_free (table);
1693 sqlite3_free (prev);
1694 prev = sql;
1695 table = sqlite3_mprintf ("%s_face", topo_name);
1696 sql =
1697 sqlite3_mprintf
1698 ("%s OR (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'mbr')",
1699 prev, table);
1700 sqlite3_free (table);
1701 sqlite3_free (prev);
1702 ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
1703 sqlite3_free (sql);
1704 if (ret != SQLITE_OK)
1705 return 0;
1706 if (rows < 1)
1707 ;
1708 else
1709 {
1710 for (i = 1; i <= rows; i++)
1711 {
1712 value = results[(i * columns) + 0];
1713 if (atoi (value) != 3)
1714 error = 1;
1715 }
1716 }
1717 sqlite3_free_table (results);
1718 if (error)
1719 return 0;
1720
1721 /* testing if all Spatial Views are correctly defined in geometry_columns */
1722 sql = sqlite3_mprintf ("SELECT Count(*) FROM views_geometry_columns WHERE");
1723 prev = sql;
1724 table = sqlite3_mprintf ("%s_edge_seeds", topo_name);
1725 sql =
1726 sqlite3_mprintf
1727 ("%s (Lower(view_name) = Lower(%Q) AND view_geometry = 'geom')",
1728 prev, table);
1729 sqlite3_free (table);
1730 sqlite3_free (prev);
1731 prev = sql;
1732 table = sqlite3_mprintf ("%s_face_seeds", topo_name);
1733 sql =
1734 sqlite3_mprintf
1735 ("%s OR (Lower(view_name) = Lower(%Q) AND view_geometry = 'geom')",
1736 prev, table);
1737 sqlite3_free (table);
1738 sqlite3_free (prev);
1739 prev = sql;
1740 table = sqlite3_mprintf ("%s_face_geoms", topo_name);
1741 sql =
1742 sqlite3_mprintf
1743 ("%s OR (Lower(view_name) = Lower(%Q) AND view_geometry = 'geom')",
1744 prev, table);
1745 sqlite3_free (table);
1746 sqlite3_free (prev);
1747 ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
1748 sqlite3_free (sql);
1749 if (ret != SQLITE_OK)
1750 return 0;
1751 if (rows < 1)
1752 ;
1753 else
1754 {
1755 for (i = 1; i <= rows; i++)
1756 {
1757 value = results[(i * columns) + 0];
1758 if (atoi (value) != 3)
1759 error = 1;
1760 }
1761 }
1762 sqlite3_free_table (results);
1763 if (error)
1764 return 0;
1765
1766
1767 /* testing if all tables are already defined */
1768 sql =
1769 sqlite3_mprintf
1770 ("SELECT Count(*) FROM sqlite_master WHERE (type = 'table' AND (");
1771 prev = sql;
1772 table = sqlite3_mprintf ("%s_node", topo_name);
1773 sql = sqlite3_mprintf ("%s Lower(name) = Lower(%Q)", prev, table);
1774 sqlite3_free (table);
1775 sqlite3_free (prev);
1776 prev = sql;
1777 table = sqlite3_mprintf ("%s_edge", topo_name);
1778 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
1779 sqlite3_free (table);
1780 sqlite3_free (prev);
1781 prev = sql;
1782 table = sqlite3_mprintf ("%s_face", topo_name);
1783 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
1784 sqlite3_free (table);
1785 sqlite3_free (prev);
1786 prev = sql;
1787 table = sqlite3_mprintf ("idx_%s_node_geom", topo_name);
1788 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
1789 sqlite3_free (table);
1790 sqlite3_free (prev);
1791 prev = sql;
1792 table = sqlite3_mprintf ("idx_%s_edge_geom", topo_name);
1793 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
1794 sqlite3_free (table);
1795 sqlite3_free (prev);
1796 prev = sql;
1797 table = sqlite3_mprintf ("idx_%s_face_mbr", topo_name);
1798 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)))", prev, table);
1799 sqlite3_free (table);
1800 sqlite3_free (prev);
1801 prev = sql;
1802 table = sqlite3_mprintf ("%s_edge_seeds", topo_name);
1803 sql =
1804 sqlite3_mprintf ("%s OR (type = 'view' AND (Lower(name) = Lower(%Q)",
1805 prev, table);
1806 sqlite3_free (table);
1807 sqlite3_free (prev);
1808 prev = sql;
1809 table = sqlite3_mprintf ("%s_face_seeds", topo_name);
1810 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
1811 sqlite3_free (table);
1812 sqlite3_free (prev);
1813 prev = sql;
1814 table = sqlite3_mprintf ("%s_face_geoms", topo_name);
1815 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)))", prev, table);
1816 sqlite3_free (table);
1817 sqlite3_free (prev);
1818 ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
1819 sqlite3_free (sql);
1820 if (ret != SQLITE_OK)
1821 return 0;
1822 if (rows < 1)
1823 ;
1824 else
1825 {
1826 for (i = 1; i <= rows; i++)
1827 {
1828 value = results[(i * columns) + 0];
1829 if (atoi (value) != 9)
1830 error = 1;
1831 }
1832 }
1833 sqlite3_free_table (results);
1834 if (error)
1835 return 0;
1836
1837 return 1;
1838 }
1839
1840 static int
do_drop_topo_face(sqlite3 * handle,const char * topo_name)1841 do_drop_topo_face (sqlite3 * handle, const char *topo_name)
1842 {
1843 /* attempting to drop the Topology-Face table */
1844 char *sql;
1845 char *table;
1846 char *xtable;
1847 char *err_msg = NULL;
1848 int ret;
1849
1850 /* disabling the corresponding Spatial Index */
1851 table = sqlite3_mprintf ("%s_face", topo_name);
1852 sql = sqlite3_mprintf ("SELECT DisableSpatialIndex(%Q, 'mbr')", table);
1853 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1854 sqlite3_free (table);
1855 sqlite3_free (sql);
1856 if (ret != SQLITE_OK)
1857 {
1858 spatialite_e
1859 ("DisableSpatialIndex topology-face - error: %s\n", err_msg);
1860 sqlite3_free (err_msg);
1861 return 0;
1862 }
1863
1864 /* discarding the Geometry column */
1865 table = sqlite3_mprintf ("%s_face", topo_name);
1866 sql = sqlite3_mprintf ("SELECT DiscardGeometryColumn(%Q, 'mbr')", table);
1867 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1868 sqlite3_free (table);
1869 sqlite3_free (sql);
1870 if (ret != SQLITE_OK)
1871 {
1872 spatialite_e
1873 ("DisableGeometryColumn topology-face - error: %s\n", err_msg);
1874 sqlite3_free (err_msg);
1875 return 0;
1876 }
1877
1878 /* dropping the main table */
1879 table = sqlite3_mprintf ("%s_face", topo_name);
1880 xtable = gaiaDoubleQuotedSql (table);
1881 sqlite3_free (table);
1882 sql = sqlite3_mprintf ("DROP TABLE IF EXISTS \"%s\"", xtable);
1883 free (xtable);
1884 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1885 sqlite3_free (sql);
1886 if (ret != SQLITE_OK)
1887 {
1888 spatialite_e ("DROP topology-face - error: %s\n", err_msg);
1889 sqlite3_free (err_msg);
1890 return 0;
1891 }
1892
1893 /* dropping the corresponding Spatial Index */
1894 table = sqlite3_mprintf ("idx_%s_face_mbr", topo_name);
1895 sql = sqlite3_mprintf ("DROP TABLE IF EXISTS \"%s\"", table);
1896 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1897 sqlite3_free (table);
1898 sqlite3_free (sql);
1899 if (ret != SQLITE_OK)
1900 {
1901 spatialite_e
1902 ("DROP SpatialIndex topology-face - error: %s\n", err_msg);
1903 sqlite3_free (err_msg);
1904 return 0;
1905 }
1906
1907 return 1;
1908 }
1909
1910 static int
do_drop_topo_table(sqlite3 * handle,const char * topo_name,const char * which,int spatial)1911 do_drop_topo_table (sqlite3 * handle, const char *topo_name, const char *which,
1912 int spatial)
1913 {
1914 /* attempting to drop some Topology table */
1915 char *sql;
1916 char *table;
1917 char *xtable;
1918 char *err_msg = NULL;
1919 int ret;
1920
1921 if (strcmp (which, "face") == 0)
1922 return do_drop_topo_face (handle, topo_name);
1923
1924 if (spatial)
1925 {
1926 /* disabling the corresponding Spatial Index */
1927 table = sqlite3_mprintf ("%s_%s", topo_name, which);
1928 sql =
1929 sqlite3_mprintf ("SELECT DisableSpatialIndex(%Q, 'geom')", table);
1930 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1931 sqlite3_free (table);
1932 sqlite3_free (sql);
1933 if (ret != SQLITE_OK)
1934 {
1935 spatialite_e
1936 ("DisableSpatialIndex topology-%s - error: %s\n", which,
1937 err_msg);
1938 sqlite3_free (err_msg);
1939 return 0;
1940 }
1941 /* discarding the Geometry column */
1942 table = sqlite3_mprintf ("%s_%s", topo_name, which);
1943 sql =
1944 sqlite3_mprintf ("SELECT DiscardGeometryColumn(%Q, 'geom')",
1945 table);
1946 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1947 sqlite3_free (table);
1948 sqlite3_free (sql);
1949 if (ret != SQLITE_OK)
1950 {
1951 spatialite_e
1952 ("DisableGeometryColumn topology-%s - error: %s\n", which,
1953 err_msg);
1954 sqlite3_free (err_msg);
1955 return 0;
1956 }
1957 }
1958
1959 /* dropping the main table */
1960 table = sqlite3_mprintf ("%s_%s", topo_name, which);
1961 xtable = gaiaDoubleQuotedSql (table);
1962 sqlite3_free (table);
1963 sql = sqlite3_mprintf ("DROP TABLE IF EXISTS MAIN.\"%s\"", xtable);
1964 free (xtable);
1965 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1966 sqlite3_free (sql);
1967 if (ret != SQLITE_OK)
1968 {
1969 spatialite_e ("DROP topology-%s - error: %s\n", which, err_msg);
1970 sqlite3_free (err_msg);
1971 return 0;
1972 }
1973
1974 if (spatial)
1975 {
1976 /* dropping the corresponding Spatial Index */
1977 table = sqlite3_mprintf ("idx_%s_%s_geom", topo_name, which);
1978 sql = sqlite3_mprintf ("DROP TABLE IF EXISTS MAIN.\"%s\"", table);
1979 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1980 sqlite3_free (table);
1981 sqlite3_free (sql);
1982 if (ret != SQLITE_OK)
1983 {
1984 spatialite_e
1985 ("DROP SpatialIndex topology-%s - error: %s\n", which,
1986 err_msg);
1987 sqlite3_free (err_msg);
1988 return 0;
1989 }
1990 }
1991
1992 return 1;
1993 }
1994
1995 static int
do_drop_topo_view(sqlite3 * handle,const char * topo_name,const char * which)1996 do_drop_topo_view (sqlite3 * handle, const char *topo_name, const char *which)
1997 {
1998 /* attempting to drop some Topology view */
1999 char *sql;
2000 char *table;
2001 char *xtable;
2002 char *err_msg = NULL;
2003 int ret;
2004
2005 /* unregistering the Spatial View */
2006 table = sqlite3_mprintf ("%s_%s", topo_name, which);
2007 sql =
2008 sqlite3_mprintf
2009 ("DELETE FROM views_geometry_columns WHERE view_name = Lower(%Q)",
2010 table);
2011 sqlite3_free (table);
2012 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
2013 sqlite3_free (sql);
2014 if (ret != SQLITE_OK)
2015 {
2016 spatialite_e ("Unregister Spatial View -%s - error: %s\n", which,
2017 err_msg);
2018 sqlite3_free (err_msg);
2019 }
2020
2021 /* dropping the view */
2022 table = sqlite3_mprintf ("%s_%s", topo_name, which);
2023 xtable = gaiaDoubleQuotedSql (table);
2024 sqlite3_free (table);
2025 sql = sqlite3_mprintf ("DROP VIEW IF EXISTS MAIN.\"%s\"", xtable);
2026 free (xtable);
2027 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
2028 sqlite3_free (sql);
2029 if (ret != SQLITE_OK)
2030 {
2031 spatialite_e ("DROP topology-%s - error: %s\n", which, err_msg);
2032 sqlite3_free (err_msg);
2033 return 0;
2034 }
2035
2036 return 1;
2037 }
2038
2039 static int
do_drop_topofeature_tables(sqlite3 * handle,const char * topo_name)2040 do_drop_topofeature_tables (sqlite3 * handle, const char *topo_name)
2041 {
2042 /* dropping any eventual topofeatures table */
2043 char *table;
2044 char *xtable;
2045 char *sql;
2046 char *err_msg = NULL;
2047 int ret;
2048 int i;
2049 char **results;
2050 int rows;
2051 int columns;
2052
2053 table = sqlite3_mprintf ("%s_topolayers", topo_name);
2054 xtable = gaiaDoubleQuotedSql (table);
2055 sqlite3_free (table);
2056 sql = sqlite3_mprintf ("SELECT topolayer_id FROM MAIN.\"%s\"", xtable);
2057 free (xtable);
2058 ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
2059 sqlite3_free (sql);
2060 if (ret != SQLITE_OK)
2061 return 1;
2062 if (rows < 1)
2063 ;
2064 else
2065 {
2066 for (i = 1; i <= rows; i++)
2067 {
2068 const char *id = results[(i * columns) + 0];
2069 table = sqlite3_mprintf ("%s_topofeatures_%s", topo_name, id);
2070 xtable = gaiaDoubleQuotedSql (table);
2071 sqlite3_free (table);
2072 sql =
2073 sqlite3_mprintf ("DROP TABLE IF EXISTS MAIN.\"%s\"",
2074 xtable);
2075 free (xtable);
2076 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
2077 sqlite3_free (sql);
2078 if (ret != SQLITE_OK)
2079 {
2080 spatialite_e ("DROP topology-features (%s) - error: %s\n",
2081 id, err_msg);
2082 sqlite3_free (err_msg);
2083 return 0;
2084 }
2085 }
2086 }
2087 sqlite3_free_table (results);
2088 return 1;
2089 }
2090
2091 static int
do_get_topology(sqlite3 * handle,const char * topo_name,char ** topology_name,int * srid,double * tolerance,int * has_z)2092 do_get_topology (sqlite3 * handle, const char *topo_name, char **topology_name,
2093 int *srid, double *tolerance, int *has_z)
2094 {
2095 /* retrieving a Topology configuration */
2096 char *sql;
2097 int ret;
2098 sqlite3_stmt *stmt = NULL;
2099 int ok = 0;
2100 char *xtopology_name = NULL;
2101 int xsrid;
2102 double xtolerance;
2103 int xhas_z;
2104
2105 /* preparing the SQL query */
2106 sql =
2107 sqlite3_mprintf
2108 ("SELECT topology_name, srid, tolerance, has_z FROM MAIN.topologies WHERE "
2109 "Lower(topology_name) = Lower(%Q)", topo_name);
2110 ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
2111 sqlite3_free (sql);
2112 if (ret != SQLITE_OK)
2113 {
2114 spatialite_e ("SELECT FROM topologys error: \"%s\"\n",
2115 sqlite3_errmsg (handle));
2116 return 0;
2117 }
2118
2119 while (1)
2120 {
2121 /* scrolling the result set rows */
2122 ret = sqlite3_step (stmt);
2123 if (ret == SQLITE_DONE)
2124 break; /* end of result set */
2125 if (ret == SQLITE_ROW)
2126 {
2127 int ok_name = 0;
2128 int ok_srid = 0;
2129 int ok_tolerance = 0;
2130 int ok_z = 0;
2131 if (sqlite3_column_type (stmt, 0) == SQLITE_TEXT)
2132 {
2133 const char *str =
2134 (const char *) sqlite3_column_text (stmt, 0);
2135 if (xtopology_name != NULL)
2136 free (xtopology_name);
2137 xtopology_name = malloc (strlen (str) + 1);
2138 strcpy (xtopology_name, str);
2139 ok_name = 1;
2140 }
2141 if (sqlite3_column_type (stmt, 1) == SQLITE_INTEGER)
2142 {
2143 xsrid = sqlite3_column_int (stmt, 1);
2144 ok_srid = 1;
2145 }
2146 if (sqlite3_column_type (stmt, 2) == SQLITE_FLOAT)
2147 {
2148 xtolerance = sqlite3_column_double (stmt, 2);
2149 ok_tolerance = 1;
2150 }
2151 if (sqlite3_column_type (stmt, 3) == SQLITE_INTEGER)
2152 {
2153 xhas_z = sqlite3_column_int (stmt, 3);
2154 ok_z = 1;
2155 }
2156 if (ok_name && ok_srid && ok_tolerance && ok_z)
2157 {
2158 ok = 1;
2159 break;
2160 }
2161 }
2162 else
2163 {
2164 spatialite_e
2165 ("step: SELECT FROM topologies error: \"%s\"\n",
2166 sqlite3_errmsg (handle));
2167 sqlite3_finalize (stmt);
2168 return 0;
2169 }
2170 }
2171 sqlite3_finalize (stmt);
2172
2173 if (ok)
2174 {
2175 *topology_name = xtopology_name;
2176 *srid = xsrid;
2177 *tolerance = xtolerance;
2178 *has_z = xhas_z;
2179 return 1;
2180 }
2181
2182 if (xtopology_name != NULL)
2183 free (xtopology_name);
2184 return 0;
2185 }
2186
2187 GAIATOPO_DECLARE GaiaTopologyAccessorPtr
gaiaGetTopology(sqlite3 * handle,const void * cache,const char * topo_name)2188 gaiaGetTopology (sqlite3 * handle, const void *cache, const char *topo_name)
2189 {
2190 /* attempting to get a reference to some Topology Accessor Object */
2191 GaiaTopologyAccessorPtr accessor;
2192
2193 /* attempting to retrieve an alredy cached definition */
2194 accessor = gaiaTopologyFromCache (cache, topo_name);
2195 if (accessor != NULL)
2196 return accessor;
2197
2198 /* attempting to create a new Topology Accessor */
2199 accessor = gaiaTopologyFromDBMS (handle, cache, topo_name);
2200 return accessor;
2201 }
2202
2203 GAIATOPO_DECLARE GaiaTopologyAccessorPtr
gaiaTopologyFromCache(const void * p_cache,const char * topo_name)2204 gaiaTopologyFromCache (const void *p_cache, const char *topo_name)
2205 {
2206 /* attempting to retrieve an already defined Topology Accessor Object from the Connection Cache */
2207 struct gaia_topology *ptr;
2208 struct splite_internal_cache *cache =
2209 (struct splite_internal_cache *) p_cache;
2210 if (cache == NULL)
2211 return NULL;
2212
2213 ptr = (struct gaia_topology *) (cache->firstTopology);
2214 while (ptr != NULL)
2215 {
2216 /* checking for an already registered Topology */
2217 if (strcasecmp (topo_name, ptr->topology_name) == 0)
2218 return (GaiaTopologyAccessorPtr) ptr;
2219 ptr = ptr->next;
2220 }
2221 return NULL;
2222 }
2223
2224 GAIATOPO_DECLARE int
gaiaReadTopologyFromDBMS(sqlite3 * handle,const char * topo_name,char ** topology_name,int * srid,double * tolerance,int * has_z)2225 gaiaReadTopologyFromDBMS (sqlite3 *
2226 handle,
2227 const char
2228 *topo_name, char **topology_name, int *srid,
2229 double *tolerance, int *has_z)
2230 {
2231 /* testing for existing DBMS objects */
2232 if (!check_existing_topology (handle, topo_name, 1))
2233 return 0;
2234
2235 /* retrieving the Topology configuration */
2236 if (!do_get_topology
2237 (handle, topo_name, topology_name, srid, tolerance, has_z))
2238 return 0;
2239 return 1;
2240 }
2241
2242 GAIATOPO_DECLARE GaiaTopologyAccessorPtr
gaiaTopologyFromDBMS(sqlite3 * handle,const void * p_cache,const char * topo_name)2243 gaiaTopologyFromDBMS (sqlite3 * handle, const void *p_cache,
2244 const char *topo_name)
2245 {
2246 /* attempting to create a Topology Accessor Object into the Connection Cache */
2247 const RTCTX *ctx = NULL;
2248 RTT_BE_CALLBACKS *callbacks;
2249 struct gaia_topology *ptr;
2250 struct splite_internal_cache *cache =
2251 (struct splite_internal_cache *) p_cache;
2252 if (cache == NULL)
2253 return NULL;
2254 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2255 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2256 return NULL;
2257 ctx = cache->RTTOPO_handle;
2258 if (ctx == NULL)
2259 return NULL;
2260
2261 /* allocating and initializing the opaque object */
2262 ptr = malloc (sizeof (struct gaia_topology));
2263 ptr->db_handle = handle;
2264 ptr->cache = cache;
2265 ptr->topology_name = NULL;
2266 ptr->srid = -1;
2267 ptr->tolerance = 0;
2268 ptr->has_z = 0;
2269 ptr->last_error_message = NULL;
2270 ptr->rtt_iface = rtt_CreateBackendIface (ctx, (const RTT_BE_DATA *) ptr);
2271 ptr->prev = cache->lastTopology;
2272 ptr->next = NULL;
2273
2274 callbacks = malloc (sizeof (RTT_BE_CALLBACKS));
2275 callbacks->lastErrorMessage = callback_lastErrorMessage;
2276 callbacks->topoGetSRID = callback_topoGetSRID;
2277 callbacks->topoGetPrecision = callback_topoGetPrecision;
2278 callbacks->topoHasZ = callback_topoHasZ;
2279 callbacks->createTopology = NULL;
2280 callbacks->loadTopologyByName = callback_loadTopologyByName;
2281 callbacks->freeTopology = callback_freeTopology;
2282 callbacks->getNodeById = callback_getNodeById;
2283 callbacks->getNodeWithinDistance2D = callback_getNodeWithinDistance2D;
2284 callbacks->insertNodes = callback_insertNodes;
2285 callbacks->getEdgeById = callback_getEdgeById;
2286 callbacks->getEdgeWithinDistance2D = callback_getEdgeWithinDistance2D;
2287 callbacks->getNextEdgeId = callback_getNextEdgeId;
2288 callbacks->insertEdges = callback_insertEdges;
2289 callbacks->updateEdges = callback_updateEdges;
2290 callbacks->getFaceById = callback_getFaceById;
2291 callbacks->getFaceContainingPoint = callback_getFaceContainingPoint;
2292 callbacks->deleteEdges = callback_deleteEdges;
2293 callbacks->getNodeWithinBox2D = callback_getNodeWithinBox2D;
2294 callbacks->getEdgeWithinBox2D = callback_getEdgeWithinBox2D;
2295 callbacks->getEdgeByNode = callback_getEdgeByNode;
2296 callbacks->updateNodes = callback_updateNodes;
2297 callbacks->insertFaces = callback_insertFaces;
2298 callbacks->updateFacesById = callback_updateFacesById;
2299 callbacks->deleteFacesById = callback_deleteFacesById;
2300 callbacks->getRingEdges = callback_getRingEdges;
2301 callbacks->updateEdgesById = callback_updateEdgesById;
2302 callbacks->getEdgeByFace = callback_getEdgeByFace;
2303 callbacks->getNodeByFace = callback_getNodeByFace;
2304 callbacks->updateNodesById = callback_updateNodesById;
2305 callbacks->deleteNodesById = callback_deleteNodesById;
2306 callbacks->updateTopoGeomEdgeSplit = callback_updateTopoGeomEdgeSplit;
2307 callbacks->updateTopoGeomFaceSplit = callback_updateTopoGeomFaceSplit;
2308 callbacks->checkTopoGeomRemEdge = callback_checkTopoGeomRemEdge;
2309 callbacks->updateTopoGeomFaceHeal = callback_updateTopoGeomFaceHeal;
2310 callbacks->checkTopoGeomRemNode = callback_checkTopoGeomRemNode;
2311 callbacks->updateTopoGeomEdgeHeal = callback_updateTopoGeomEdgeHeal;
2312 callbacks->getFaceWithinBox2D = callback_getFaceWithinBox2D;
2313 ptr->callbacks = callbacks;
2314
2315 rtt_BackendIfaceRegisterCallbacks (ptr->rtt_iface, callbacks);
2316 ptr->rtt_topology = rtt_LoadTopology (ptr->rtt_iface, topo_name);
2317
2318 ptr->stmt_getNodeWithinDistance2D = NULL;
2319 ptr->stmt_insertNodes = NULL;
2320 ptr->stmt_getEdgeWithinDistance2D = NULL;
2321 ptr->stmt_getNextEdgeId = NULL;
2322 ptr->stmt_setNextEdgeId = NULL;
2323 ptr->stmt_insertEdges = NULL;
2324 ptr->stmt_getFaceContainingPoint_1 = NULL;
2325 ptr->stmt_getFaceContainingPoint_2 = NULL;
2326 ptr->stmt_deleteEdges = NULL;
2327 ptr->stmt_getNodeWithinBox2D = NULL;
2328 ptr->stmt_getEdgeWithinBox2D = NULL;
2329 ptr->stmt_getFaceWithinBox2D = NULL;
2330 ptr->stmt_getAllEdges = NULL;
2331 ptr->stmt_updateNodes = NULL;
2332 ptr->stmt_insertFaces = NULL;
2333 ptr->stmt_updateFacesById = NULL;
2334 ptr->stmt_deleteFacesById = NULL;
2335 ptr->stmt_deleteNodesById = NULL;
2336 ptr->stmt_getRingEdges = NULL;
2337 if (ptr->rtt_topology == NULL)
2338 {
2339 char *msg =
2340 sqlite3_mprintf ("Topology \"%s\" is undefined !!!", topo_name);
2341 gaiaSetRtTopoErrorMsg (p_cache, msg);
2342 sqlite3_free (msg);
2343 goto invalid;
2344 }
2345
2346 /* creating the SQL prepared statements */
2347 create_topogeo_prepared_stmts ((GaiaTopologyAccessorPtr) ptr);
2348
2349 return (GaiaTopologyAccessorPtr) ptr;
2350
2351 invalid:
2352 gaiaTopologyDestroy ((GaiaTopologyAccessorPtr) ptr);
2353 return NULL;
2354 }
2355
2356 GAIATOPO_DECLARE void
gaiaTopologyDestroy(GaiaTopologyAccessorPtr topo_ptr)2357 gaiaTopologyDestroy (GaiaTopologyAccessorPtr topo_ptr)
2358 {
2359 /* destroying a Topology Accessor Object */
2360 struct gaia_topology *prev;
2361 struct gaia_topology *next;
2362 struct splite_internal_cache *cache;
2363 struct gaia_topology *ptr = (struct gaia_topology *) topo_ptr;
2364 if (ptr == NULL)
2365 return;
2366
2367 prev = ptr->prev;
2368 next = ptr->next;
2369 cache = (struct splite_internal_cache *) (ptr->cache);
2370 if (ptr->rtt_topology != NULL)
2371 rtt_FreeTopology ((RTT_TOPOLOGY *) (ptr->rtt_topology));
2372 if (ptr->rtt_iface != NULL)
2373 rtt_FreeBackendIface ((RTT_BE_IFACE *) (ptr->rtt_iface));
2374 if (ptr->callbacks != NULL)
2375 free (ptr->callbacks);
2376 if (ptr->topology_name != NULL)
2377 free (ptr->topology_name);
2378 if (ptr->last_error_message != NULL)
2379 free (ptr->last_error_message);
2380
2381 finalize_topogeo_prepared_stmts (topo_ptr);
2382 free (ptr);
2383
2384 /* unregistering from the Internal Cache double linked list */
2385 if (prev != NULL)
2386 prev->next = next;
2387 if (next != NULL)
2388 next->prev = prev;
2389 if (cache->firstTopology == ptr)
2390 cache->firstTopology = next;
2391 if (cache->lastTopology == ptr)
2392 cache->lastTopology = prev;
2393 }
2394
2395 TOPOLOGY_PRIVATE void
finalize_topogeo_prepared_stmts(GaiaTopologyAccessorPtr accessor)2396 finalize_topogeo_prepared_stmts (GaiaTopologyAccessorPtr accessor)
2397 {
2398 /* finalizing the SQL prepared statements */
2399 struct gaia_topology *ptr = (struct gaia_topology *) accessor;
2400 if (ptr->stmt_getNodeWithinDistance2D != NULL)
2401 sqlite3_finalize (ptr->stmt_getNodeWithinDistance2D);
2402 if (ptr->stmt_insertNodes != NULL)
2403 sqlite3_finalize (ptr->stmt_insertNodes);
2404 if (ptr->stmt_getEdgeWithinDistance2D != NULL)
2405 sqlite3_finalize (ptr->stmt_getEdgeWithinDistance2D);
2406 if (ptr->stmt_getNextEdgeId != NULL)
2407 sqlite3_finalize (ptr->stmt_getNextEdgeId);
2408 if (ptr->stmt_setNextEdgeId != NULL)
2409 sqlite3_finalize (ptr->stmt_setNextEdgeId);
2410 if (ptr->stmt_insertEdges != NULL)
2411 sqlite3_finalize (ptr->stmt_insertEdges);
2412 if (ptr->stmt_getFaceContainingPoint_1 != NULL)
2413 sqlite3_finalize (ptr->stmt_getFaceContainingPoint_1);
2414 if (ptr->stmt_getFaceContainingPoint_2 != NULL)
2415 sqlite3_finalize (ptr->stmt_getFaceContainingPoint_2);
2416 if (ptr->stmt_deleteEdges != NULL)
2417 sqlite3_finalize (ptr->stmt_deleteEdges);
2418 if (ptr->stmt_getNodeWithinBox2D != NULL)
2419 sqlite3_finalize (ptr->stmt_getNodeWithinBox2D);
2420 if (ptr->stmt_getEdgeWithinBox2D != NULL)
2421 sqlite3_finalize (ptr->stmt_getEdgeWithinBox2D);
2422 if (ptr->stmt_getFaceWithinBox2D != NULL)
2423 sqlite3_finalize (ptr->stmt_getFaceWithinBox2D);
2424 if (ptr->stmt_getAllEdges != NULL)
2425 sqlite3_finalize (ptr->stmt_getAllEdges);
2426 if (ptr->stmt_updateNodes != NULL)
2427 sqlite3_finalize (ptr->stmt_updateNodes);
2428 if (ptr->stmt_insertFaces != NULL)
2429 sqlite3_finalize (ptr->stmt_insertFaces);
2430 if (ptr->stmt_updateFacesById != NULL)
2431 sqlite3_finalize (ptr->stmt_updateFacesById);
2432 if (ptr->stmt_deleteFacesById != NULL)
2433 sqlite3_finalize (ptr->stmt_deleteFacesById);
2434 if (ptr->stmt_deleteNodesById != NULL)
2435 sqlite3_finalize (ptr->stmt_deleteNodesById);
2436 if (ptr->stmt_getRingEdges != NULL)
2437 sqlite3_finalize (ptr->stmt_getRingEdges);
2438 ptr->stmt_getNodeWithinDistance2D = NULL;
2439 ptr->stmt_insertNodes = NULL;
2440 ptr->stmt_getEdgeWithinDistance2D = NULL;
2441 ptr->stmt_getNextEdgeId = NULL;
2442 ptr->stmt_setNextEdgeId = NULL;
2443 ptr->stmt_insertEdges = NULL;
2444 ptr->stmt_getFaceContainingPoint_1 = NULL;
2445 ptr->stmt_getFaceContainingPoint_2 = NULL;
2446 ptr->stmt_deleteEdges = NULL;
2447 ptr->stmt_getNodeWithinBox2D = NULL;
2448 ptr->stmt_getEdgeWithinBox2D = NULL;
2449 ptr->stmt_getFaceWithinBox2D = NULL;
2450 ptr->stmt_getAllEdges = NULL;
2451 ptr->stmt_updateNodes = NULL;
2452 ptr->stmt_insertFaces = NULL;
2453 ptr->stmt_updateFacesById = NULL;
2454 ptr->stmt_deleteFacesById = NULL;
2455 ptr->stmt_deleteNodesById = NULL;
2456 ptr->stmt_getRingEdges = NULL;
2457 }
2458
2459 TOPOLOGY_PRIVATE void
create_topogeo_prepared_stmts(GaiaTopologyAccessorPtr accessor)2460 create_topogeo_prepared_stmts (GaiaTopologyAccessorPtr accessor)
2461 {
2462 /* creating the SQL prepared statements */
2463 struct gaia_topology *ptr = (struct gaia_topology *) accessor;
2464 finalize_topogeo_prepared_stmts (accessor);
2465 ptr->stmt_getNodeWithinDistance2D =
2466 do_create_stmt_getNodeWithinDistance2D (accessor);
2467 ptr->stmt_insertNodes = do_create_stmt_insertNodes (accessor);
2468 ptr->stmt_getEdgeWithinDistance2D =
2469 do_create_stmt_getEdgeWithinDistance2D (accessor);
2470 ptr->stmt_getNextEdgeId = do_create_stmt_getNextEdgeId (accessor);
2471 ptr->stmt_setNextEdgeId = do_create_stmt_setNextEdgeId (accessor);
2472 ptr->stmt_insertEdges = do_create_stmt_insertEdges (accessor);
2473 ptr->stmt_getFaceContainingPoint_1 =
2474 do_create_stmt_getFaceContainingPoint_1 (accessor);
2475 ptr->stmt_getFaceContainingPoint_2 =
2476 do_create_stmt_getFaceContainingPoint_2 (accessor);
2477 ptr->stmt_deleteEdges = NULL;
2478 ptr->stmt_getNodeWithinBox2D = do_create_stmt_getNodeWithinBox2D (accessor);
2479 ptr->stmt_getEdgeWithinBox2D = do_create_stmt_getEdgeWithinBox2D (accessor);
2480 ptr->stmt_getFaceWithinBox2D = do_create_stmt_getFaceWithinBox2D (accessor);
2481 ptr->stmt_getAllEdges = do_create_stmt_getAllEdges (accessor);
2482 ptr->stmt_updateNodes = NULL;
2483 ptr->stmt_insertFaces = do_create_stmt_insertFaces (accessor);
2484 ptr->stmt_updateFacesById = do_create_stmt_updateFacesById (accessor);
2485 ptr->stmt_deleteFacesById = do_create_stmt_deleteFacesById (accessor);
2486 ptr->stmt_deleteNodesById = do_create_stmt_deleteNodesById (accessor);
2487 ptr->stmt_getRingEdges = do_create_stmt_getRingEdges (accessor);
2488 }
2489
2490 TOPOLOGY_PRIVATE void
finalize_all_topo_prepared_stmts(const void * p_cache)2491 finalize_all_topo_prepared_stmts (const void *p_cache)
2492 {
2493 /* finalizing all Topology-related prepared Stms */
2494 struct gaia_topology *p_topo;
2495 struct gaia_network *p_network;
2496 struct splite_internal_cache *cache =
2497 (struct splite_internal_cache *) p_cache;
2498 if (cache == NULL)
2499 return;
2500 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2501 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2502 return;
2503
2504 p_topo = (struct gaia_topology *) cache->firstTopology;
2505 while (p_topo != NULL)
2506 {
2507 finalize_topogeo_prepared_stmts ((GaiaTopologyAccessorPtr) p_topo);
2508 p_topo = p_topo->next;
2509 }
2510
2511 p_network = (struct gaia_network *) cache->firstNetwork;
2512 while (p_network != NULL)
2513 {
2514 finalize_toponet_prepared_stmts ((GaiaNetworkAccessorPtr) p_network);
2515 p_network = p_network->next;
2516 }
2517 }
2518
2519 TOPOLOGY_PRIVATE void
create_all_topo_prepared_stmts(const void * p_cache)2520 create_all_topo_prepared_stmts (const void *p_cache)
2521 {
2522 /* (re)creating all Topology-related prepared Stms */
2523 struct gaia_topology *p_topo;
2524 struct gaia_network *p_network;
2525 struct splite_internal_cache *cache =
2526 (struct splite_internal_cache *) p_cache;
2527 if (cache == NULL)
2528 return;
2529 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2530 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2531 return;
2532
2533 p_topo = (struct gaia_topology *) cache->firstTopology;
2534 while (p_topo != NULL)
2535 {
2536 create_topogeo_prepared_stmts ((GaiaTopologyAccessorPtr) p_topo);
2537 p_topo = p_topo->next;
2538 }
2539
2540 p_network = (struct gaia_network *) cache->firstNetwork;
2541 while (p_network != NULL)
2542 {
2543 create_toponet_prepared_stmts ((GaiaNetworkAccessorPtr) p_network);
2544 p_network = p_network->next;
2545 }
2546 }
2547
2548 TOPOLOGY_PRIVATE void
gaiatopo_reset_last_error_msg(GaiaTopologyAccessorPtr accessor)2549 gaiatopo_reset_last_error_msg (GaiaTopologyAccessorPtr accessor)
2550 {
2551 /* resets the last Topology error message */
2552 struct gaia_topology *topo = (struct gaia_topology *) accessor;
2553 if (topo == NULL)
2554 return;
2555
2556 if (topo->cache != NULL)
2557 gaiaResetRtTopoMsg (topo->cache);
2558 if (topo->last_error_message != NULL)
2559 free (topo->last_error_message);
2560 topo->last_error_message = NULL;
2561 }
2562
2563 TOPOLOGY_PRIVATE void
gaiatopo_set_last_error_msg(GaiaTopologyAccessorPtr accessor,const char * msg)2564 gaiatopo_set_last_error_msg (GaiaTopologyAccessorPtr accessor, const char *msg)
2565 {
2566 /* sets the last Topology error message */
2567 int len;
2568 struct gaia_topology *topo = (struct gaia_topology *) accessor;
2569 if (msg == NULL)
2570 msg = "no message available";
2571
2572 spatialite_e ("%s\n", msg);
2573 if (topo == NULL)
2574 return;
2575
2576 if (topo->last_error_message != NULL)
2577 return;
2578
2579 len = strlen (msg);
2580 topo->last_error_message = malloc (len + 1);
2581 strcpy (topo->last_error_message, msg);
2582 }
2583
2584 TOPOLOGY_PRIVATE const char *
gaiatopo_get_last_exception(GaiaTopologyAccessorPtr accessor)2585 gaiatopo_get_last_exception (GaiaTopologyAccessorPtr accessor)
2586 {
2587 /* returns the last Topology error message */
2588 struct gaia_topology *topo = (struct gaia_topology *) accessor;
2589 if (topo == NULL)
2590 return NULL;
2591
2592 return topo->last_error_message;
2593 }
2594
2595 GAIATOPO_DECLARE int
gaiaTopologyDrop(sqlite3 * handle,const char * topo_name)2596 gaiaTopologyDrop (sqlite3 * handle, const char *topo_name)
2597 {
2598 /* attempting to drop an already existing Topology */
2599 int ret;
2600 char *sql;
2601
2602 /* creating the Topologies table (just in case) */
2603 if (!do_create_topologies (handle))
2604 return 0;
2605
2606 /* testing for existing DBMS objects */
2607 if (!check_existing_topology (handle, topo_name, 0))
2608 return 0;
2609
2610 /* dropping all topofeature tables (if any) */
2611 if (!do_drop_topofeature_tables (handle, topo_name))
2612 goto error;
2613
2614 /* dropping the Topology own Tables */
2615 if (!do_drop_topo_view (handle, topo_name, "edge_seeds"))
2616 goto error;
2617 if (!do_drop_topo_view (handle, topo_name, "face_seeds"))
2618 goto error;
2619 if (!do_drop_topo_view (handle, topo_name, "face_geoms"))
2620 goto error;
2621 if (!do_drop_topo_table (handle, topo_name, "topofeatures", 0))
2622 goto error;
2623 if (!do_drop_topo_table (handle, topo_name, "topolayers", 0))
2624 goto error;
2625 if (!do_drop_topo_table (handle, topo_name, "seeds", 1))
2626 goto error;
2627 if (!do_drop_topo_table (handle, topo_name, "edge", 1))
2628 goto error;
2629 if (!do_drop_topo_table (handle, topo_name, "node", 1))
2630 goto error;
2631 if (!do_drop_topo_table (handle, topo_name, "face", 1))
2632 goto error;
2633
2634 /* unregistering the Topology */
2635 sql =
2636 sqlite3_mprintf
2637 ("DELETE FROM MAIN.topologies WHERE Lower(topology_name) = Lower(%Q)",
2638 topo_name);
2639 ret = sqlite3_exec (handle, sql, NULL, NULL, NULL);
2640 sqlite3_free (sql);
2641 if (ret != SQLITE_OK)
2642 goto error;
2643
2644 return 1;
2645
2646 error:
2647 return 0;
2648 }
2649
2650 GAIATOPO_DECLARE sqlite3_int64
gaiaAddIsoNode(GaiaTopologyAccessorPtr accessor,sqlite3_int64 face,gaiaPointPtr pt,int skip_checks)2651 gaiaAddIsoNode (GaiaTopologyAccessorPtr accessor,
2652 sqlite3_int64 face, gaiaPointPtr pt, int skip_checks)
2653 {
2654 /* RTT wrapper - AddIsoNode */
2655 const RTCTX *ctx = NULL;
2656 struct splite_internal_cache *cache = NULL;
2657 sqlite3_int64 ret;
2658 int has_z = 0;
2659 RTPOINT *rt_pt;
2660 RTPOINTARRAY *pa;
2661 RTPOINT4D point;
2662 struct gaia_topology *topo = (struct gaia_topology *) accessor;
2663 if (topo == NULL)
2664 return 0;
2665
2666 cache = (struct splite_internal_cache *) topo->cache;
2667 if (cache == NULL)
2668 return 0;
2669 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2670 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2671 return 0;
2672 ctx = cache->RTTOPO_handle;
2673 if (ctx == NULL)
2674 return 0;
2675
2676 if (pt->DimensionModel == GAIA_XY_Z || pt->DimensionModel == GAIA_XY_Z_M)
2677 has_z = 1;
2678 pa = ptarray_construct (ctx, has_z, 0, 1);
2679 point.x = pt->X;
2680 point.y = pt->Y;
2681 if (has_z)
2682 point.z = pt->Z;
2683 ptarray_set_point4d (ctx, pa, 0, &point);
2684 rt_pt = rtpoint_construct (ctx, topo->srid, NULL, pa);
2685
2686 gaiaResetRtTopoMsg (cache);
2687 ret =
2688 rtt_AddIsoNode ((RTT_TOPOLOGY *) (topo->rtt_topology), face, rt_pt,
2689 skip_checks);
2690
2691 rtpoint_free (ctx, rt_pt);
2692 return ret;
2693 }
2694
2695 GAIATOPO_DECLARE int
gaiaMoveIsoNode(GaiaTopologyAccessorPtr accessor,sqlite3_int64 node,gaiaPointPtr pt)2696 gaiaMoveIsoNode (GaiaTopologyAccessorPtr accessor,
2697 sqlite3_int64 node, gaiaPointPtr pt)
2698 {
2699 /* RTT wrapper - MoveIsoNode */
2700 const RTCTX *ctx = NULL;
2701 struct splite_internal_cache *cache = NULL;
2702 int ret;
2703 int has_z = 0;
2704 RTPOINT *rt_pt;
2705 RTPOINTARRAY *pa;
2706 RTPOINT4D point;
2707 struct gaia_topology *topo = (struct gaia_topology *) accessor;
2708 if (topo == NULL)
2709 return 0;
2710
2711 cache = (struct splite_internal_cache *) topo->cache;
2712 if (cache == NULL)
2713 return 0;
2714 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2715 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2716 return 0;
2717 ctx = cache->RTTOPO_handle;
2718 if (ctx == NULL)
2719 return 0;
2720
2721 if (pt->DimensionModel == GAIA_XY_Z || pt->DimensionModel == GAIA_XY_Z_M)
2722 has_z = 1;
2723 pa = ptarray_construct (ctx, has_z, 0, 1);
2724 point.x = pt->X;
2725 point.y = pt->Y;
2726 if (has_z)
2727 point.z = pt->Z;
2728 ptarray_set_point4d (ctx, pa, 0, &point);
2729 rt_pt = rtpoint_construct (ctx, topo->srid, NULL, pa);
2730
2731 gaiaResetRtTopoMsg (cache);
2732 ret = rtt_MoveIsoNode ((RTT_TOPOLOGY *) (topo->rtt_topology), node, rt_pt);
2733
2734 rtpoint_free (ctx, rt_pt);
2735 if (ret == 0)
2736 return 1;
2737 return 0;
2738 }
2739
2740 GAIATOPO_DECLARE int
gaiaRemIsoNode(GaiaTopologyAccessorPtr accessor,sqlite3_int64 node)2741 gaiaRemIsoNode (GaiaTopologyAccessorPtr accessor, sqlite3_int64 node)
2742 {
2743 /* RTT wrapper - RemIsoNode */
2744 struct splite_internal_cache *cache = NULL;
2745 int ret;
2746 struct gaia_topology *topo = (struct gaia_topology *) accessor;
2747 if (topo == NULL)
2748 return 0;
2749
2750 cache = (struct splite_internal_cache *) topo->cache;
2751 if (cache == NULL)
2752 return 0;
2753 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2754 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2755 return 0;
2756
2757 gaiaResetRtTopoMsg (cache);
2758 ret = rtt_RemoveIsoNode ((RTT_TOPOLOGY *) (topo->rtt_topology), node);
2759
2760 if (ret == 0)
2761 return 1;
2762 return 0;
2763 }
2764
2765 GAIATOPO_DECLARE sqlite3_int64
gaiaAddIsoEdge(GaiaTopologyAccessorPtr accessor,sqlite3_int64 start_node,sqlite3_int64 end_node,gaiaLinestringPtr ln)2766 gaiaAddIsoEdge (GaiaTopologyAccessorPtr accessor,
2767 sqlite3_int64 start_node, sqlite3_int64 end_node,
2768 gaiaLinestringPtr ln)
2769 {
2770 /* RTT wrapper - AddIsoEdge */
2771 const RTCTX *ctx = NULL;
2772 struct splite_internal_cache *cache = NULL;
2773 sqlite3_int64 ret;
2774 RTLINE *rt_line;
2775 struct gaia_topology *topo = (struct gaia_topology *) accessor;
2776 if (topo == NULL)
2777 return 0;
2778
2779 cache = (struct splite_internal_cache *) topo->cache;
2780 if (cache == NULL)
2781 return 0;
2782 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2783 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2784 return 0;
2785 ctx = cache->RTTOPO_handle;
2786 if (ctx == NULL)
2787 return 0;
2788
2789 rt_line =
2790 gaia_convert_linestring_to_rtline (ctx, ln, topo->srid, topo->has_z);
2791
2792 gaiaResetRtTopoMsg (cache);
2793 ret =
2794 rtt_AddIsoEdge ((RTT_TOPOLOGY *) (topo->rtt_topology), start_node,
2795 end_node, rt_line);
2796
2797 rtline_free (ctx, rt_line);
2798 return ret;
2799 }
2800
2801 GAIATOPO_DECLARE int
gaiaRemIsoEdge(GaiaTopologyAccessorPtr accessor,sqlite3_int64 edge)2802 gaiaRemIsoEdge (GaiaTopologyAccessorPtr accessor, sqlite3_int64 edge)
2803 {
2804 /* RTT wrapper - RemIsoEdge */
2805 struct splite_internal_cache *cache = NULL;
2806 int ret;
2807 struct gaia_topology *topo = (struct gaia_topology *) accessor;
2808 if (topo == NULL)
2809 return 0;
2810
2811 cache = (struct splite_internal_cache *) topo->cache;
2812 if (cache == NULL)
2813 return 0;
2814 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2815 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2816 return 0;
2817
2818 gaiaResetRtTopoMsg (cache);
2819 ret = rtt_RemIsoEdge ((RTT_TOPOLOGY *) (topo->rtt_topology), edge);
2820
2821 if (ret == 0)
2822 return 1;
2823 return 0;
2824 }
2825
2826 GAIATOPO_DECLARE int
gaiaChangeEdgeGeom(GaiaTopologyAccessorPtr accessor,sqlite3_int64 edge_id,gaiaLinestringPtr ln)2827 gaiaChangeEdgeGeom (GaiaTopologyAccessorPtr accessor,
2828 sqlite3_int64 edge_id, gaiaLinestringPtr ln)
2829 {
2830 /* RTT wrapper - ChangeEdgeGeom */
2831 const RTCTX *ctx = NULL;
2832 struct splite_internal_cache *cache = NULL;
2833 int ret;
2834 RTLINE *rt_line;
2835 struct gaia_topology *topo = (struct gaia_topology *) accessor;
2836 if (topo == NULL)
2837 return 0;
2838
2839 cache = (struct splite_internal_cache *) topo->cache;
2840 if (cache == NULL)
2841 return 0;
2842 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2843 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2844 return 0;
2845 ctx = cache->RTTOPO_handle;
2846 if (ctx == NULL)
2847 return 0;
2848
2849 rt_line =
2850 gaia_convert_linestring_to_rtline (ctx, ln, topo->srid, topo->has_z);
2851
2852 gaiaResetRtTopoMsg (cache);
2853 ret =
2854 rtt_ChangeEdgeGeom ((RTT_TOPOLOGY *) (topo->rtt_topology), edge_id,
2855 rt_line);
2856
2857 rtline_free (ctx, rt_line);
2858 if (ret == 0)
2859 return 1;
2860 return 0;
2861 }
2862
2863 static void
do_check_mod_split_edge3d(struct gaia_topology * topo,gaiaPointPtr pt,sqlite3_int64 old_edge)2864 do_check_mod_split_edge3d (struct gaia_topology *topo, gaiaPointPtr pt,
2865 sqlite3_int64 old_edge)
2866 {
2867 /*
2868 / defensive programming: carefully ensuring that lwgeom could
2869 / never shift Edges' start/end points after computing ModSplit
2870 / 3D topology
2871 */
2872 sqlite3_stmt *stmt = NULL;
2873 int ret;
2874 char *sql;
2875 char *table;
2876 char *xtable;
2877 double x1s;
2878 double y1s;
2879 double z1s;
2880 double x1e;
2881 double y1e;
2882 double z1e;
2883 double x2s;
2884 double y2s;
2885 double z2s;
2886 double x2e;
2887 double y2e;
2888 double z2e;
2889 sqlite3_int64 new_edge = sqlite3_last_insert_rowid (topo->db_handle);
2890 table = sqlite3_mprintf ("%s_edge", topo->topology_name);
2891 xtable = gaiaDoubleQuotedSql (table);
2892 sql =
2893 sqlite3_mprintf
2894 ("SELECT ST_X(ST_StartPoint(geom)), ST_Y(ST_StartPoint(geom)), "
2895 "ST_Z(ST_StartPoint(geom)), ST_X(ST_EndPoint(geom)), ST_Y(ST_EndPoint(geom)), "
2896 "ST_Z(ST_EndPoint(geom)) FROM \"%s\" WHERE edge_id = ?", xtable);
2897 free (xtable);
2898 sqlite3_free (table);
2899 ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
2900 sqlite3_free (sql);
2901 if (ret != SQLITE_OK)
2902 return;
2903
2904 sqlite3_reset (stmt);
2905 sqlite3_clear_bindings (stmt);
2906 sqlite3_bind_int64 (stmt, 1, old_edge);
2907 while (1)
2908 {
2909 /* scrolling the result set rows */
2910 ret = sqlite3_step (stmt);
2911 if (ret == SQLITE_DONE)
2912 break; /* end of result set */
2913 if (ret == SQLITE_ROW)
2914 {
2915 x1s = sqlite3_column_double (stmt, 0);
2916 y1s = sqlite3_column_double (stmt, 1);
2917 z1s = sqlite3_column_double (stmt, 2);
2918 x1e = sqlite3_column_double (stmt, 3);
2919 y1e = sqlite3_column_double (stmt, 4);
2920 z1e = sqlite3_column_double (stmt, 5);
2921 }
2922 else
2923 goto error;
2924 }
2925
2926 sqlite3_reset (stmt);
2927 sqlite3_clear_bindings (stmt);
2928 sqlite3_bind_int64 (stmt, 1, new_edge);
2929 while (1)
2930 {
2931 /* scrolling the result set rows */
2932 ret = sqlite3_step (stmt);
2933 if (ret == SQLITE_DONE)
2934 break; /* end of result set */
2935 if (ret == SQLITE_ROW)
2936 {
2937 x2s = sqlite3_column_double (stmt, 0);
2938 y2s = sqlite3_column_double (stmt, 1);
2939 z2s = sqlite3_column_double (stmt, 2);
2940 x2e = sqlite3_column_double (stmt, 3);
2941 y2e = sqlite3_column_double (stmt, 4);
2942 z2e = sqlite3_column_double (stmt, 5);
2943 }
2944 else
2945 goto error;
2946 }
2947 if (x1s == x2e && y1s == y2e && z1s == z2e)
2948 {
2949 /* just silencing stupid compiler warnings */
2950 ;
2951 }
2952 if (x1e == x2s && y1e == y2s && z1e == z2s)
2953 {
2954 if (x1e != pt->X || y1e != pt->Y || z1e != pt->Z)
2955 goto fixme;
2956 }
2957 error:
2958 sqlite3_finalize (stmt);
2959 return;
2960
2961 fixme:
2962 sqlite3_finalize (stmt);
2963 table = sqlite3_mprintf ("%s_edge", topo->topology_name);
2964 xtable = gaiaDoubleQuotedSql (table);
2965 sql =
2966 sqlite3_mprintf
2967 ("UPDATE \"%s\" SET geom = ST_SetEndPoint(geom, MakePointZ(?, ?, ?)) WHERE edge_id = ?",
2968 xtable);
2969 free (xtable);
2970 sqlite3_free (table);
2971 ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
2972 sqlite3_free (sql);
2973 if (ret != SQLITE_OK)
2974 return;
2975 sqlite3_reset (stmt);
2976 sqlite3_clear_bindings (stmt);
2977 sqlite3_bind_double (stmt, 1, pt->X);
2978 sqlite3_bind_double (stmt, 2, pt->Y);
2979 sqlite3_bind_double (stmt, 3, pt->Z);
2980 sqlite3_bind_int64 (stmt, 4, old_edge);
2981 ret = sqlite3_step (stmt);
2982 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
2983 ;
2984 else
2985 goto error2;
2986
2987 sqlite3_finalize (stmt);
2988 table = sqlite3_mprintf ("%s_edge", topo->topology_name);
2989 xtable = gaiaDoubleQuotedSql (table);
2990 sql =
2991 sqlite3_mprintf
2992 ("UPDATE \"%s\" SET geom = ST_SetStartPoint(geom, MakePointZ(?, ?, ?)) WHERE edge_id = ?",
2993 xtable);
2994 free (xtable);
2995 sqlite3_free (table);
2996 ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
2997 sqlite3_free (sql);
2998 if (ret != SQLITE_OK)
2999 return;
3000 sqlite3_reset (stmt);
3001 sqlite3_clear_bindings (stmt);
3002 sqlite3_bind_double (stmt, 1, pt->X);
3003 sqlite3_bind_double (stmt, 2, pt->Y);
3004 sqlite3_bind_double (stmt, 3, pt->Z);
3005 sqlite3_bind_int64 (stmt, 4, new_edge);
3006 ret = sqlite3_step (stmt);
3007 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
3008 ;
3009 else
3010 goto error2;
3011
3012 error2:
3013 sqlite3_finalize (stmt);
3014 return;
3015 }
3016
3017 static void
do_check_mod_split_edge(struct gaia_topology * topo,gaiaPointPtr pt,sqlite3_int64 old_edge)3018 do_check_mod_split_edge (struct gaia_topology *topo, gaiaPointPtr pt,
3019 sqlite3_int64 old_edge)
3020 {
3021 /*
3022 / defensive programming: carefully ensuring that lwgeom could
3023 / never shift Edges' start/end points after computing ModSplit
3024 / 2D topology
3025 */
3026 sqlite3_stmt *stmt = NULL;
3027 int ret;
3028 char *sql;
3029 char *table;
3030 char *xtable;
3031 double x1s;
3032 double y1s;
3033 double x1e;
3034 double y1e;
3035 double x2s;
3036 double y2s;
3037 double x2e;
3038 double y2e;
3039 sqlite3_int64 new_edge;
3040 if (topo->has_z)
3041 {
3042 do_check_mod_split_edge3d (topo, pt, old_edge);
3043 return;
3044 }
3045
3046 new_edge = sqlite3_last_insert_rowid (topo->db_handle);
3047 table = sqlite3_mprintf ("%s_edge", topo->topology_name);
3048 xtable = gaiaDoubleQuotedSql (table);
3049 sql =
3050 sqlite3_mprintf
3051 ("SELECT ST_X(ST_StartPoint(geom)), ST_Y(ST_StartPoint(geom)), "
3052 "ST_X(ST_EndPoint(geom)), ST_Y(ST_EndPoint(geom)) FROM \"%s\" WHERE edge_id = ?",
3053 xtable);
3054 free (xtable);
3055 sqlite3_free (table);
3056 ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
3057 sqlite3_free (sql);
3058 if (ret != SQLITE_OK)
3059 return;
3060
3061 sqlite3_reset (stmt);
3062 sqlite3_clear_bindings (stmt);
3063 sqlite3_bind_int64 (stmt, 1, old_edge);
3064 while (1)
3065 {
3066 /* scrolling the result set rows */
3067 ret = sqlite3_step (stmt);
3068 if (ret == SQLITE_DONE)
3069 break; /* end of result set */
3070 if (ret == SQLITE_ROW)
3071 {
3072 x1s = sqlite3_column_double (stmt, 0);
3073 y1s = sqlite3_column_double (stmt, 1);
3074 x1e = sqlite3_column_double (stmt, 2);
3075 y1e = sqlite3_column_double (stmt, 3);
3076 }
3077 else
3078 goto error;
3079 }
3080
3081 sqlite3_reset (stmt);
3082 sqlite3_clear_bindings (stmt);
3083 sqlite3_bind_int64 (stmt, 1, new_edge);
3084 while (1)
3085 {
3086 /* scrolling the result set rows */
3087 ret = sqlite3_step (stmt);
3088 if (ret == SQLITE_DONE)
3089 break; /* end of result set */
3090 if (ret == SQLITE_ROW)
3091 {
3092 x2s = sqlite3_column_double (stmt, 0);
3093 y2s = sqlite3_column_double (stmt, 1);
3094 x2e = sqlite3_column_double (stmt, 2);
3095 y2e = sqlite3_column_double (stmt, 3);
3096 }
3097 else
3098 goto error;
3099 }
3100 if (x1s == x2e && y1s == y2e)
3101 {
3102 /* just silencing stupid compiler warnings */
3103 ;
3104 }
3105 if (x1e == x2s && y1e == y2s)
3106 {
3107 if (x1e != pt->X || y1e != pt->Y)
3108 goto fixme;
3109 }
3110 error:
3111 sqlite3_finalize (stmt);
3112 return;
3113
3114 fixme:
3115 sqlite3_finalize (stmt);
3116 table = sqlite3_mprintf ("%s_edge", topo->topology_name);
3117 xtable = gaiaDoubleQuotedSql (table);
3118 sql =
3119 sqlite3_mprintf
3120 ("UPDATE \"%s\" SET geom = ST_SetEndPoint(geom, MakePoint(?, ?)) WHERE edge_id = ?",
3121 xtable);
3122 free (xtable);
3123 sqlite3_free (table);
3124 ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
3125 sqlite3_free (sql);
3126 if (ret != SQLITE_OK)
3127 return;
3128 sqlite3_reset (stmt);
3129 sqlite3_clear_bindings (stmt);
3130 sqlite3_bind_double (stmt, 1, pt->X);
3131 sqlite3_bind_double (stmt, 2, pt->Y);
3132 sqlite3_bind_int64 (stmt, 3, old_edge);
3133 ret = sqlite3_step (stmt);
3134 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
3135 ;
3136 else
3137 goto error2;
3138
3139 sqlite3_finalize (stmt);
3140 table = sqlite3_mprintf ("%s_edge", topo->topology_name);
3141 xtable = gaiaDoubleQuotedSql (table);
3142 sql =
3143 sqlite3_mprintf
3144 ("UPDATE \"%s\" SET geom = ST_SetStartPoint(geom, MakePoint(?, ?)) WHERE edge_id = ?",
3145 xtable);
3146 free (xtable);
3147 sqlite3_free (table);
3148 ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
3149 sqlite3_free (sql);
3150 if (ret != SQLITE_OK)
3151 return;
3152 sqlite3_reset (stmt);
3153 sqlite3_clear_bindings (stmt);
3154 sqlite3_bind_double (stmt, 1, pt->X);
3155 sqlite3_bind_double (stmt, 2, pt->Y);
3156 sqlite3_bind_int64 (stmt, 3, new_edge);
3157 ret = sqlite3_step (stmt);
3158 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
3159 ;
3160 else
3161 goto error2;
3162
3163 error2:
3164 sqlite3_finalize (stmt);
3165 return;
3166 }
3167
3168 GAIATOPO_DECLARE sqlite3_int64
gaiaModEdgeSplit(GaiaTopologyAccessorPtr accessor,sqlite3_int64 edge,gaiaPointPtr pt,int skip_checks)3169 gaiaModEdgeSplit (GaiaTopologyAccessorPtr accessor,
3170 sqlite3_int64 edge, gaiaPointPtr pt, int skip_checks)
3171 {
3172 /* RTT wrapper - ModEdgeSplit */
3173 const RTCTX *ctx = NULL;
3174 struct splite_internal_cache *cache = NULL;
3175 sqlite3_int64 ret;
3176 int has_z = 0;
3177 RTPOINT *rt_pt;
3178 RTPOINTARRAY *pa;
3179 RTPOINT4D point;
3180 struct gaia_topology *topo = (struct gaia_topology *) accessor;
3181 if (topo == NULL)
3182 return 0;
3183
3184 cache = (struct splite_internal_cache *) topo->cache;
3185 if (cache == NULL)
3186 return 0;
3187 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
3188 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
3189 return 0;
3190 ctx = cache->RTTOPO_handle;
3191 if (ctx == NULL)
3192 return 0;
3193
3194 if (pt->DimensionModel == GAIA_XY_Z || pt->DimensionModel == GAIA_XY_Z_M)
3195 has_z = 1;
3196 pa = ptarray_construct (ctx, has_z, 0, 1);
3197 point.x = pt->X;
3198 point.y = pt->Y;
3199 if (has_z)
3200 point.z = pt->Z;
3201 ptarray_set_point4d (ctx, pa, 0, &point);
3202 rt_pt = rtpoint_construct (ctx, topo->srid, NULL, pa);
3203
3204 gaiaResetRtTopoMsg (cache);
3205 ret =
3206 rtt_ModEdgeSplit ((RTT_TOPOLOGY *) (topo->rtt_topology), edge, rt_pt,
3207 skip_checks);
3208
3209 rtpoint_free (ctx, rt_pt);
3210
3211 if (ret > 0)
3212 do_check_mod_split_edge (topo, pt, edge);
3213
3214 return ret;
3215 }
3216
3217 GAIATOPO_DECLARE sqlite3_int64
gaiaNewEdgesSplit(GaiaTopologyAccessorPtr accessor,sqlite3_int64 edge,gaiaPointPtr pt,int skip_checks)3218 gaiaNewEdgesSplit (GaiaTopologyAccessorPtr accessor,
3219 sqlite3_int64 edge, gaiaPointPtr pt, int skip_checks)
3220 {
3221 /* RTT wrapper - NewEdgesSplit */
3222 const RTCTX *ctx = NULL;
3223 struct splite_internal_cache *cache = NULL;
3224 sqlite3_int64 ret;
3225 int has_z = 0;
3226 RTPOINT *rt_pt;
3227 RTPOINTARRAY *pa;
3228 RTPOINT4D point;
3229 struct gaia_topology *topo = (struct gaia_topology *) accessor;
3230 if (topo == NULL)
3231 return 0;
3232
3233 cache = (struct splite_internal_cache *) topo->cache;
3234 if (cache == NULL)
3235 return 0;
3236 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
3237 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
3238 return 0;
3239 ctx = cache->RTTOPO_handle;
3240 if (ctx == NULL)
3241 return 0;
3242
3243 if (pt->DimensionModel == GAIA_XY_Z || pt->DimensionModel == GAIA_XY_Z_M)
3244 has_z = 1;
3245 pa = ptarray_construct (ctx, has_z, 0, 1);
3246 point.x = pt->X;
3247 point.y = pt->Y;
3248 if (has_z)
3249 point.z = pt->Z;
3250 ptarray_set_point4d (ctx, pa, 0, &point);
3251 rt_pt = rtpoint_construct (ctx, topo->srid, NULL, pa);
3252
3253 gaiaResetRtTopoMsg (cache);
3254 ret =
3255 rtt_NewEdgesSplit ((RTT_TOPOLOGY *) (topo->rtt_topology), edge, rt_pt,
3256 skip_checks);
3257
3258 rtpoint_free (ctx, rt_pt);
3259 return ret;
3260 }
3261
3262 GAIATOPO_DECLARE sqlite3_int64
gaiaAddEdgeModFace(GaiaTopologyAccessorPtr accessor,sqlite3_int64 start_node,sqlite3_int64 end_node,gaiaLinestringPtr ln,int skip_checks)3263 gaiaAddEdgeModFace (GaiaTopologyAccessorPtr accessor,
3264 sqlite3_int64 start_node, sqlite3_int64 end_node,
3265 gaiaLinestringPtr ln, int skip_checks)
3266 {
3267 /* RTT wrapper - AddEdgeModFace */
3268 const RTCTX *ctx = NULL;
3269 struct splite_internal_cache *cache = NULL;
3270 sqlite3_int64 ret;
3271 RTLINE *rt_line;
3272 struct gaia_topology *topo = (struct gaia_topology *) accessor;
3273 if (topo == NULL)
3274 return 0;
3275
3276 cache = (struct splite_internal_cache *) topo->cache;
3277 if (cache == NULL)
3278 return 0;
3279 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
3280 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
3281 return 0;
3282 ctx = cache->RTTOPO_handle;
3283 if (ctx == NULL)
3284 return 0;
3285
3286 rt_line =
3287 gaia_convert_linestring_to_rtline (ctx, ln, topo->srid, topo->has_z);
3288
3289 gaiaResetRtTopoMsg (cache);
3290 ret =
3291 rtt_AddEdgeModFace ((RTT_TOPOLOGY *) (topo->rtt_topology), start_node,
3292 end_node, rt_line, skip_checks);
3293
3294 rtline_free (ctx, rt_line);
3295 return ret;
3296 }
3297
3298 GAIATOPO_DECLARE sqlite3_int64
gaiaAddEdgeNewFaces(GaiaTopologyAccessorPtr accessor,sqlite3_int64 start_node,sqlite3_int64 end_node,gaiaLinestringPtr ln,int skip_checks)3299 gaiaAddEdgeNewFaces (GaiaTopologyAccessorPtr accessor,
3300 sqlite3_int64 start_node, sqlite3_int64 end_node,
3301 gaiaLinestringPtr ln, int skip_checks)
3302 {
3303 /* RTT wrapper - AddEdgeNewFaces */
3304 const RTCTX *ctx = NULL;
3305 struct splite_internal_cache *cache = NULL;
3306 sqlite3_int64 ret;
3307 RTLINE *rt_line;
3308 struct gaia_topology *topo = (struct gaia_topology *) accessor;
3309 if (topo == NULL)
3310 return 0;
3311
3312 cache = (struct splite_internal_cache *) topo->cache;
3313 if (cache == NULL)
3314 return 0;
3315 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
3316 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
3317 return 0;
3318 ctx = cache->RTTOPO_handle;
3319 if (ctx == NULL)
3320 return 0;
3321
3322 rt_line =
3323 gaia_convert_linestring_to_rtline (ctx, ln, topo->srid, topo->has_z);
3324
3325 gaiaResetRtTopoMsg (cache);
3326 ret =
3327 rtt_AddEdgeNewFaces ((RTT_TOPOLOGY *) (topo->rtt_topology), start_node,
3328 end_node, rt_line, skip_checks);
3329
3330 rtline_free (ctx, rt_line);
3331 return ret;
3332 }
3333
3334 GAIATOPO_DECLARE sqlite3_int64
gaiaRemEdgeNewFace(GaiaTopologyAccessorPtr accessor,sqlite3_int64 edge_id)3335 gaiaRemEdgeNewFace (GaiaTopologyAccessorPtr accessor, sqlite3_int64 edge_id)
3336 {
3337 /* RTT wrapper - RemEdgeNewFace */
3338 struct splite_internal_cache *cache = NULL;
3339 sqlite3_int64 ret;
3340 struct gaia_topology *topo = (struct gaia_topology *) accessor;
3341 if (topo == NULL)
3342 return 0;
3343
3344 cache = (struct splite_internal_cache *) topo->cache;
3345 if (cache == NULL)
3346 return 0;
3347 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
3348 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
3349 return 0;
3350
3351 gaiaResetRtTopoMsg (cache);
3352 ret = rtt_RemEdgeNewFace ((RTT_TOPOLOGY *) (topo->rtt_topology), edge_id);
3353
3354 return ret;
3355 }
3356
3357 GAIATOPO_DECLARE sqlite3_int64
gaiaRemEdgeModFace(GaiaTopologyAccessorPtr accessor,sqlite3_int64 edge_id)3358 gaiaRemEdgeModFace (GaiaTopologyAccessorPtr accessor, sqlite3_int64 edge_id)
3359 {
3360 /* RTT wrapper - RemEdgeModFace */
3361 struct splite_internal_cache *cache = NULL;
3362 sqlite3_int64 ret;
3363 struct gaia_topology *topo = (struct gaia_topology *) accessor;
3364 if (topo == NULL)
3365 return 0;
3366
3367 cache = (struct splite_internal_cache *) topo->cache;
3368 if (cache == NULL)
3369 return 0;
3370 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
3371 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
3372 return 0;
3373
3374 gaiaResetRtTopoMsg (cache);
3375 ret = rtt_RemEdgeModFace ((RTT_TOPOLOGY *) (topo->rtt_topology), edge_id);
3376
3377 return ret;
3378 }
3379
3380 GAIATOPO_DECLARE sqlite3_int64
gaiaNewEdgeHeal(GaiaTopologyAccessorPtr accessor,sqlite3_int64 edge_id1,sqlite3_int64 edge_id2)3381 gaiaNewEdgeHeal (GaiaTopologyAccessorPtr accessor, sqlite3_int64 edge_id1,
3382 sqlite3_int64 edge_id2)
3383 {
3384 /* RTT wrapper - NewEdgeHeal */
3385 struct splite_internal_cache *cache = NULL;
3386 sqlite3_int64 ret;
3387 struct gaia_topology *topo = (struct gaia_topology *) accessor;
3388 if (topo == NULL)
3389 return 0;
3390
3391 cache = (struct splite_internal_cache *) topo->cache;
3392 if (cache == NULL)
3393 return 0;
3394 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
3395 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
3396 return 0;
3397
3398 gaiaResetRtTopoMsg (cache);
3399 ret =
3400 rtt_NewEdgeHeal ((RTT_TOPOLOGY *) (topo->rtt_topology), edge_id1,
3401 edge_id2);
3402
3403 return ret;
3404 }
3405
3406 GAIATOPO_DECLARE sqlite3_int64
gaiaModEdgeHeal(GaiaTopologyAccessorPtr accessor,sqlite3_int64 edge_id1,sqlite3_int64 edge_id2)3407 gaiaModEdgeHeal (GaiaTopologyAccessorPtr accessor, sqlite3_int64 edge_id1,
3408 sqlite3_int64 edge_id2)
3409 {
3410 /* RTT wrapper - ModEdgeHeal */
3411 struct splite_internal_cache *cache = NULL;
3412 sqlite3_int64 ret;
3413 struct gaia_topology *topo = (struct gaia_topology *) accessor;
3414 if (topo == NULL)
3415 return 0;
3416
3417 cache = (struct splite_internal_cache *) topo->cache;
3418 if (cache == NULL)
3419 return 0;
3420 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
3421 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
3422 return 0;
3423
3424 gaiaResetRtTopoMsg (cache);
3425 ret =
3426 rtt_ModEdgeHeal ((RTT_TOPOLOGY *) (topo->rtt_topology), edge_id1,
3427 edge_id2);
3428
3429 return ret;
3430 }
3431
3432 GAIATOPO_DECLARE gaiaGeomCollPtr
gaiaGetFaceGeometry(GaiaTopologyAccessorPtr accessor,sqlite3_int64 face)3433 gaiaGetFaceGeometry (GaiaTopologyAccessorPtr accessor, sqlite3_int64 face)
3434 {
3435 /* RTT wrapper - GetFaceGeometry */
3436 const RTCTX *ctx = NULL;
3437 struct splite_internal_cache *cache = NULL;
3438 RTGEOM *result = NULL;
3439 RTPOLY *rtpoly;
3440 int has_z = 0;
3441 RTPOINTARRAY *pa;
3442 RTPOINT4D pt4d;
3443 int iv;
3444 int ib;
3445 double x;
3446 double y;
3447 double z;
3448 gaiaGeomCollPtr geom;
3449 gaiaPolygonPtr pg;
3450 gaiaRingPtr rng;
3451 int dimension_model;
3452 struct gaia_topology *topo = (struct gaia_topology *) accessor;
3453 if (topo == NULL)
3454 return 0;
3455
3456 cache = (struct splite_internal_cache *) topo->cache;
3457 if (cache == NULL)
3458 return 0;
3459 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
3460 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
3461 return 0;
3462 ctx = cache->RTTOPO_handle;
3463 if (ctx == NULL)
3464 return 0;
3465
3466 result = rtt_GetFaceGeometry ((RTT_TOPOLOGY *) (topo->rtt_topology), face);
3467 if (result == NULL)
3468 return NULL;
3469
3470 /* converting the result as a Gaia Geometry */
3471 rtpoly = (RTPOLY *) result;
3472 if (rtpoly->nrings <= 0)
3473 {
3474 /* empty geometry */
3475 rtgeom_free (ctx, result);
3476 return NULL;
3477 }
3478 pa = rtpoly->rings[0];
3479 if (pa->npoints <= 0)
3480 {
3481 /* empty geometry */
3482 rtgeom_free (ctx, result);
3483 return NULL;
3484 }
3485 if (RTFLAGS_GET_Z (pa->flags))
3486 has_z = 1;
3487 if (has_z)
3488 {
3489 dimension_model = GAIA_XY_Z;
3490 geom = gaiaAllocGeomCollXYZ ();
3491 }
3492 else
3493 {
3494 dimension_model = GAIA_XY;
3495 geom = gaiaAllocGeomColl ();
3496 }
3497 pg = gaiaAddPolygonToGeomColl (geom, pa->npoints, rtpoly->nrings - 1);
3498 rng = pg->Exterior;
3499 for (iv = 0; iv < pa->npoints; iv++)
3500 {
3501 /* copying Exterior Ring vertices */
3502 rt_getPoint4d_p (ctx, pa, iv, &pt4d);
3503 x = pt4d.x;
3504 y = pt4d.y;
3505 if (has_z)
3506 z = pt4d.z;
3507 else
3508 z = 0.0;
3509 if (dimension_model == GAIA_XY_Z)
3510 {
3511 gaiaSetPointXYZ (rng->Coords, iv, x, y, z);
3512 }
3513 else
3514 {
3515 gaiaSetPoint (rng->Coords, iv, x, y);
3516 }
3517 }
3518 for (ib = 1; ib < rtpoly->nrings; ib++)
3519 {
3520 has_z = 0;
3521 pa = rtpoly->rings[ib];
3522 if (RTFLAGS_GET_Z (pa->flags))
3523 has_z = 1;
3524 rng = gaiaAddInteriorRing (pg, ib - 1, pa->npoints);
3525 for (iv = 0; iv < pa->npoints; iv++)
3526 {
3527 /* copying Exterior Ring vertices */
3528 rt_getPoint4d_p (ctx, pa, iv, &pt4d);
3529 x = pt4d.x;
3530 y = pt4d.y;
3531 if (has_z)
3532 z = pt4d.z;
3533 else
3534 z = 0.0;
3535 if (dimension_model == GAIA_XY_Z)
3536 {
3537 gaiaSetPointXYZ (rng->Coords, iv, x, y, z);
3538 }
3539 else
3540 {
3541 gaiaSetPoint (rng->Coords, iv, x, y);
3542 }
3543 }
3544 }
3545 rtgeom_free (ctx, result);
3546 geom->DeclaredType = GAIA_POLYGON;
3547 geom->Srid = topo->srid;
3548 return geom;
3549 }
3550
3551 static int
do_check_create_faceedges_table(GaiaTopologyAccessorPtr accessor)3552 do_check_create_faceedges_table (GaiaTopologyAccessorPtr accessor)
3553 {
3554 /* attemtping to create or validate the target table */
3555 char *sql;
3556 char *table;
3557 char *xtable;
3558 int ret;
3559 int i;
3560 char **results;
3561 int rows;
3562 int columns;
3563 char *errMsg = NULL;
3564 int exists = 0;
3565 int ok_face_id = 0;
3566 int ok_sequence = 0;
3567 int ok_edge_id = 0;
3568 struct gaia_topology *topo = (struct gaia_topology *) accessor;
3569
3570 /* testing for an already existing table */
3571 table = sqlite3_mprintf ("%s_face_edges_temp", topo->topology_name);
3572 xtable = gaiaDoubleQuotedSql (table);
3573 sqlite3_free (table);
3574 sql = sqlite3_mprintf ("PRAGMA TEMP.table_info(\"%s\")", xtable);
3575 free (xtable);
3576 ret =
3577 sqlite3_get_table (topo->db_handle, sql, &results, &rows, &columns,
3578 &errMsg);
3579 sqlite3_free (sql);
3580 if (ret != SQLITE_OK)
3581 {
3582 char *msg = sqlite3_mprintf ("ST_GetFaceEdges exception: %s", errMsg);
3583 gaiatopo_set_last_error_msg (accessor, msg);
3584 sqlite3_free (msg);
3585 sqlite3_free (errMsg);
3586 return 0;
3587 }
3588 for (i = 1; i <= rows; i++)
3589 {
3590 const char *name = results[(i * columns) + 1];
3591 const char *type = results[(i * columns) + 2];
3592 const char *notnull = results[(i * columns) + 3];
3593 const char *dflt_value = results[(i * columns) + 4];
3594 const char *pk = results[(i * columns) + 5];
3595 if (strcmp (name, "face_id") == 0 && strcmp (type, "INTEGER") == 0
3596 && strcmp (notnull, "1") == 0 && dflt_value == NULL
3597 && strcmp (pk, "1") == 0)
3598 ok_face_id = 1;
3599 if (strcmp (name, "sequence") == 0 && strcmp (type, "INTEGER") == 0
3600 && strcmp (notnull, "1") == 0 && dflt_value == NULL
3601 && strcmp (pk, "2") == 0)
3602 ok_sequence = 1;
3603 if (strcmp (name, "edge_id") == 0 && strcmp (type, "INTEGER") == 0
3604 && strcmp (notnull, "1") == 0 && dflt_value == NULL
3605 && strcmp (pk, "0") == 0)
3606 ok_edge_id = 1;
3607 exists = 1;
3608 }
3609 sqlite3_free_table (results);
3610 if (ok_face_id && ok_sequence && ok_edge_id)
3611 return 1; /* already existing and valid */
3612
3613 if (exists)
3614 return 0; /* already existing but invalid */
3615
3616 /* attempting to create the table */
3617 table = sqlite3_mprintf ("%s_face_edges_temp", topo->topology_name);
3618 xtable = gaiaDoubleQuotedSql (table);
3619 sqlite3_free (table);
3620 sql =
3621 sqlite3_mprintf
3622 ("CREATE TEMP TABLE \"%s\" (\n\tface_id INTEGER NOT NULL,\n"
3623 "\tsequence INTEGER NOT NULL,\n\tedge_id INTEGER NOT NULL,\n"
3624 "\tCONSTRAINT pk_topo_facee_edges PRIMARY KEY (face_id, sequence))",
3625 xtable);
3626 free (xtable);
3627 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
3628 sqlite3_free (sql);
3629 if (ret != SQLITE_OK)
3630 {
3631 char *msg = sqlite3_mprintf ("ST_GetFaceEdges exception: %s", errMsg);
3632 gaiatopo_set_last_error_msg (accessor, msg);
3633 sqlite3_free (msg);
3634 sqlite3_free (errMsg);
3635 return 0;
3636 }
3637
3638 return 1;
3639 }
3640
3641 static int
do_populate_faceedges_table(GaiaTopologyAccessorPtr accessor,sqlite3_int64 face,RTT_ELEMID * edges,int num_edges)3642 do_populate_faceedges_table (GaiaTopologyAccessorPtr accessor,
3643 sqlite3_int64 face, RTT_ELEMID * edges,
3644 int num_edges)
3645 {
3646 /* populating the target table */
3647 char *sql;
3648 char *table;
3649 char *xtable;
3650 int ret;
3651 int i;
3652 sqlite3_stmt *stmt = NULL;
3653 struct gaia_topology *topo = (struct gaia_topology *) accessor;
3654
3655 /* deleting all rows belonging to Face (if any) */
3656 table = sqlite3_mprintf ("%s_face_edges_temp", topo->topology_name);
3657 xtable = gaiaDoubleQuotedSql (table);
3658 sqlite3_free (table);
3659 sql = sqlite3_mprintf ("DELETE FROM TEMP.\"%s\" WHERE face_id = ?", xtable);
3660 free (xtable);
3661 ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
3662 sqlite3_free (sql);
3663 if (ret != SQLITE_OK)
3664 {
3665 char *msg = sqlite3_mprintf ("ST_GetFaceEdges exception: %s",
3666 sqlite3_errmsg (topo->db_handle));
3667 gaiatopo_set_last_error_msg (accessor, msg);
3668 sqlite3_free (msg);
3669 goto error;
3670 }
3671 sqlite3_reset (stmt);
3672 sqlite3_clear_bindings (stmt);
3673 sqlite3_bind_int64 (stmt, 1, face);
3674 ret = sqlite3_step (stmt);
3675 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
3676 ;
3677 else
3678 {
3679 char *msg = sqlite3_mprintf ("ST_GetFaceEdges exception: %s",
3680 sqlite3_errmsg (topo->db_handle));
3681 gaiatopo_set_last_error_msg (accessor, msg);
3682 sqlite3_free (msg);
3683 goto error;
3684 }
3685 sqlite3_finalize (stmt);
3686 stmt = NULL;
3687
3688 /* preparing the INSERT statement */
3689 table = sqlite3_mprintf ("%s_face_edges_temp", topo->topology_name);
3690 xtable = gaiaDoubleQuotedSql (table);
3691 sqlite3_free (table);
3692 sql =
3693 sqlite3_mprintf
3694 ("INSERT INTO TEMP.\"%s\" (face_id, sequence, edge_id) VALUES (?, ?, ?)",
3695 xtable);
3696 free (xtable);
3697 ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
3698 sqlite3_free (sql);
3699 if (ret != SQLITE_OK)
3700 {
3701 char *msg = sqlite3_mprintf ("ST_GetFaceEdges exception: %s",
3702 sqlite3_errmsg (topo->db_handle));
3703 gaiatopo_set_last_error_msg (accessor, msg);
3704 sqlite3_free (msg);
3705 goto error;
3706 }
3707 for (i = 0; i < num_edges; i++)
3708 {
3709 /* inserting all Face/Edges */
3710 sqlite3_reset (stmt);
3711 sqlite3_clear_bindings (stmt);
3712 sqlite3_bind_int64 (stmt, 1, face);
3713 sqlite3_bind_int (stmt, 2, i + 1);
3714 sqlite3_bind_int64 (stmt, 3, *(edges + i));
3715 ret = sqlite3_step (stmt);
3716 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
3717 ;
3718 else
3719 {
3720 char *msg = sqlite3_mprintf ("ST_GetFaceEdges exception: %s",
3721 sqlite3_errmsg (topo->db_handle));
3722 gaiatopo_set_last_error_msg (accessor, msg);
3723 sqlite3_free (msg);
3724 goto error;
3725 }
3726 }
3727 sqlite3_finalize (stmt);
3728 return 1;
3729
3730 error:
3731 if (stmt != NULL)
3732 sqlite3_finalize (stmt);
3733 return 0;
3734 }
3735
3736 GAIATOPO_DECLARE int
gaiaGetFaceEdges(GaiaTopologyAccessorPtr accessor,sqlite3_int64 face)3737 gaiaGetFaceEdges (GaiaTopologyAccessorPtr accessor, sqlite3_int64 face)
3738 {
3739 /* RTT wrapper - GetFaceEdges */
3740 const RTCTX *ctx = NULL;
3741 struct splite_internal_cache *cache = NULL;
3742 RTT_ELEMID *edges = NULL;
3743 int num_edges;
3744 struct gaia_topology *topo = (struct gaia_topology *) accessor;
3745 if (topo == NULL)
3746 return 0;
3747
3748 cache = (struct splite_internal_cache *) topo->cache;
3749 if (cache == NULL)
3750 return 0;
3751 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
3752 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
3753 return 0;
3754 ctx = cache->RTTOPO_handle;
3755 if (ctx == NULL)
3756 return 0;
3757
3758 gaiaResetRtTopoMsg (cache);
3759
3760 num_edges =
3761 rtt_GetFaceEdges ((RTT_TOPOLOGY *) (topo->rtt_topology), face, &edges);
3762
3763 if (num_edges < 0)
3764 return 0;
3765
3766 if (num_edges > 0)
3767 {
3768 /* attemtping to create or validate the target table */
3769 if (!do_check_create_faceedges_table (accessor))
3770 {
3771 rtfree (ctx, edges);
3772 return 0;
3773 }
3774
3775 /* populating the target table */
3776 if (!do_populate_faceedges_table (accessor, face, edges, num_edges))
3777 {
3778 rtfree (ctx, edges);
3779 return 0;
3780 }
3781 }
3782 rtfree (ctx, edges);
3783 return 1;
3784 }
3785
3786 static int
do_check_create_validate_topogeo_table(GaiaTopologyAccessorPtr accessor)3787 do_check_create_validate_topogeo_table (GaiaTopologyAccessorPtr accessor)
3788 {
3789 /* attemtping to create or validate the target table */
3790 char *sql;
3791 char *table;
3792 char *xtable;
3793 int ret;
3794 char *errMsg = NULL;
3795 struct gaia_topology *topo = (struct gaia_topology *) accessor;
3796
3797 /* finalizing all prepared Statements */
3798 finalize_all_topo_prepared_stmts (topo->cache);
3799
3800 /* attempting to drop the table (just in case if it already exists) */
3801 table = sqlite3_mprintf ("%s_validate_topogeo", topo->topology_name);
3802 xtable = gaiaDoubleQuotedSql (table);
3803 sqlite3_free (table);
3804 sql = sqlite3_mprintf ("DROP TABLE IF EXISTS temp.\"%s\"", xtable);
3805 free (xtable);
3806 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
3807 create_all_topo_prepared_stmts (topo->cache); /* recreating prepared stsms */
3808 sqlite3_free (sql);
3809 if (ret != SQLITE_OK)
3810 {
3811 char *msg =
3812 sqlite3_mprintf ("ST_ValidSpatialNet exception: %s", errMsg);
3813 gaiatopo_set_last_error_msg (accessor, msg);
3814 sqlite3_free (msg);
3815 sqlite3_free (errMsg);
3816 return 0;
3817 }
3818 /* attempting to create the table */
3819 table = sqlite3_mprintf ("%s_validate_topogeo", topo->topology_name);
3820 xtable = gaiaDoubleQuotedSql (table);
3821 sqlite3_free (table);
3822 sql =
3823 sqlite3_mprintf
3824 ("CREATE TEMP TABLE \"%s\" (\n\terror TEXT,\n"
3825 "\tprimitive1 INTEGER,\n\tprimitive2 INTEGER)", xtable);
3826 free (xtable);
3827 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
3828 sqlite3_free (sql);
3829 if (ret != SQLITE_OK)
3830 {
3831 char *msg =
3832 sqlite3_mprintf ("ST_ValidateTopoGeo exception: %s", errMsg);
3833 gaiatopo_set_last_error_msg (accessor, msg);
3834 sqlite3_free (msg);
3835 sqlite3_free (errMsg);
3836 return 0;
3837 }
3838
3839 return 1;
3840 }
3841
3842 static int
do_topo_check_coincident_nodes(GaiaTopologyAccessorPtr accessor,sqlite3_stmt * stmt)3843 do_topo_check_coincident_nodes (GaiaTopologyAccessorPtr accessor,
3844 sqlite3_stmt * stmt)
3845 {
3846 /* checking for coincident nodes */
3847 char *sql;
3848 char *table;
3849 char *xtable;
3850 int ret;
3851 sqlite3_stmt *stmt_in = NULL;
3852 struct gaia_topology *topo = (struct gaia_topology *) accessor;
3853
3854 table = sqlite3_mprintf ("%s_node", topo->topology_name);
3855 xtable = gaiaDoubleQuotedSql (table);
3856 sql =
3857 sqlite3_mprintf ("SELECT n1.node_id, n2.node_id FROM MAIN.\"%s\" AS n1 "
3858 "JOIN MAIN.\"%s\" AS n2 ON (n1.node_id <> n2.node_id AND "
3859 "ST_Equals(n1.geom, n2.geom) = 1 AND n2.node_id IN "
3860 "(SELECT rowid FROM SpatialIndex WHERE f_table_name = %Q AND "
3861 "f_geometry_column = 'geom' AND search_frame = n1.geom))",
3862 xtable, xtable, table);
3863 sqlite3_free (table);
3864 free (xtable);
3865 ret =
3866 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
3867 sqlite3_free (sql);
3868 if (ret != SQLITE_OK)
3869 {
3870 char *msg =
3871 sqlite3_mprintf
3872 ("ST_ValidateTopoGeo() - CoicidentNodes error: \"%s\"",
3873 sqlite3_errmsg (topo->db_handle));
3874 gaiatopo_set_last_error_msg (accessor, msg);
3875 sqlite3_free (msg);
3876 goto error;
3877 }
3878
3879 sqlite3_reset (stmt_in);
3880 sqlite3_clear_bindings (stmt_in);
3881 while (1)
3882 {
3883 /* scrolling the result set rows */
3884 ret = sqlite3_step (stmt_in);
3885 if (ret == SQLITE_DONE)
3886 break; /* end of result set */
3887 if (ret == SQLITE_ROW)
3888 {
3889 sqlite3_int64 node_id1 = sqlite3_column_int64 (stmt_in, 0);
3890 sqlite3_int64 node_id2 = sqlite3_column_int64 (stmt_in, 1);
3891 /* reporting the error */
3892 sqlite3_reset (stmt);
3893 sqlite3_clear_bindings (stmt);
3894 sqlite3_bind_text (stmt, 1, "coincident nodes", -1,
3895 SQLITE_STATIC);
3896 sqlite3_bind_int64 (stmt, 2, node_id1);
3897 sqlite3_bind_int64 (stmt, 3, node_id2);
3898 ret = sqlite3_step (stmt);
3899 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
3900 ;
3901 else
3902 {
3903 char *msg =
3904 sqlite3_mprintf
3905 ("ST_ValidateTopoGeo() insert #1 error: \"%s\"",
3906 sqlite3_errmsg (topo->db_handle));
3907 gaiatopo_set_last_error_msg (accessor, msg);
3908 sqlite3_free (msg);
3909 goto error;
3910 }
3911 }
3912 else
3913 {
3914 char *msg =
3915 sqlite3_mprintf
3916 ("ST_ValidateTopoGeo() - CoicidentNodes step error: %s",
3917 sqlite3_errmsg (topo->db_handle));
3918 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
3919 msg);
3920 sqlite3_free (msg);
3921 goto error;
3922 }
3923 }
3924 sqlite3_finalize (stmt_in);
3925
3926 return 1;
3927
3928 error:
3929 if (stmt_in == NULL)
3930 sqlite3_finalize (stmt_in);
3931 return 0;
3932 }
3933
3934 static int
do_topo_check_edge_node(GaiaTopologyAccessorPtr accessor,sqlite3_stmt * stmt)3935 do_topo_check_edge_node (GaiaTopologyAccessorPtr accessor, sqlite3_stmt * stmt)
3936 {
3937 /* checking for edge-node crossing */
3938 char *sql;
3939 char *table;
3940 char *xtable1;
3941 char *xtable2;
3942 int ret;
3943 sqlite3_stmt *stmt_in = NULL;
3944 struct gaia_topology *topo = (struct gaia_topology *) accessor;
3945
3946 table = sqlite3_mprintf ("%s_edge", topo->topology_name);
3947 xtable1 = gaiaDoubleQuotedSql (table);
3948 sqlite3_free (table);
3949 table = sqlite3_mprintf ("%s_node", topo->topology_name);
3950 xtable2 = gaiaDoubleQuotedSql (table);
3951 sql = sqlite3_mprintf ("SELECT e.edge_id, n.node_id FROM MAIN.\"%s\" AS e "
3952 "JOIN MAIN.\"%s\" AS n ON (ST_Distance(e.geom, n.geom) <= 0 "
3953 "AND ST_Disjoint(ST_StartPoint(e.geom), n.geom) = 1 AND "
3954 "ST_Disjoint(ST_EndPoint(e.geom), n.geom) = 1 AND n.node_id IN "
3955 "(SELECT rowid FROM SpatialIndex WHERE f_table_name = %Q AND "
3956 "f_geometry_column = 'geom' AND search_frame = e.geom))",
3957 xtable1, xtable2, table);
3958 sqlite3_free (table);
3959 free (xtable1);
3960 free (xtable2);
3961 ret =
3962 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
3963 sqlite3_free (sql);
3964 if (ret != SQLITE_OK)
3965 {
3966 char *msg =
3967 sqlite3_mprintf
3968 ("ST_ValidateTopoGeo() - EdgeCrossedNode error: \"%s\"",
3969 sqlite3_errmsg (topo->db_handle));
3970 gaiatopo_set_last_error_msg (accessor, msg);
3971 sqlite3_free (msg);
3972 goto error;
3973 }
3974
3975 sqlite3_reset (stmt_in);
3976 sqlite3_clear_bindings (stmt_in);
3977 while (1)
3978 {
3979 /* scrolling the result set rows */
3980 ret = sqlite3_step (stmt_in);
3981 if (ret == SQLITE_DONE)
3982 break; /* end of result set */
3983 if (ret == SQLITE_ROW)
3984 {
3985 sqlite3_int64 edge_id = sqlite3_column_int64 (stmt_in, 0);
3986 sqlite3_int64 node_id = sqlite3_column_int64 (stmt_in, 1);
3987 /* reporting the error */
3988 sqlite3_reset (stmt);
3989 sqlite3_clear_bindings (stmt);
3990 sqlite3_bind_text (stmt, 1, "edge crosses node", -1,
3991 SQLITE_STATIC);
3992 sqlite3_bind_int64 (stmt, 2, node_id);
3993 sqlite3_bind_int64 (stmt, 3, edge_id);
3994 ret = sqlite3_step (stmt);
3995 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
3996 ;
3997 else
3998 {
3999 char *msg =
4000 sqlite3_mprintf
4001 ("ST_ValidateTopoGeo() insert #2 error: \"%s\"",
4002 sqlite3_errmsg (topo->db_handle));
4003 gaiatopo_set_last_error_msg (accessor, msg);
4004 sqlite3_free (msg);
4005 goto error;
4006 }
4007 }
4008 else
4009 {
4010 char *msg =
4011 sqlite3_mprintf
4012 ("ST_ValidateTopoGeo() - EdgeCrossedNode step error: %s",
4013 sqlite3_errmsg (topo->db_handle));
4014 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
4015 msg);
4016 sqlite3_free (msg);
4017 goto error;
4018 }
4019 }
4020 sqlite3_finalize (stmt_in);
4021
4022 return 1;
4023
4024 error:
4025 if (stmt_in == NULL)
4026 sqlite3_finalize (stmt_in);
4027 return 0;
4028 }
4029
4030 static int
do_topo_check_non_simple(GaiaTopologyAccessorPtr accessor,sqlite3_stmt * stmt)4031 do_topo_check_non_simple (GaiaTopologyAccessorPtr accessor, sqlite3_stmt * stmt)
4032 {
4033 /* checking for non-simple edges */
4034 char *sql;
4035 char *table;
4036 char *xtable;
4037 int ret;
4038 sqlite3_stmt *stmt_in = NULL;
4039 struct gaia_topology *topo = (struct gaia_topology *) accessor;
4040
4041 table = sqlite3_mprintf ("%s_edge", topo->topology_name);
4042 xtable = gaiaDoubleQuotedSql (table);
4043 sqlite3_free (table);
4044 sql =
4045 sqlite3_mprintf
4046 ("SELECT edge_id FROM MAIN.\"%s\" WHERE ST_IsSimple(geom) = 0", xtable);
4047 free (xtable);
4048 ret =
4049 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
4050 sqlite3_free (sql);
4051 if (ret != SQLITE_OK)
4052 {
4053 char *msg =
4054 sqlite3_mprintf
4055 ("ST_ValidateTopoGeo() - NonSimpleEdge error: \"%s\"",
4056 sqlite3_errmsg (topo->db_handle));
4057 gaiatopo_set_last_error_msg (accessor, msg);
4058 sqlite3_free (msg);
4059 goto error;
4060 }
4061
4062 sqlite3_reset (stmt_in);
4063 sqlite3_clear_bindings (stmt_in);
4064 while (1)
4065 {
4066 /* scrolling the result set rows */
4067 ret = sqlite3_step (stmt_in);
4068 if (ret == SQLITE_DONE)
4069 break; /* end of result set */
4070 if (ret == SQLITE_ROW)
4071 {
4072 sqlite3_int64 edge_id = sqlite3_column_int64 (stmt_in, 0);
4073 /* reporting the error */
4074 sqlite3_reset (stmt);
4075 sqlite3_clear_bindings (stmt);
4076 sqlite3_bind_text (stmt, 1, "edge not simple", -1,
4077 SQLITE_STATIC);
4078 sqlite3_bind_int64 (stmt, 2, edge_id);
4079 sqlite3_bind_null (stmt, 3);
4080 ret = sqlite3_step (stmt);
4081 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
4082 ;
4083 else
4084 {
4085 char *msg =
4086 sqlite3_mprintf
4087 ("ST_ValidateTopoGeo() insert #3 error: \"%s\"",
4088 sqlite3_errmsg (topo->db_handle));
4089 gaiatopo_set_last_error_msg (accessor, msg);
4090 sqlite3_free (msg);
4091 goto error;
4092 }
4093 }
4094 else
4095 {
4096 char *msg =
4097 sqlite3_mprintf
4098 ("ST_ValidateTopoGeo() - NonSimpleEdge step error: %s",
4099 sqlite3_errmsg (topo->db_handle));
4100 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
4101 msg);
4102 sqlite3_free (msg);
4103 goto error;
4104 }
4105 }
4106 sqlite3_finalize (stmt_in);
4107
4108 return 1;
4109
4110 error:
4111 if (stmt_in == NULL)
4112 sqlite3_finalize (stmt_in);
4113 return 0;
4114 }
4115
4116 static int
do_topo_check_edge_edge(GaiaTopologyAccessorPtr accessor,sqlite3_stmt * stmt)4117 do_topo_check_edge_edge (GaiaTopologyAccessorPtr accessor, sqlite3_stmt * stmt)
4118 {
4119 /* checking for edge-edge crossing */
4120 char *sql;
4121 char *table;
4122 char *xtable;
4123 int ret;
4124 sqlite3_stmt *stmt_in = NULL;
4125 struct gaia_topology *topo = (struct gaia_topology *) accessor;
4126
4127 table = sqlite3_mprintf ("%s_edge", topo->topology_name);
4128 xtable = gaiaDoubleQuotedSql (table);
4129 /*
4130 sql =
4131 sqlite3_mprintf ("SELECT e1.edge_id, e2.edge_id FROM MAIN.\"%s\" AS e1 "
4132 "JOIN MAIN.\"%s\" AS e2 ON (e1.edge_id <> e2.edge_id AND "
4133 "ST_Crosses(e1.geom, e2.geom) = 1 AND e2.edge_id IN "
4134 "(SELECT rowid FROM SpatialIndex WHERE f_table_name = %Q AND "
4135 "f_geometry_column = 'geom' AND search_frame = e1.geom))",
4136 xtable, xtable, table);
4137 */
4138 sql =
4139 sqlite3_mprintf ("SELECT e1.edge_id, e2.edge_id FROM MAIN.\"%s\" AS e1 "
4140 "JOIN MAIN.\"%s\" AS e2 ON (e1.edge_id <> e2.edge_id AND "
4141 "ST_RelateMatch(ST_Relate(e1.geom, e2.geom), '0******0*') = 1 AND e2.edge_id IN "
4142 "(SELECT rowid FROM SpatialIndex WHERE f_table_name = %Q AND "
4143 "f_geometry_column = 'geom' AND search_frame = e1.geom))",
4144 xtable, xtable, table);
4145 sqlite3_free (table);
4146 free (xtable);
4147 ret =
4148 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
4149 sqlite3_free (sql);
4150 if (ret != SQLITE_OK)
4151 {
4152 char *msg =
4153 sqlite3_mprintf
4154 ("ST_ValidateTopoGeo() - EdgeCrossesEdge error: \"%s\"",
4155 sqlite3_errmsg (topo->db_handle));
4156 gaiatopo_set_last_error_msg (accessor, msg);
4157 sqlite3_free (msg);
4158 goto error;
4159 }
4160
4161 sqlite3_reset (stmt_in);
4162 sqlite3_clear_bindings (stmt_in);
4163 while (1)
4164 {
4165 /* scrolling the result set rows */
4166 ret = sqlite3_step (stmt_in);
4167 if (ret == SQLITE_DONE)
4168 break; /* end of result set */
4169 if (ret == SQLITE_ROW)
4170 {
4171 sqlite3_int64 edge_id1 = sqlite3_column_int64 (stmt_in, 0);
4172 sqlite3_int64 edge_id2 = sqlite3_column_int64 (stmt_in, 1);
4173 /* reporting the error */
4174 sqlite3_reset (stmt);
4175 sqlite3_clear_bindings (stmt);
4176 sqlite3_bind_text (stmt, 1, "edge crosses edge", -1,
4177 SQLITE_STATIC);
4178 sqlite3_bind_int64 (stmt, 2, edge_id1);
4179 sqlite3_bind_int64 (stmt, 3, edge_id2);
4180 ret = sqlite3_step (stmt);
4181 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
4182 ;
4183 else
4184 {
4185 char *msg =
4186 sqlite3_mprintf
4187 ("ST_ValidateTopoGeo() insert #4 error: \"%s\"",
4188 sqlite3_errmsg (topo->db_handle));
4189 gaiatopo_set_last_error_msg (accessor, msg);
4190 sqlite3_free (msg);
4191 goto error;
4192 }
4193 }
4194 else
4195 {
4196 char *msg =
4197 sqlite3_mprintf
4198 ("ST_ValidateTopoGeo() - EdgeCrossesEdge step error: %s",
4199 sqlite3_errmsg (topo->db_handle));
4200 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
4201 msg);
4202 sqlite3_free (msg);
4203 goto error;
4204 }
4205 }
4206 sqlite3_finalize (stmt_in);
4207
4208 return 1;
4209
4210 error:
4211 if (stmt_in == NULL)
4212 sqlite3_finalize (stmt_in);
4213 return 0;
4214 }
4215
4216 static int
do_topo_check_start_nodes(GaiaTopologyAccessorPtr accessor,sqlite3_stmt * stmt)4217 do_topo_check_start_nodes (GaiaTopologyAccessorPtr accessor,
4218 sqlite3_stmt * stmt)
4219 {
4220 /* checking for edges mismatching start nodes */
4221 char *sql;
4222 char *table;
4223 char *xtable1;
4224 char *xtable2;
4225 int ret;
4226 sqlite3_stmt *stmt_in = NULL;
4227 struct gaia_topology *topo = (struct gaia_topology *) accessor;
4228
4229 table = sqlite3_mprintf ("%s_edge", topo->topology_name);
4230 xtable1 = gaiaDoubleQuotedSql (table);
4231 sqlite3_free (table);
4232 table = sqlite3_mprintf ("%s_node", topo->topology_name);
4233 xtable2 = gaiaDoubleQuotedSql (table);
4234 sqlite3_free (table);
4235 sql =
4236 sqlite3_mprintf ("SELECT e.edge_id, e.start_node FROM MAIN.\"%s\" AS e "
4237 "JOIN MAIN.\"%s\" AS n ON (e.start_node = n.node_id) "
4238 "WHERE ST_Disjoint(ST_StartPoint(e.geom), n.geom) = 1",
4239 xtable1, xtable2);
4240 free (xtable1);
4241 free (xtable2);
4242 ret =
4243 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
4244 sqlite3_free (sql);
4245 if (ret != SQLITE_OK)
4246 {
4247 char *msg =
4248 sqlite3_mprintf
4249 ("ST_ValidateTopoGeo() - StartNodes error: \"%s\"",
4250 sqlite3_errmsg (topo->db_handle));
4251 gaiatopo_set_last_error_msg (accessor, msg);
4252 sqlite3_free (msg);
4253 goto error;
4254 }
4255
4256 sqlite3_reset (stmt_in);
4257 sqlite3_clear_bindings (stmt_in);
4258 while (1)
4259 {
4260 /* scrolling the result set rows */
4261 ret = sqlite3_step (stmt_in);
4262 if (ret == SQLITE_DONE)
4263 break; /* end of result set */
4264 if (ret == SQLITE_ROW)
4265 {
4266 sqlite3_int64 edge_id = sqlite3_column_int64 (stmt_in, 0);
4267 sqlite3_int64 node_id = sqlite3_column_int64 (stmt_in, 1);
4268 /* reporting the error */
4269 sqlite3_reset (stmt);
4270 sqlite3_clear_bindings (stmt);
4271 sqlite3_bind_text (stmt, 1, "geometry start mismatch", -1,
4272 SQLITE_STATIC);
4273 sqlite3_bind_int64 (stmt, 2, edge_id);
4274 sqlite3_bind_int64 (stmt, 3, node_id);
4275 ret = sqlite3_step (stmt);
4276 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
4277 ;
4278 else
4279 {
4280 char *msg =
4281 sqlite3_mprintf
4282 ("ST_ValidateTopoGeo() insert #5 error: \"%s\"",
4283 sqlite3_errmsg (topo->db_handle));
4284 gaiatopo_set_last_error_msg (accessor, msg);
4285 sqlite3_free (msg);
4286 goto error;
4287 }
4288 }
4289 else
4290 {
4291 char *msg =
4292 sqlite3_mprintf
4293 ("ST_ValidateTopoGeo() - StartNodes step error: %s",
4294 sqlite3_errmsg (topo->db_handle));
4295 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
4296 msg);
4297 sqlite3_free (msg);
4298 goto error;
4299 }
4300 }
4301 sqlite3_finalize (stmt_in);
4302
4303 return 1;
4304
4305 error:
4306 if (stmt_in == NULL)
4307 sqlite3_finalize (stmt_in);
4308 return 0;
4309 }
4310
4311 static int
do_topo_check_end_nodes(GaiaTopologyAccessorPtr accessor,sqlite3_stmt * stmt)4312 do_topo_check_end_nodes (GaiaTopologyAccessorPtr accessor, sqlite3_stmt * stmt)
4313 {
4314 /* checking for edges mismatching end nodes */
4315 char *sql;
4316 char *table;
4317 char *xtable1;
4318 char *xtable2;
4319 int ret;
4320 sqlite3_stmt *stmt_in = NULL;
4321 struct gaia_topology *topo = (struct gaia_topology *) accessor;
4322
4323 table = sqlite3_mprintf ("%s_edge", topo->topology_name);
4324 xtable1 = gaiaDoubleQuotedSql (table);
4325 sqlite3_free (table);
4326 table = sqlite3_mprintf ("%s_node", topo->topology_name);
4327 xtable2 = gaiaDoubleQuotedSql (table);
4328 sqlite3_free (table);
4329 sql = sqlite3_mprintf ("SELECT e.edge_id, e.end_node FROM MAIN.\"%s\" AS e "
4330 "JOIN MAIN.\"%s\" AS n ON (e.end_node = n.node_id) "
4331 "WHERE ST_Disjoint(ST_EndPoint(e.geom), n.geom) = 1",
4332 xtable1, xtable2);
4333 free (xtable1);
4334 free (xtable2);
4335 ret =
4336 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
4337 sqlite3_free (sql);
4338 if (ret != SQLITE_OK)
4339 {
4340 char *msg =
4341 sqlite3_mprintf ("ST_ValidateTopoGeo() - EndNodes error: \"%s\"",
4342 sqlite3_errmsg (topo->db_handle));
4343 gaiatopo_set_last_error_msg (accessor, msg);
4344 sqlite3_free (msg);
4345 goto error;
4346 }
4347
4348 sqlite3_reset (stmt_in);
4349 sqlite3_clear_bindings (stmt_in);
4350 while (1)
4351 {
4352 /* scrolling the result set rows */
4353 ret = sqlite3_step (stmt_in);
4354 if (ret == SQLITE_DONE)
4355 break; /* end of result set */
4356 if (ret == SQLITE_ROW)
4357 {
4358 sqlite3_int64 edge_id = sqlite3_column_int64 (stmt_in, 0);
4359 sqlite3_int64 node_id = sqlite3_column_int64 (stmt_in, 1);
4360 /* reporting the error */
4361 sqlite3_reset (stmt);
4362 sqlite3_clear_bindings (stmt);
4363 sqlite3_bind_text (stmt, 1, "geometry end mismatch", -1,
4364 SQLITE_STATIC);
4365 sqlite3_bind_int64 (stmt, 2, edge_id);
4366 sqlite3_bind_int64 (stmt, 3, node_id);
4367 ret = sqlite3_step (stmt);
4368 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
4369 ;
4370 else
4371 {
4372 char *msg =
4373 sqlite3_mprintf
4374 ("ST_ValidateTopoGeo() insert #6 error: \"%s\"",
4375 sqlite3_errmsg (topo->db_handle));
4376 gaiatopo_set_last_error_msg (accessor, msg);
4377 sqlite3_free (msg);
4378 goto error;
4379 }
4380 }
4381 else
4382 {
4383 char *msg =
4384 sqlite3_mprintf
4385 ("ST_ValidateTopoGeo() - EndNodes step error: %s",
4386 sqlite3_errmsg (topo->db_handle));
4387 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
4388 msg);
4389 sqlite3_free (msg);
4390 goto error;
4391 }
4392 }
4393 sqlite3_finalize (stmt_in);
4394
4395 return 1;
4396
4397 error:
4398 if (stmt_in == NULL)
4399 sqlite3_finalize (stmt_in);
4400 return 0;
4401 }
4402
4403 static int
do_topo_check_face_no_edges(GaiaTopologyAccessorPtr accessor,sqlite3_stmt * stmt)4404 do_topo_check_face_no_edges (GaiaTopologyAccessorPtr accessor,
4405 sqlite3_stmt * stmt)
4406 {
4407 /* checking for faces with no edges */
4408 char *sql;
4409 char *table;
4410 char *xtable1;
4411 char *xtable2;
4412 int ret;
4413 sqlite3_stmt *stmt_in = NULL;
4414 struct gaia_topology *topo = (struct gaia_topology *) accessor;
4415
4416 table = sqlite3_mprintf ("%s_face", topo->topology_name);
4417 xtable1 = gaiaDoubleQuotedSql (table);
4418 sqlite3_free (table);
4419 table = sqlite3_mprintf ("%s_edge", topo->topology_name);
4420 xtable2 = gaiaDoubleQuotedSql (table);
4421 sqlite3_free (table);
4422 sql = sqlite3_mprintf ("SELECT f.face_id, Count(e1.edge_id) AS cnt1, "
4423 "Count(e2.edge_id) AS cnt2 FROM MAIN.\"%s\" AS f "
4424 "LEFT JOIN MAIN.\"%s\" AS e1 ON (f.face_id = e1.left_face) "
4425 "LEFT JOIN MAIN.\"%s\" AS e2 ON (f.face_id = e2.right_face) "
4426 "GROUP BY f.face_id HAVING cnt1 = 0 AND cnt2 = 0",
4427 xtable1, xtable2, xtable2);
4428 free (xtable1);
4429 free (xtable2);
4430 ret =
4431 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
4432 sqlite3_free (sql);
4433 if (ret != SQLITE_OK)
4434 {
4435 char *msg =
4436 sqlite3_mprintf
4437 ("ST_ValidateTopoGeo() - FaceNoEdges error: \"%s\"",
4438 sqlite3_errmsg (topo->db_handle));
4439 gaiatopo_set_last_error_msg (accessor, msg);
4440 sqlite3_free (msg);
4441 goto error;
4442 }
4443
4444 sqlite3_reset (stmt_in);
4445 sqlite3_clear_bindings (stmt_in);
4446 while (1)
4447 {
4448 /* scrolling the result set rows */
4449 ret = sqlite3_step (stmt_in);
4450 if (ret == SQLITE_DONE)
4451 break; /* end of result set */
4452 if (ret == SQLITE_ROW)
4453 {
4454 sqlite3_int64 face_id = sqlite3_column_int64 (stmt_in, 0);
4455 /* reporting the error */
4456 sqlite3_reset (stmt);
4457 sqlite3_clear_bindings (stmt);
4458 sqlite3_bind_text (stmt, 1, "face without edges", -1,
4459 SQLITE_STATIC);
4460 sqlite3_bind_int64 (stmt, 2, face_id);
4461 sqlite3_bind_null (stmt, 3);
4462 ret = sqlite3_step (stmt);
4463 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
4464 ;
4465 else
4466 {
4467 char *msg =
4468 sqlite3_mprintf
4469 ("ST_ValidateTopoGeo() insert #7 error: \"%s\"",
4470 sqlite3_errmsg (topo->db_handle));
4471 gaiatopo_set_last_error_msg (accessor, msg);
4472 sqlite3_free (msg);
4473 goto error;
4474 }
4475 }
4476 else
4477 {
4478 char *msg =
4479 sqlite3_mprintf
4480 ("ST_ValidateTopoGeo() - FaceNoEdges step error: %s",
4481 sqlite3_errmsg (topo->db_handle));
4482 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
4483 msg);
4484 sqlite3_free (msg);
4485 goto error;
4486 }
4487 }
4488 sqlite3_finalize (stmt_in);
4489
4490 return 1;
4491
4492 error:
4493 if (stmt_in == NULL)
4494 sqlite3_finalize (stmt_in);
4495 return 0;
4496 }
4497
4498 static int
do_topo_check_no_universal_face(GaiaTopologyAccessorPtr accessor,sqlite3_stmt * stmt)4499 do_topo_check_no_universal_face (GaiaTopologyAccessorPtr accessor,
4500 sqlite3_stmt * stmt)
4501 {
4502 /* checking for missing universal face */
4503 char *sql;
4504 char *table;
4505 char *xtable;
4506 int ret;
4507 int i;
4508 char **results;
4509 int rows;
4510 int columns;
4511 char *errMsg = NULL;
4512 int count = 0;
4513 struct gaia_topology *topo = (struct gaia_topology *) accessor;
4514
4515 table = sqlite3_mprintf ("%s_face", topo->topology_name);
4516 xtable = gaiaDoubleQuotedSql (table);
4517 sqlite3_free (table);
4518 sql =
4519 sqlite3_mprintf ("SELECT Count(*) FROM MAIN.\"%s\" WHERE face_id = 0",
4520 xtable);
4521 free (xtable);
4522 ret =
4523 sqlite3_get_table (topo->db_handle, sql, &results, &rows, &columns,
4524 &errMsg);
4525 sqlite3_free (sql);
4526 if (ret != SQLITE_OK)
4527 {
4528 sqlite3_free (errMsg);
4529 return 0;
4530 }
4531 for (i = 1; i <= rows; i++)
4532 {
4533 count = atoi (results[(i * columns) + 0]);
4534 }
4535 sqlite3_free_table (results);
4536
4537 if (count <= 0)
4538 {
4539 /* reporting the error */
4540 sqlite3_reset (stmt);
4541 sqlite3_clear_bindings (stmt);
4542 sqlite3_bind_text (stmt, 1, "no universal face", -1, SQLITE_STATIC);
4543 sqlite3_bind_null (stmt, 2);
4544 sqlite3_bind_null (stmt, 3);
4545 ret = sqlite3_step (stmt);
4546 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
4547 ;
4548 else
4549 {
4550 char *msg =
4551 sqlite3_mprintf
4552 ("ST_ValidateTopoGeo() insert #8 error: \"%s\"",
4553 sqlite3_errmsg (topo->db_handle));
4554 gaiatopo_set_last_error_msg (accessor, msg);
4555 sqlite3_free (msg);
4556 return 0;
4557 }
4558 }
4559
4560 return 1;
4561 }
4562
4563 static int
do_topo_check_create_aux_faces(GaiaTopologyAccessorPtr accessor)4564 do_topo_check_create_aux_faces (GaiaTopologyAccessorPtr accessor)
4565 {
4566 /* creating the aux-Face temp table */
4567 char *table;
4568 char *xtable;
4569 char *sql;
4570 char *errMsg;
4571 int ret;
4572 #if defined(_WIN32) && !defined(__MINGW32__)
4573 int pid;
4574 #else
4575 pid_t pid;
4576 #endif
4577 struct gaia_topology *topo = (struct gaia_topology *) accessor;
4578
4579 /* creating the aux-face Temp Table */
4580 #if defined(_WIN32) && !defined(__MINGW32__)
4581 pid = _getpid ();
4582 #else
4583 pid = getpid ();
4584 #endif
4585 table = sqlite3_mprintf ("%s_aux_face_%d", topo->topology_name, pid);
4586 xtable = gaiaDoubleQuotedSql (table);
4587 sqlite3_free (table);
4588 sql = sqlite3_mprintf ("CREATE TEMPORARY TABLE \"%s\" (\n"
4589 "\tface_id INTEGER PRIMARY KEY,\n\tgeom BLOB)",
4590 xtable);
4591 free (xtable);
4592 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
4593 sqlite3_free (sql);
4594 if (ret != SQLITE_OK)
4595 {
4596 char *msg =
4597 sqlite3_mprintf ("CREATE TEMPORARY TABLE aux_face - error: %s\n",
4598 errMsg);
4599 sqlite3_free (errMsg);
4600 gaiatopo_set_last_error_msg (accessor, msg);
4601 sqlite3_free (msg);
4602 return 0;
4603 }
4604
4605 /* creating the exotic spatial index */
4606 table = sqlite3_mprintf ("%s_aux_face_%d_rtree", topo->topology_name, pid);
4607 xtable = gaiaDoubleQuotedSql (table);
4608 sqlite3_free (table);
4609 sql = sqlite3_mprintf ("CREATE VIRTUAL TABLE temp.\"%s\" USING RTree "
4610 "(id_face, x_min, x_max, y_min, y_max)", xtable);
4611 free (xtable);
4612 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
4613 sqlite3_free (sql);
4614 if (ret != SQLITE_OK)
4615 {
4616 char *msg =
4617 sqlite3_mprintf ("CREATE TEMPORARY TABLE aux_face - error: %s\n",
4618 errMsg);
4619 sqlite3_free (errMsg);
4620 gaiatopo_set_last_error_msg (accessor, msg);
4621 sqlite3_free (msg);
4622 return 0;
4623 }
4624
4625 return 1;
4626 }
4627
4628 static int
do_topo_check_build_aux_faces(GaiaTopologyAccessorPtr accessor,sqlite3_stmt * stmt)4629 do_topo_check_build_aux_faces (GaiaTopologyAccessorPtr accessor,
4630 sqlite3_stmt * stmt)
4631 {
4632 /* populating the aux-face Temp Table */
4633 char *sql;
4634 char *table;
4635 char *xtable;
4636 int ret;
4637 sqlite3_stmt *stmt_in = NULL;
4638 sqlite3_stmt *stmt_out = NULL;
4639 sqlite3_stmt *stmt_rtree = NULL;
4640 #if defined(_WIN32) && !defined(__MINGW32__)
4641 int pid;
4642 #else
4643 pid_t pid;
4644 #endif
4645 struct gaia_topology *topo = (struct gaia_topology *) accessor;
4646
4647 /* preparing the input SQL statement */
4648 #if defined(_WIN32) && !defined(__MINGW32__)
4649 pid = _getpid ();
4650 #else
4651 pid = getpid ();
4652 #endif
4653 table = sqlite3_mprintf ("%s_face", topo->topology_name);
4654 xtable = gaiaDoubleQuotedSql (table);
4655 sqlite3_free (table);
4656 sql = sqlite3_mprintf ("SELECT face_id, ST_GetFaceGeometry(%Q, face_id) "
4657 "FROM MAIN.\"%s\" WHERE face_id <> 0",
4658 topo->topology_name, xtable);
4659 free (xtable);
4660 ret =
4661 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
4662 sqlite3_free (sql);
4663 if (ret != SQLITE_OK)
4664 {
4665 char *msg =
4666 sqlite3_mprintf
4667 ("ST_ValidateTopoGeo() - GetFaceGeometry error: \"%s\"",
4668 sqlite3_errmsg (topo->db_handle));
4669 gaiatopo_set_last_error_msg (accessor, msg);
4670 sqlite3_free (msg);
4671 goto error;
4672 }
4673
4674 /* preparing the output SQL statement */
4675 table = sqlite3_mprintf ("%s_aux_face_%d", topo->topology_name, pid);
4676 xtable = gaiaDoubleQuotedSql (table);
4677 sqlite3_free (table);
4678 sql =
4679 sqlite3_mprintf
4680 ("INSERT INTO TEMP.\"%s\" (face_id, geom) VALUES (?, ?)", xtable);
4681 free (xtable);
4682 ret =
4683 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_out,
4684 NULL);
4685 sqlite3_free (sql);
4686 if (ret != SQLITE_OK)
4687 {
4688 char *msg =
4689 sqlite3_mprintf ("ST_ValidateTopoGeo() - AuxFace error: \"%s\"",
4690 sqlite3_errmsg (topo->db_handle));
4691 gaiatopo_set_last_error_msg (accessor, msg);
4692 sqlite3_free (msg);
4693 goto error;
4694 }
4695
4696 /* preparing the RTree SQL statement */
4697 table = sqlite3_mprintf ("%s_aux_face_%d_rtree", topo->topology_name, pid);
4698 xtable = gaiaDoubleQuotedSql (table);
4699 sqlite3_free (table);
4700 sql = sqlite3_mprintf ("INSERT INTO TEMP.\"%s\" "
4701 "(id_face, x_min, x_max, y_min, y_max) VALUES (?, ?, ?, ?, ?)",
4702 xtable);
4703 free (xtable);
4704 ret =
4705 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_rtree,
4706 NULL);
4707 sqlite3_free (sql);
4708 if (ret != SQLITE_OK)
4709 {
4710 char *msg =
4711 sqlite3_mprintf
4712 ("ST_ValidateTopoGeo() - AuxFaceRTree error: \"%s\"",
4713 sqlite3_errmsg (topo->db_handle));
4714 gaiatopo_set_last_error_msg (accessor, msg);
4715 sqlite3_free (msg);
4716 goto error;
4717 }
4718
4719 sqlite3_reset (stmt_in);
4720 sqlite3_clear_bindings (stmt_in);
4721 while (1)
4722 {
4723 /* scrolling the result set rows */
4724 ret = sqlite3_step (stmt_in);
4725 if (ret == SQLITE_DONE)
4726 break; /* end of result set */
4727 if (ret == SQLITE_ROW)
4728 {
4729 gaiaGeomCollPtr geom = NULL;
4730 const unsigned char *blob;
4731 int blob_sz;
4732 sqlite3_int64 face_id = sqlite3_column_int64 (stmt_in, 0);
4733 if (sqlite3_column_type (stmt_in, 1) == SQLITE_BLOB)
4734 {
4735 blob = sqlite3_column_blob (stmt_in, 1);
4736 blob_sz = sqlite3_column_bytes (stmt_in, 1);
4737 geom = gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
4738 }
4739 if (geom == NULL)
4740 {
4741 /* reporting the error */
4742 sqlite3_reset (stmt);
4743 sqlite3_clear_bindings (stmt);
4744 sqlite3_bind_text (stmt, 1, "invalid face geometry", -1,
4745 SQLITE_STATIC);
4746 sqlite3_bind_int64 (stmt, 2, face_id);
4747 sqlite3_bind_null (stmt, 3);
4748 ret = sqlite3_step (stmt);
4749 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
4750 ;
4751 else
4752 {
4753 char *msg =
4754 sqlite3_mprintf
4755 ("ST_ValidateTopoGeo() insert #9 error: \"%s\"",
4756 sqlite3_errmsg (topo->db_handle));
4757 gaiatopo_set_last_error_msg (accessor, msg);
4758 sqlite3_free (msg);
4759 goto error;
4760 }
4761 }
4762 else
4763 {
4764 double xmin = geom->MinX;
4765 double xmax = geom->MaxX;
4766 double ymin = geom->MinY;
4767 double ymax = geom->MaxY;
4768 gaiaFreeGeomColl (geom);
4769 /* inserting into AuxFace */
4770 sqlite3_reset (stmt_out);
4771 sqlite3_clear_bindings (stmt_out);
4772 sqlite3_bind_int64 (stmt_out, 1, face_id);
4773 sqlite3_bind_blob (stmt_out, 2, blob, blob_sz,
4774 SQLITE_STATIC);
4775 ret = sqlite3_step (stmt_out);
4776 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
4777 ;
4778 else
4779 {
4780 char *msg =
4781 sqlite3_mprintf
4782 ("ST_ValidateTopoGeo() insert #10 error: \"%s\"",
4783 sqlite3_errmsg (topo->db_handle));
4784 gaiatopo_set_last_error_msg (accessor, msg);
4785 sqlite3_free (msg);
4786 goto error;
4787 }
4788 /* updating the AuxFaceRTree */
4789 sqlite3_reset (stmt_rtree);
4790 sqlite3_clear_bindings (stmt_rtree);
4791 sqlite3_bind_int64 (stmt_rtree, 1, face_id);
4792 sqlite3_bind_double (stmt_rtree, 2, xmin);
4793 sqlite3_bind_double (stmt_rtree, 3, xmax);
4794 sqlite3_bind_double (stmt_rtree, 4, ymin);
4795 sqlite3_bind_double (stmt_rtree, 5, ymax);
4796 ret = sqlite3_step (stmt_rtree);
4797 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
4798 ;
4799 else
4800 {
4801 char *msg =
4802 sqlite3_mprintf
4803 ("ST_ValidateTopoGeo() insert #11 error: \"%s\"",
4804 sqlite3_errmsg (topo->db_handle));
4805 gaiatopo_set_last_error_msg (accessor, msg);
4806 sqlite3_free (msg);
4807 goto error;
4808 }
4809 }
4810 }
4811 else
4812 {
4813 char *msg =
4814 sqlite3_mprintf
4815 ("ST_ValidateTopoGeo() - GetFaceGeometry step error: %s",
4816 sqlite3_errmsg (topo->db_handle));
4817 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
4818 msg);
4819 sqlite3_free (msg);
4820 goto error;
4821 }
4822 }
4823 sqlite3_finalize (stmt_in);
4824 sqlite3_finalize (stmt_out);
4825 sqlite3_finalize (stmt_rtree);
4826
4827 return 1;
4828
4829 error:
4830 if (stmt_in == NULL)
4831 sqlite3_finalize (stmt_in);
4832 if (stmt_out == NULL)
4833 sqlite3_finalize (stmt_out);
4834 if (stmt_rtree == NULL)
4835 sqlite3_finalize (stmt_rtree);
4836 return 0;
4837 }
4838
4839 static int
do_topo_check_overlapping_faces(GaiaTopologyAccessorPtr accessor,sqlite3_stmt * stmt)4840 do_topo_check_overlapping_faces (GaiaTopologyAccessorPtr accessor,
4841 sqlite3_stmt * stmt)
4842 {
4843 /* checking for overlapping faces */
4844 char *sql;
4845 char *table;
4846 char *xtable;
4847 char *rtree;
4848 int ret;
4849 #if defined(_WIN32) && !defined(__MINGW32__)
4850 int pid;
4851 #else
4852 pid_t pid;
4853 #endif
4854 sqlite3_stmt *stmt_in = NULL;
4855 struct gaia_topology *topo = (struct gaia_topology *) accessor;
4856
4857
4858 #if defined(_WIN32) && !defined(__MINGW32__)
4859 pid = _getpid ();
4860 #else
4861 pid = getpid ();
4862 #endif
4863 table = sqlite3_mprintf ("%s_aux_face_%d", topo->topology_name, pid);
4864 xtable = gaiaDoubleQuotedSql (table);
4865 sqlite3_free (table);
4866 table = sqlite3_mprintf ("%s_aux_face_%d_rtree", topo->topology_name, pid);
4867 rtree = gaiaDoubleQuotedSql (table);
4868 sqlite3_free (table);
4869 sql =
4870 sqlite3_mprintf
4871 ("SELECT a.face_id, b.face_id FROM TEMP.\"%s\" AS a, TEMP.\"%s\" AS b "
4872 "WHERE a.geom IS NOT NULL AND a.face_id <> b.face_id AND ST_Overlaps(a.geom, b.geom) = 1 "
4873 "AND b.face_id IN (SELECT id_face FROM TEMP.\"%s\" WHERE x_min <= MbrMaxX(a.geom) "
4874 "AND x_max >= MbrMinX(a.geom) AND y_min <= MbrMaxY(a.geom) AND y_max >= MbrMinY(a.geom))",
4875 xtable, xtable, rtree);
4876 free (xtable);
4877 free (rtree);
4878 ret =
4879 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
4880 sqlite3_free (sql);
4881 if (ret != SQLITE_OK)
4882 {
4883 char *msg =
4884 sqlite3_mprintf
4885 ("ST_ValidateTopoGeo() - OverlappingFaces error: \"%s\"",
4886 sqlite3_errmsg (topo->db_handle));
4887 gaiatopo_set_last_error_msg (accessor, msg);
4888 sqlite3_free (msg);
4889 goto error;
4890 }
4891
4892 sqlite3_reset (stmt_in);
4893 sqlite3_clear_bindings (stmt_in);
4894 while (1)
4895 {
4896 /* scrolling the result set rows */
4897 ret = sqlite3_step (stmt_in);
4898 if (ret == SQLITE_DONE)
4899 break; /* end of result set */
4900 if (ret == SQLITE_ROW)
4901 {
4902 sqlite3_int64 face_id1 = sqlite3_column_int64 (stmt_in, 0);
4903 sqlite3_int64 face_id2 = sqlite3_column_int64 (stmt_in, 1);
4904 /* reporting the error */
4905 sqlite3_reset (stmt);
4906 sqlite3_clear_bindings (stmt);
4907 sqlite3_bind_text (stmt, 1, "face overlaps face", -1,
4908 SQLITE_STATIC);
4909 sqlite3_bind_int64 (stmt, 2, face_id1);
4910 sqlite3_bind_int64 (stmt, 3, face_id2);
4911 ret = sqlite3_step (stmt);
4912 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
4913 ;
4914 else
4915 {
4916 char *msg =
4917 sqlite3_mprintf
4918 ("ST_ValidateTopoGeo() insert #12 error: \"%s\"",
4919 sqlite3_errmsg (topo->db_handle));
4920 gaiatopo_set_last_error_msg (accessor, msg);
4921 sqlite3_free (msg);
4922 goto error;
4923 }
4924 }
4925 else
4926 {
4927 char *msg =
4928 sqlite3_mprintf
4929 ("ST_ValidateTopoGeo() - OverlappingFaces step error: %s",
4930 sqlite3_errmsg (topo->db_handle));
4931 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
4932 msg);
4933 sqlite3_free (msg);
4934 goto error;
4935 }
4936 }
4937 sqlite3_finalize (stmt_in);
4938
4939 return 1;
4940
4941 error:
4942 if (stmt_in == NULL)
4943 sqlite3_finalize (stmt_in);
4944 return 0;
4945 }
4946
4947 static int
do_topo_check_face_within_face(GaiaTopologyAccessorPtr accessor,sqlite3_stmt * stmt)4948 do_topo_check_face_within_face (GaiaTopologyAccessorPtr accessor,
4949 sqlite3_stmt * stmt)
4950 {
4951 /* checking for face-within-face */
4952 char *sql;
4953 char *table;
4954 char *xtable;
4955 char *rtree;
4956 int ret;
4957 #if defined(_WIN32) && !defined(__MINGW32__)
4958 int pid;
4959 #else
4960 pid_t pid;
4961 #endif
4962 sqlite3_stmt *stmt_in = NULL;
4963 struct gaia_topology *topo = (struct gaia_topology *) accessor;
4964
4965
4966 #if defined(_WIN32) && !defined(__MINGW32__)
4967 pid = _getpid ();
4968 #else
4969 pid = getpid ();
4970 #endif
4971 table = sqlite3_mprintf ("%s_aux_face_%d", topo->topology_name, pid);
4972 xtable = gaiaDoubleQuotedSql (table);
4973 sqlite3_free (table);
4974 table = sqlite3_mprintf ("%s_aux_face_%d_rtree", topo->topology_name, pid);
4975 rtree = gaiaDoubleQuotedSql (table);
4976 sqlite3_free (table);
4977 sql =
4978 sqlite3_mprintf
4979 ("SELECT a.face_id, b.face_id FROM TEMP.\"%s\" AS a, TEMP.\"%s\" AS b "
4980 "WHERE a.geom IS NOT NULL AND a.face_id <> b.face_id AND ST_Within(a.geom, b.geom) = 1 "
4981 "AND b.face_id IN (SELECT id_face FROM TEMP.\"%s\" WHERE x_min <= MbrMaxX(a.geom) "
4982 "AND x_max >= MbrMinX(a.geom) AND y_min <= MbrMaxY(a.geom) AND y_max >= MbrMinY(a.geom))",
4983 xtable, xtable, rtree);
4984 free (xtable);
4985 free (rtree);
4986 ret =
4987 sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt_in, NULL);
4988 sqlite3_free (sql);
4989 if (ret != SQLITE_OK)
4990 {
4991 char *msg =
4992 sqlite3_mprintf
4993 ("ST_ValidateTopoGeo() - FaceWithinFace error: \"%s\"",
4994 sqlite3_errmsg (topo->db_handle));
4995 gaiatopo_set_last_error_msg (accessor, msg);
4996 sqlite3_free (msg);
4997 goto error;
4998 }
4999
5000 sqlite3_reset (stmt_in);
5001 sqlite3_clear_bindings (stmt_in);
5002 while (1)
5003 {
5004 /* scrolling the result set rows */
5005 ret = sqlite3_step (stmt_in);
5006 if (ret == SQLITE_DONE)
5007 break; /* end of result set */
5008 if (ret == SQLITE_ROW)
5009 {
5010 sqlite3_int64 face_id1 = sqlite3_column_int64 (stmt_in, 0);
5011 sqlite3_int64 face_id2 = sqlite3_column_int64 (stmt_in, 1);
5012 /* reporting the error */
5013 sqlite3_reset (stmt);
5014 sqlite3_clear_bindings (stmt);
5015 sqlite3_bind_text (stmt, 1, "face within face", -1,
5016 SQLITE_STATIC);
5017 sqlite3_bind_int64 (stmt, 2, face_id1);
5018 sqlite3_bind_int64 (stmt, 3, face_id2);
5019 ret = sqlite3_step (stmt);
5020 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
5021 ;
5022 else
5023 {
5024 char *msg =
5025 sqlite3_mprintf
5026 ("ST_ValidateTopoGeo() insert #13 error: \"%s\"",
5027 sqlite3_errmsg (topo->db_handle));
5028 gaiatopo_set_last_error_msg (accessor, msg);
5029 sqlite3_free (msg);
5030 goto error;
5031 }
5032 }
5033 else
5034 {
5035 char *msg =
5036 sqlite3_mprintf
5037 ("ST_ValidateTopoGeo() - FaceWithinFace step error: %s",
5038 sqlite3_errmsg (topo->db_handle));
5039 gaiatopo_set_last_error_msg ((GaiaTopologyAccessorPtr) topo,
5040 msg);
5041 sqlite3_free (msg);
5042 goto error;
5043 }
5044 }
5045 sqlite3_finalize (stmt_in);
5046
5047 return 1;
5048
5049 error:
5050 if (stmt_in == NULL)
5051 sqlite3_finalize (stmt_in);
5052 return 0;
5053 }
5054
5055 static int
do_topo_check_drop_aux_faces(GaiaTopologyAccessorPtr accessor)5056 do_topo_check_drop_aux_faces (GaiaTopologyAccessorPtr accessor)
5057 {
5058 /* dropping the aux-Face temp table */
5059 char *table;
5060 char *xtable;
5061 char *sql;
5062 char *errMsg;
5063 int ret;
5064 #if defined(_WIN32) && !defined(__MINGW32__)
5065 int pid;
5066 #else
5067 pid_t pid;
5068 #endif
5069 struct gaia_topology *topo = (struct gaia_topology *) accessor;
5070
5071 /* finalizing all prepared Statements */
5072 finalize_all_topo_prepared_stmts (topo->cache);
5073
5074 /* dropping the aux-face Temp Table */
5075 #if defined(_WIN32) && !defined(__MINGW32__)
5076 pid = _getpid ();
5077 #else
5078 pid = getpid ();
5079 #endif
5080 table = sqlite3_mprintf ("%s_aux_face_%d", topo->topology_name, pid);
5081 xtable = gaiaDoubleQuotedSql (table);
5082 sqlite3_free (table);
5083 sql = sqlite3_mprintf ("DROP TABLE TEMP.\"%s\"", xtable);
5084 free (xtable);
5085 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
5086 create_all_topo_prepared_stmts (topo->cache); /* recreating prepared stsms */
5087 sqlite3_free (sql);
5088 if (ret != SQLITE_OK)
5089 {
5090 char *msg = sqlite3_mprintf ("DROP TABLE temp.aux_face - error: %s\n",
5091 errMsg);
5092 sqlite3_free (errMsg);
5093 gaiatopo_set_last_error_msg (accessor, msg);
5094 sqlite3_free (msg);
5095 return 0;
5096 }
5097
5098 /* dropping the aux-face Temp RTree */
5099 table = sqlite3_mprintf ("%s_aux_face_%d_rtree", topo->topology_name, pid);
5100 xtable = gaiaDoubleQuotedSql (table);
5101 sqlite3_free (table);
5102 sql = sqlite3_mprintf ("DROP TABLE TEMP.\"%s\"", xtable);
5103 free (xtable);
5104 ret = sqlite3_exec (topo->db_handle, sql, NULL, NULL, &errMsg);
5105 sqlite3_free (sql);
5106 if (ret != SQLITE_OK)
5107 {
5108 char *msg =
5109 sqlite3_mprintf ("DROP TABLE temp.aux_face_rtree - error: %s\n",
5110 errMsg);
5111 sqlite3_free (errMsg);
5112 gaiatopo_set_last_error_msg (accessor, msg);
5113 sqlite3_free (msg);
5114 return 0;
5115 }
5116
5117 return 1;
5118 }
5119
5120 GAIATOPO_DECLARE int
gaiaValidateTopoGeo(GaiaTopologyAccessorPtr accessor)5121 gaiaValidateTopoGeo (GaiaTopologyAccessorPtr accessor)
5122 {
5123 /* generating a validity report for a given Topology */
5124 char *table;
5125 char *xtable;
5126 char *sql;
5127 int ret;
5128 sqlite3_stmt *stmt = NULL;
5129 struct gaia_topology *topo = (struct gaia_topology *) accessor;
5130 if (topo == NULL)
5131 return 0;
5132
5133 if (!do_check_create_validate_topogeo_table (accessor))
5134 return 0;
5135
5136 table = sqlite3_mprintf ("%s_validate_topogeo", topo->topology_name);
5137 xtable = gaiaDoubleQuotedSql (table);
5138 sqlite3_free (table);
5139 sql =
5140 sqlite3_mprintf
5141 ("INSERT INTO TEMP.\"%s\" (error, primitive1, primitive2) VALUES (?, ?, ?)",
5142 xtable);
5143 free (xtable);
5144 ret = sqlite3_prepare_v2 (topo->db_handle, sql, strlen (sql), &stmt, NULL);
5145 sqlite3_free (sql);
5146 if (ret != SQLITE_OK)
5147 {
5148 char *msg = sqlite3_mprintf ("ST_ValidateTopoGeo error: \"%s\"",
5149 sqlite3_errmsg (topo->db_handle));
5150 gaiatopo_set_last_error_msg (accessor, msg);
5151 sqlite3_free (msg);
5152 goto error;
5153 }
5154
5155 if (!do_topo_check_coincident_nodes (accessor, stmt))
5156 goto error;
5157
5158 if (!do_topo_check_edge_node (accessor, stmt))
5159 goto error;
5160
5161 if (!do_topo_check_non_simple (accessor, stmt))
5162 goto error;
5163
5164 if (!do_topo_check_edge_edge (accessor, stmt))
5165 goto error;
5166
5167 if (!do_topo_check_start_nodes (accessor, stmt))
5168 goto error;
5169
5170 if (!do_topo_check_end_nodes (accessor, stmt))
5171 goto error;
5172
5173 if (!do_topo_check_face_no_edges (accessor, stmt))
5174 goto error;
5175
5176 if (!do_topo_check_no_universal_face (accessor, stmt))
5177 goto error;
5178
5179 if (!do_topo_check_create_aux_faces (accessor))
5180 goto error;
5181
5182 if (!do_topo_check_build_aux_faces (accessor, stmt))
5183 goto error;
5184
5185 if (!do_topo_check_overlapping_faces (accessor, stmt))
5186 goto error;
5187
5188 if (!do_topo_check_face_within_face (accessor, stmt))
5189 goto error;
5190
5191 if (!do_topo_check_drop_aux_faces (accessor))
5192 goto error;
5193
5194 sqlite3_finalize (stmt);
5195 return 1;
5196
5197 error:
5198 if (stmt != NULL)
5199 sqlite3_finalize (stmt);
5200 return 0;
5201 }
5202
5203 GAIATOPO_DECLARE sqlite3_int64
gaiaGetNodeByPoint(GaiaTopologyAccessorPtr accessor,gaiaPointPtr pt,double tolerance)5204 gaiaGetNodeByPoint (GaiaTopologyAccessorPtr accessor, gaiaPointPtr pt,
5205 double tolerance)
5206 {
5207 /* RTT wrapper - GetNodeByPoint */
5208 const RTCTX *ctx = NULL;
5209 struct splite_internal_cache *cache = NULL;
5210 sqlite3_int64 ret;
5211 int has_z = 0;
5212 RTPOINT *rt_pt;
5213 RTPOINTARRAY *pa;
5214 RTPOINT4D point;
5215 struct gaia_topology *topo = (struct gaia_topology *) accessor;
5216 if (topo == NULL)
5217 return 0;
5218
5219 cache = (struct splite_internal_cache *) topo->cache;
5220 if (cache == NULL)
5221 return 0;
5222 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
5223 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
5224 return 0;
5225 ctx = cache->RTTOPO_handle;
5226 if (ctx == NULL)
5227 return 0;
5228
5229 if (pt->DimensionModel == GAIA_XY_Z || pt->DimensionModel == GAIA_XY_Z_M)
5230 has_z = 1;
5231 pa = ptarray_construct (ctx, has_z, 0, 1);
5232 point.x = pt->X;
5233 point.y = pt->Y;
5234 if (has_z)
5235 point.z = pt->Z;
5236 ptarray_set_point4d (ctx, pa, 0, &point);
5237 rt_pt = rtpoint_construct (ctx, topo->srid, NULL, pa);
5238
5239 if (tolerance < 0.0)
5240 tolerance = topo->tolerance; /* using the standard tolerance */
5241
5242 gaiaResetRtTopoMsg (cache);
5243 ret =
5244 rtt_GetNodeByPoint ((RTT_TOPOLOGY *) (topo->rtt_topology), rt_pt,
5245 tolerance);
5246 rtpoint_free (ctx, rt_pt);
5247
5248 return ret;
5249 }
5250
5251 GAIATOPO_DECLARE sqlite3_int64
gaiaGetEdgeByPoint(GaiaTopologyAccessorPtr accessor,gaiaPointPtr pt,double tolerance)5252 gaiaGetEdgeByPoint (GaiaTopologyAccessorPtr accessor, gaiaPointPtr pt,
5253 double tolerance)
5254 {
5255 /* RTT wrapper - GetEdgeByPoint */
5256 const RTCTX *ctx = NULL;
5257 struct splite_internal_cache *cache = NULL;
5258 sqlite3_int64 ret;
5259 int has_z = 0;
5260 RTPOINT *rt_pt;
5261 RTPOINTARRAY *pa;
5262 RTPOINT4D point;
5263 struct gaia_topology *topo = (struct gaia_topology *) accessor;
5264 if (topo == NULL)
5265 return 0;
5266
5267 cache = (struct splite_internal_cache *) topo->cache;
5268 if (cache == NULL)
5269 return 0;
5270 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
5271 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
5272 return 0;
5273 ctx = cache->RTTOPO_handle;
5274 if (ctx == NULL)
5275 return 0;
5276
5277 if (pt->DimensionModel == GAIA_XY_Z || pt->DimensionModel == GAIA_XY_Z_M)
5278 has_z = 1;
5279 pa = ptarray_construct (ctx, has_z, 0, 1);
5280 point.x = pt->X;
5281 point.y = pt->Y;
5282 if (has_z)
5283 point.z = pt->Z;
5284 ptarray_set_point4d (ctx, pa, 0, &point);
5285 rt_pt = rtpoint_construct (ctx, topo->srid, NULL, pa);
5286
5287 if (tolerance < 0.0)
5288 tolerance = topo->tolerance; /* using the standard tolerance */
5289
5290 gaiaResetRtTopoMsg (cache);
5291 ret =
5292 rtt_GetEdgeByPoint ((RTT_TOPOLOGY *) (topo->rtt_topology), rt_pt,
5293 tolerance);
5294 rtpoint_free (ctx, rt_pt);
5295
5296 return ret;
5297 }
5298
5299 GAIATOPO_DECLARE sqlite3_int64
gaiaGetFaceByPoint(GaiaTopologyAccessorPtr accessor,gaiaPointPtr pt,double tolerance)5300 gaiaGetFaceByPoint (GaiaTopologyAccessorPtr accessor, gaiaPointPtr pt,
5301 double tolerance)
5302 {
5303 /* RTT wrapper - GetFaceByPoint */
5304 const RTCTX *ctx = NULL;
5305 struct splite_internal_cache *cache = NULL;
5306 sqlite3_int64 ret;
5307 int has_z = 0;
5308 RTPOINT *rt_pt;
5309 RTPOINTARRAY *pa;
5310 RTPOINT4D point;
5311 struct gaia_topology *topo = (struct gaia_topology *) accessor;
5312 if (topo == NULL)
5313 return 0;
5314
5315 cache = (struct splite_internal_cache *) topo->cache;
5316 if (cache == NULL)
5317 return 0;
5318 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
5319 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
5320 return 0;
5321 ctx = cache->RTTOPO_handle;
5322 if (ctx == NULL)
5323 return 0;
5324
5325 if (pt->DimensionModel == GAIA_XY_Z || pt->DimensionModel == GAIA_XY_Z_M)
5326 has_z = 1;
5327 pa = ptarray_construct (ctx, has_z, 0, 1);
5328 point.x = pt->X;
5329 point.y = pt->Y;
5330 if (has_z)
5331 point.z = pt->Z;
5332 ptarray_set_point4d (ctx, pa, 0, &point);
5333 rt_pt = rtpoint_construct (ctx, topo->srid, NULL, pa);
5334
5335 if (tolerance < 0.0)
5336 tolerance = topo->tolerance; /* using the standard tolerance */
5337
5338 gaiaResetRtTopoMsg (cache);
5339 ret =
5340 rtt_GetFaceByPoint ((RTT_TOPOLOGY *) (topo->rtt_topology), rt_pt,
5341 tolerance);
5342 rtpoint_free (ctx, rt_pt);
5343
5344 return ret;
5345 }
5346
5347 GAIATOPO_DECLARE sqlite3_int64
gaiaTopoGeo_AddPoint(GaiaTopologyAccessorPtr accessor,gaiaPointPtr pt,double tolerance)5348 gaiaTopoGeo_AddPoint (GaiaTopologyAccessorPtr accessor, gaiaPointPtr pt,
5349 double tolerance)
5350 {
5351 /* RTT wrapper - AddPoint */
5352 const RTCTX *ctx = NULL;
5353 struct splite_internal_cache *cache = NULL;
5354 sqlite3_int64 ret;
5355 int has_z = 0;
5356 RTPOINT *rt_pt;
5357 RTPOINTARRAY *pa;
5358 RTPOINT4D point;
5359 struct gaia_topology *topo = (struct gaia_topology *) accessor;
5360 if (topo == NULL)
5361 return 0;
5362
5363 cache = (struct splite_internal_cache *) topo->cache;
5364 if (cache == NULL)
5365 return 0;
5366 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
5367 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
5368 return 0;
5369 ctx = cache->RTTOPO_handle;
5370 if (ctx == NULL)
5371 return 0;
5372
5373 if (pt->DimensionModel == GAIA_XY_Z || pt->DimensionModel == GAIA_XY_Z_M)
5374 has_z = 1;
5375 pa = ptarray_construct (ctx, has_z, 0, 1);
5376 point.x = pt->X;
5377 point.y = pt->Y;
5378 if (has_z)
5379 point.z = pt->Z;
5380 ptarray_set_point4d (ctx, pa, 0, &point);
5381 rt_pt = rtpoint_construct (ctx, topo->srid, NULL, pa);
5382
5383 if (tolerance < 0.0)
5384 tolerance = topo->tolerance; /* using the standard tolerance */
5385
5386 gaiaResetRtTopoMsg (cache);
5387 ret =
5388 rtt_AddPoint ((RTT_TOPOLOGY *) (topo->rtt_topology), rt_pt, tolerance);
5389 rtpoint_free (ctx, rt_pt);
5390
5391 return ret;
5392 }
5393
5394 GAIATOPO_DECLARE int
gaiaTopoGeo_AddLineString(GaiaTopologyAccessorPtr accessor,gaiaLinestringPtr ln,double tolerance,sqlite3_int64 ** edge_ids,int * ids_count)5395 gaiaTopoGeo_AddLineString (GaiaTopologyAccessorPtr accessor,
5396 gaiaLinestringPtr ln, double tolerance,
5397 sqlite3_int64 ** edge_ids, int *ids_count)
5398 {
5399 /* RTT wrapper - AddLinestring */
5400 const RTCTX *ctx = NULL;
5401 struct splite_internal_cache *cache = NULL;
5402 int ret = 0;
5403 RTT_ELEMID *edgeids;
5404 int nedges;
5405 int i;
5406 sqlite3_int64 *ids;
5407 RTLINE *rt_line;
5408 struct gaia_topology *topo = (struct gaia_topology *) accessor;
5409 *edge_ids = NULL;
5410 *ids_count = 0;
5411 if (topo == NULL)
5412 return 0;
5413
5414 cache = (struct splite_internal_cache *) topo->cache;
5415 if (cache == NULL)
5416 return 0;
5417 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
5418 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
5419 return 0;
5420 ctx = cache->RTTOPO_handle;
5421 if (ctx == NULL)
5422 return 0;
5423
5424 rt_line =
5425 gaia_convert_linestring_to_rtline (ctx, ln, topo->srid, topo->has_z);
5426
5427 if (tolerance < 0.0)
5428 tolerance = topo->tolerance; /* using the standard tolerance */
5429
5430 gaiaResetRtTopoMsg (cache);
5431 edgeids =
5432 rtt_AddLine ((RTT_TOPOLOGY *) (topo->rtt_topology), rt_line, tolerance,
5433 &nedges);
5434
5435 rtline_free (ctx, rt_line);
5436 if (edgeids != NULL)
5437 {
5438 ids = malloc (sizeof (sqlite3_int64) * nedges);
5439 for (i = 0; i < nedges; i++)
5440 ids[i] = edgeids[i];
5441 *edge_ids = ids;
5442 *ids_count = nedges;
5443 ret = 1;
5444 rtfree (ctx, edgeids);
5445 }
5446 return ret;
5447 }
5448
5449 GAIATOPO_DECLARE int
gaiaTopoGeo_AddLineStringNoFace(GaiaTopologyAccessorPtr accessor,gaiaLinestringPtr ln,double tolerance,sqlite3_int64 ** edge_ids,int * ids_count)5450 gaiaTopoGeo_AddLineStringNoFace (GaiaTopologyAccessorPtr accessor,
5451 gaiaLinestringPtr ln, double tolerance,
5452 sqlite3_int64 ** edge_ids, int *ids_count)
5453 {
5454 /* RTT wrapper - AddLinestring NO FACE */
5455 const RTCTX *ctx = NULL;
5456 struct splite_internal_cache *cache = NULL;
5457 int ret = 0;
5458 RTT_ELEMID *edgeids;
5459 int nedges;
5460 int i;
5461 sqlite3_int64 *ids;
5462 RTLINE *rt_line;
5463 struct gaia_topology *topo = (struct gaia_topology *) accessor;
5464 *edge_ids = NULL;
5465 *ids_count = 0;
5466 if (topo == NULL)
5467 return 0;
5468
5469 cache = (struct splite_internal_cache *) topo->cache;
5470 if (cache == NULL)
5471 return 0;
5472 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
5473 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
5474 return 0;
5475 ctx = cache->RTTOPO_handle;
5476 if (ctx == NULL)
5477 return 0;
5478
5479 rt_line =
5480 gaia_convert_linestring_to_rtline (ctx, ln, topo->srid, topo->has_z);
5481
5482 if (tolerance < 0.0)
5483 tolerance = topo->tolerance; /* using the standard tolerance */
5484
5485 gaiaResetRtTopoMsg (cache);
5486 edgeids =
5487 rtt_AddLineNoFace ((RTT_TOPOLOGY *) (topo->rtt_topology), rt_line,
5488 tolerance, &nedges);
5489
5490 rtline_free (ctx, rt_line);
5491 if (edgeids != NULL)
5492 {
5493 ids = malloc (sizeof (sqlite3_int64) * nedges);
5494 for (i = 0; i < nedges; i++)
5495 ids[i] = edgeids[i];
5496 *edge_ids = ids;
5497 *ids_count = nedges;
5498 ret = 1;
5499 rtfree (ctx, edgeids);
5500 }
5501 return ret;
5502 }
5503
5504 GAIATOPO_DECLARE int
gaiaTopoGeo_Polygonize(GaiaTopologyAccessorPtr accessor)5505 gaiaTopoGeo_Polygonize (GaiaTopologyAccessorPtr accessor)
5506 {
5507 /* RTT wrapper - Determine and register all topology faces */
5508 const RTCTX *ctx = NULL;
5509 struct splite_internal_cache *cache = NULL;
5510 struct gaia_topology *topo = (struct gaia_topology *) accessor;
5511 if (topo == NULL)
5512 return 0;
5513
5514 cache = (struct splite_internal_cache *) topo->cache;
5515 if (cache == NULL)
5516 return 0;
5517 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
5518 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
5519 return 0;
5520 ctx = cache->RTTOPO_handle;
5521 if (ctx == NULL)
5522 return 0;
5523
5524 gaiaResetRtTopoMsg (cache);
5525 if (rtt_Polygonize ((RTT_TOPOLOGY *) (topo->rtt_topology)) == 0)
5526 return 1;
5527 return 0;
5528 }
5529
5530 GAIATOPO_DECLARE gaiaGeomCollPtr
gaiaTopoSnap(GaiaTopologyAccessorPtr accessor,gaiaGeomCollPtr geom,double tolerance_snap,double tolerance_removal,int iterate)5531 gaiaTopoSnap (GaiaTopologyAccessorPtr accessor, gaiaGeomCollPtr geom,
5532 double tolerance_snap, double tolerance_removal, int iterate)
5533 {
5534 /* RTT wrapper - TopoSnap */
5535 const RTCTX *ctx = NULL;
5536 struct splite_internal_cache *cache = NULL;
5537 RTGEOM *input = NULL;
5538 RTGEOM *result = NULL;
5539 gaiaGeomCollPtr output;
5540 struct gaia_topology *topo = (struct gaia_topology *) accessor;
5541 if (topo == NULL)
5542 return 0;
5543
5544 cache = (struct splite_internal_cache *) topo->cache;
5545 if (cache == NULL)
5546 return NULL;
5547 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
5548 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
5549 return NULL;
5550 ctx = cache->RTTOPO_handle;
5551 if (ctx == NULL)
5552 return NULL;
5553 if (!geom)
5554 return NULL;
5555
5556 input = toRTGeom (ctx, geom);
5557 if (!input)
5558 return NULL;
5559
5560 if (tolerance_snap < 0.0)
5561 tolerance_snap = topo->tolerance;
5562
5563 result =
5564 rtt_tpsnap ((RTT_TOPOLOGY *) (topo->rtt_topology), input,
5565 tolerance_snap, tolerance_removal, iterate);
5566 rtgeom_free (ctx, input);
5567 if (result == NULL)
5568 return NULL;
5569
5570 /* converting the result as a Gaia Geometry */
5571 output = fromRTGeom (ctx, result, geom->DimensionModel, geom->DeclaredType);
5572 output->Srid = geom->Srid;
5573 rtgeom_free (ctx, result);
5574 return output;
5575 }
5576
5577 GAIATOPO_DECLARE int
gaiaTopoGeo_AddPolygon(GaiaTopologyAccessorPtr accessor,gaiaPolygonPtr pg,double tolerance,sqlite3_int64 ** face_ids,int * ids_count)5578 gaiaTopoGeo_AddPolygon (GaiaTopologyAccessorPtr accessor, gaiaPolygonPtr pg,
5579 double tolerance, sqlite3_int64 ** face_ids,
5580 int *ids_count)
5581 {
5582 /* RTT wrapper - AddPolygon */
5583 const RTCTX *ctx = NULL;
5584 struct splite_internal_cache *cache = NULL;
5585 int ret = 0;
5586 RTT_ELEMID *faceids;
5587 int nfaces;
5588 int i;
5589 sqlite3_int64 *ids;
5590 RTPOLY *rt_polyg;
5591 struct gaia_topology *topo = (struct gaia_topology *) accessor;
5592 if (topo == NULL)
5593 return 0;
5594
5595 cache = (struct splite_internal_cache *) topo->cache;
5596 if (cache == NULL)
5597 return 0;
5598 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
5599 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
5600 return 0;
5601 ctx = cache->RTTOPO_handle;
5602 if (ctx == NULL)
5603 return 0;
5604
5605 rt_polyg =
5606 gaia_convert_polygon_to_rtpoly (ctx, pg, topo->srid, topo->has_z);
5607
5608 gaiaResetRtTopoMsg (cache);
5609 faceids =
5610 rtt_AddPolygon ((RTT_TOPOLOGY *) (topo->rtt_topology), rt_polyg,
5611 tolerance, &nfaces);
5612
5613 rtpoly_free (ctx, rt_polyg);
5614 if (faceids != NULL)
5615 {
5616 ids = malloc (sizeof (sqlite3_int64) * nfaces);
5617 for (i = 0; i < nfaces; i++)
5618 ids[i] = faceids[i];
5619 *face_ids = ids;
5620 *ids_count = nfaces;
5621 ret = 1;
5622 rtfree (ctx, faceids);
5623 }
5624 return ret;
5625 }
5626
5627 static void
do_split_line(gaiaGeomCollPtr geom,gaiaDynamicLinePtr dyn)5628 do_split_line (gaiaGeomCollPtr geom, gaiaDynamicLinePtr dyn)
5629 {
5630 /* inserting a new linestring into the collection of split lines */
5631 int points = 0;
5632 int iv = 0;
5633 gaiaPointPtr pt;
5634 gaiaLinestringPtr ln;
5635
5636 pt = dyn->First;
5637 while (pt != NULL)
5638 {
5639 /* counting how many points */
5640 points++;
5641 pt = pt->Next;
5642 }
5643
5644 ln = gaiaAddLinestringToGeomColl (geom, points);
5645 pt = dyn->First;
5646 while (pt != NULL)
5647 {
5648 /* copying all points */
5649 if (ln->DimensionModel == GAIA_XY_Z)
5650 {
5651 gaiaSetPointXYZ (ln->Coords, iv, pt->X, pt->Y, pt->Z);
5652 }
5653 else if (ln->DimensionModel == GAIA_XY_M)
5654 {
5655 gaiaSetPointXYM (ln->Coords, iv, pt->X, pt->Y, pt->M);
5656 }
5657 else if (ln->DimensionModel == GAIA_XY_Z_M)
5658 {
5659 gaiaSetPointXYZM (ln->Coords, iv, pt->X, pt->Y, pt->Z, pt->M);
5660 }
5661 else
5662 {
5663 gaiaSetPoint (ln->Coords, iv, pt->X, pt->Y);
5664 }
5665 iv++;
5666 pt = pt->Next;
5667 }
5668 }
5669
5670 static void
do_geom_split_line(gaiaGeomCollPtr geom,gaiaLinestringPtr in,int line_max_points,double max_length)5671 do_geom_split_line (gaiaGeomCollPtr geom, gaiaLinestringPtr in,
5672 int line_max_points, double max_length)
5673 {
5674 /* splitting a Linestring into a collection of shorter Linestrings */
5675 int iv;
5676 int count = 0;
5677 int split = 0;
5678 double tot_length = 0.0;
5679 gaiaDynamicLinePtr dyn = gaiaAllocDynamicLine ();
5680
5681 for (iv = 0; iv < in->Points; iv++)
5682 {
5683 /* consuming all Points from the input Linestring */
5684 double ox;
5685 double oy;
5686 double x;
5687 double y;
5688 double z = 0.0;
5689 double m = 0.0;
5690 if (in->DimensionModel == GAIA_XY_Z)
5691 {
5692 gaiaGetPointXYZ (in->Coords, iv, &x, &y, &z);
5693 }
5694 else if (in->DimensionModel == GAIA_XY_M)
5695 {
5696 gaiaGetPointXYM (in->Coords, iv, &x, &y, &m);
5697 }
5698 else if (in->DimensionModel == GAIA_XY_Z_M)
5699 {
5700 gaiaGetPointXYZM (in->Coords, iv, &x, &y, &z, &m);
5701 }
5702 else
5703 {
5704 gaiaGetPoint (in->Coords, iv, &x, &y);
5705 }
5706
5707 split = 0;
5708 if (max_length > 0.0)
5709 {
5710 if (tot_length > max_length)
5711 split = 1;
5712 }
5713 if (line_max_points > 0)
5714 {
5715 if (count == line_max_points)
5716 split = 1;
5717 }
5718 if (split && count >= 2)
5719 {
5720 /* line break */
5721 double oz;
5722 double om;
5723 ox = dyn->Last->X;
5724 oy = dyn->Last->Y;
5725 if (in->DimensionModel == GAIA_XY_Z
5726 || in->DimensionModel == GAIA_XY_Z_M)
5727 oz = dyn->Last->Z;
5728 if (in->DimensionModel == GAIA_XY_M
5729 || in->DimensionModel == GAIA_XY_Z_M)
5730 om = dyn->Last->M;
5731 do_split_line (geom, dyn);
5732 gaiaFreeDynamicLine (dyn);
5733 dyn = gaiaAllocDynamicLine ();
5734 /* reinserting the last point */
5735 if (in->DimensionModel == GAIA_XY_Z)
5736 gaiaAppendPointZToDynamicLine (dyn, ox, oy, oz);
5737 else if (in->DimensionModel == GAIA_XY_M)
5738 gaiaAppendPointMToDynamicLine (dyn, ox, oy, om);
5739 else if (in->DimensionModel == GAIA_XY_Z_M)
5740 gaiaAppendPointZMToDynamicLine (dyn, ox, oy, oz, om);
5741 else
5742 gaiaAppendPointToDynamicLine (dyn, ox, oy);
5743 count = 1;
5744 tot_length = 0.0;
5745 }
5746
5747 /* inserting a point */
5748 if (in->DimensionModel == GAIA_XY_Z)
5749 gaiaAppendPointZToDynamicLine (dyn, x, y, z);
5750 else if (in->DimensionModel == GAIA_XY_M)
5751 gaiaAppendPointMToDynamicLine (dyn, x, y, m);
5752 else if (in->DimensionModel == GAIA_XY_Z_M)
5753 gaiaAppendPointZMToDynamicLine (dyn, x, y, z, m);
5754 else
5755 gaiaAppendPointToDynamicLine (dyn, x, y);
5756 if (count > 0)
5757 {
5758 if (max_length > 0.0)
5759 {
5760 double dist =
5761 sqrt (((ox - x) * (ox - x)) + ((oy - y) * (oy - y)));
5762 tot_length += dist;
5763 }
5764 }
5765 ox = x;
5766 oy = y;
5767 count++;
5768 }
5769
5770 if (dyn->First != NULL)
5771 {
5772 /* flushing the last Line */
5773 do_split_line (geom, dyn);
5774 }
5775 gaiaFreeDynamicLine (dyn);
5776 }
5777
5778 static gaiaGeomCollPtr
do_linearize(gaiaGeomCollPtr geom)5779 do_linearize (gaiaGeomCollPtr geom)
5780 {
5781 /* attempts to transform Polygon Rings into a (multi)linestring */
5782 gaiaGeomCollPtr result;
5783 gaiaLinestringPtr new_ln;
5784 gaiaPolygonPtr pg;
5785 gaiaRingPtr rng;
5786 int iv;
5787 int ib;
5788 double x;
5789 double y;
5790 double m;
5791 double z;
5792 if (!geom)
5793 return NULL;
5794
5795 if (geom->DimensionModel == GAIA_XY_Z_M)
5796 result = gaiaAllocGeomCollXYZM ();
5797 else if (geom->DimensionModel == GAIA_XY_Z)
5798 result = gaiaAllocGeomCollXYZ ();
5799 else if (geom->DimensionModel == GAIA_XY_M)
5800 result = gaiaAllocGeomCollXYM ();
5801 else
5802 result = gaiaAllocGeomColl ();
5803 result->Srid = geom->Srid;
5804
5805 pg = geom->FirstPolygon;
5806 while (pg)
5807 {
5808 /* dissolving any POLYGON as simple LINESTRINGs (rings) */
5809 rng = pg->Exterior;
5810 new_ln = gaiaAddLinestringToGeomColl (result, rng->Points);
5811 for (iv = 0; iv < rng->Points; iv++)
5812 {
5813 /* copying the EXTERIOR RING as LINESTRING */
5814 if (geom->DimensionModel == GAIA_XY_Z_M)
5815 {
5816 gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
5817 gaiaSetPointXYZM (new_ln->Coords, iv, x, y, z, m);
5818 }
5819 else if (geom->DimensionModel == GAIA_XY_Z)
5820 {
5821 gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
5822 gaiaSetPointXYZ (new_ln->Coords, iv, x, y, z);
5823 }
5824 else if (geom->DimensionModel == GAIA_XY_M)
5825 {
5826 gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
5827 gaiaSetPointXYM (new_ln->Coords, iv, x, y, m);
5828 }
5829 else
5830 {
5831 gaiaGetPoint (rng->Coords, iv, &x, &y);
5832 gaiaSetPoint (new_ln->Coords, iv, x, y);
5833 }
5834 }
5835 for (ib = 0; ib < pg->NumInteriors; ib++)
5836 {
5837 rng = pg->Interiors + ib;
5838 new_ln = gaiaAddLinestringToGeomColl (result, rng->Points);
5839 for (iv = 0; iv < rng->Points; iv++)
5840 {
5841 /* copying an INTERIOR RING as LINESTRING */
5842 if (geom->DimensionModel == GAIA_XY_Z_M)
5843 {
5844 gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
5845 gaiaSetPointXYZM (new_ln->Coords, iv, x, y, z, m);
5846 }
5847 else if (geom->DimensionModel == GAIA_XY_Z)
5848 {
5849 gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
5850 gaiaSetPointXYZ (new_ln->Coords, iv, x, y, z);
5851 }
5852 else if (geom->DimensionModel == GAIA_XY_M)
5853 {
5854 gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
5855 gaiaSetPointXYM (new_ln->Coords, iv, x, y, m);
5856 }
5857 else
5858 {
5859 gaiaGetPoint (rng->Coords, iv, &x, &y);
5860 gaiaSetPoint (new_ln->Coords, iv, x, y);
5861 }
5862 }
5863 }
5864 pg = pg->Next;
5865 }
5866 if (result->FirstLinestring == NULL)
5867 {
5868 gaiaFreeGeomColl (result);
5869 return NULL;
5870 }
5871 return result;
5872 }
5873
5874 GAIATOPO_DECLARE gaiaGeomCollPtr
gaiaTopoGeo_SubdivideLines(gaiaGeomCollPtr geom,int line_max_points,double max_length)5875 gaiaTopoGeo_SubdivideLines (gaiaGeomCollPtr geom, int line_max_points,
5876 double max_length)
5877 {
5878 /* subdividing a (multi)Linestring into a collection of simpler Linestrings */
5879 gaiaLinestringPtr ln;
5880 gaiaGeomCollPtr result;
5881
5882 if (geom == NULL)
5883 return NULL;
5884
5885 if (geom->FirstPoint != NULL)
5886 return NULL;
5887 if (geom->FirstLinestring == NULL && geom->FirstPolygon != NULL)
5888 return NULL;
5889
5890 if (geom->DimensionModel == GAIA_XY_Z)
5891 result = gaiaAllocGeomCollXYZ ();
5892 else if (geom->DimensionModel == GAIA_XY_M)
5893 result = gaiaAllocGeomCollXYM ();
5894 else if (geom->DimensionModel == GAIA_XY_Z_M)
5895 result = gaiaAllocGeomCollXYZM ();
5896 else
5897 result = gaiaAllocGeomColl ();
5898 result->Srid = geom->Srid;
5899 result->DeclaredType = GAIA_MULTILINESTRING;
5900 ln = geom->FirstLinestring;
5901 while (ln != NULL)
5902 {
5903 do_geom_split_line (result, ln, line_max_points, max_length);
5904 ln = ln->Next;
5905 }
5906
5907 if (geom->FirstPolygon != NULL)
5908 {
5909 /* transforming all Polygon Rings into Linestrings */
5910 gaiaGeomCollPtr pg_rings = do_linearize (geom);
5911 if (pg_rings != NULL)
5912 {
5913 ln = pg_rings->FirstLinestring;
5914 while (ln != NULL)
5915 {
5916 do_geom_split_line (result, ln, line_max_points,
5917 max_length);
5918 ln = ln->Next;
5919 }
5920 gaiaFreeGeomColl (pg_rings);
5921 }
5922 }
5923 return result;
5924 }
5925
5926 static gaiaGeomCollPtr
do_build_failing_point(int srid,int dims,gaiaPointPtr pt)5927 do_build_failing_point (int srid, int dims, gaiaPointPtr pt)
5928 {
5929 /* building a Point geometry */
5930 gaiaGeomCollPtr geom;
5931 if (dims == GAIA_XY_Z)
5932 geom = gaiaAllocGeomCollXYZ ();
5933 else if (dims == GAIA_XY_M)
5934 geom = gaiaAllocGeomCollXYM ();
5935 else if (dims == GAIA_XY_Z_M)
5936 geom = gaiaAllocGeomCollXYZM ();
5937 else
5938 geom = gaiaAllocGeomColl ();
5939 geom->Srid = srid;
5940 if (dims == GAIA_XY_Z)
5941 gaiaAddPointToGeomCollXYZ (geom, pt->X, pt->Y, pt->Z);
5942 else if (geom->DimensionModel == GAIA_XY_M)
5943 gaiaAddPointToGeomCollXYM (geom, pt->X, pt->Y, pt->M);
5944 else if (geom->DimensionModel == GAIA_XY_Z_M)
5945 gaiaAddPointToGeomCollXYZM (geom, pt->X, pt->Y, pt->Z, pt->M);
5946 else
5947 gaiaAddPointToGeomColl (geom, pt->X, pt->Y);
5948 return geom;
5949 }
5950
5951 static gaiaGeomCollPtr
do_build_failing_line(int srid,int dims,gaiaLinestringPtr line)5952 do_build_failing_line (int srid, int dims, gaiaLinestringPtr line)
5953 {
5954 /* building a Linestring geometry */
5955 gaiaGeomCollPtr geom;
5956 gaiaLinestringPtr ln;
5957 if (dims == GAIA_XY_Z)
5958 geom = gaiaAllocGeomCollXYZ ();
5959 else if (dims == GAIA_XY_M)
5960 geom = gaiaAllocGeomCollXYM ();
5961 else if (dims == GAIA_XY_Z_M)
5962 geom = gaiaAllocGeomCollXYZM ();
5963 else
5964 geom = gaiaAllocGeomColl ();
5965 geom->Srid = srid;
5966 ln = gaiaAddLinestringToGeomColl (geom, line->Points);
5967 gaiaCopyLinestringCoords (ln, line);
5968 return geom;
5969 }
5970
5971 TOPOLOGY_PRIVATE int
auxtopo_insert_into_topology(GaiaTopologyAccessorPtr accessor,gaiaGeomCollPtr geom,double tolerance,int line_max_points,double max_length,int mode,gaiaGeomCollPtr * failing_geometry)5972 auxtopo_insert_into_topology (GaiaTopologyAccessorPtr accessor,
5973 gaiaGeomCollPtr geom, double tolerance,
5974 int line_max_points, double max_length, int mode,
5975 gaiaGeomCollPtr * failing_geometry)
5976 {
5977 /* processing all individual geometry items */
5978 gaiaPointPtr pt;
5979 gaiaLinestringPtr ln;
5980 gaiaGeomCollPtr g;
5981 gaiaGeomCollPtr split = NULL;
5982 gaiaGeomCollPtr pg_rings;
5983 sqlite3_int64 *ids = NULL;
5984 int ids_count;
5985 struct gaia_topology *topo = (struct gaia_topology *) accessor;
5986
5987 if (failing_geometry != NULL)
5988 *failing_geometry = NULL;
5989 if (topo == NULL)
5990 return 0;
5991
5992 pt = geom->FirstPoint;
5993 while (pt != NULL)
5994 {
5995 /* looping on Point items */
5996 if (gaiaTopoGeo_AddPoint (accessor, pt, tolerance) < 0)
5997 {
5998 if (failing_geometry != NULL)
5999 *failing_geometry =
6000 do_build_failing_point (geom->Srid,
6001 geom->DimensionModel, pt);
6002 return 0;
6003 }
6004 pt = pt->Next;
6005 }
6006
6007 if (line_max_points <= 0 && max_length <= 0.0)
6008 g = geom;
6009 else
6010 {
6011 /* subdividing Linestrings */
6012 split =
6013 gaiaTopoGeo_SubdivideLines (geom, line_max_points, max_length);
6014 if (split != NULL)
6015 g = split;
6016 else
6017 g = geom;
6018 }
6019 ln = g->FirstLinestring;
6020 while (ln != NULL)
6021 {
6022 /* looping on Linestrings items */
6023 int ret;
6024 if (mode == GAIA_MODE_TOPO_NO_FACE)
6025 ret = gaiaTopoGeo_AddLineStringNoFace
6026 (accessor, ln, tolerance, &ids, &ids_count);
6027 else
6028 ret = gaiaTopoGeo_AddLineString
6029 (accessor, ln, tolerance, &ids, &ids_count);
6030 if (ret == 0)
6031 {
6032 if (failing_geometry != NULL)
6033 *failing_geometry =
6034 do_build_failing_line (geom->Srid, geom->DimensionModel,
6035 ln);
6036 if (ids != NULL)
6037 free (ids);
6038 if (split != NULL)
6039 gaiaFreeGeomColl (split);
6040 return 0;
6041 }
6042 if (ids != NULL)
6043 free (ids);
6044 ln = ln->Next;
6045 }
6046 if (split != NULL)
6047 gaiaFreeGeomColl (split);
6048 split = NULL;
6049
6050 /* transforming all Polygon Rings into Linestrings */
6051 pg_rings = do_linearize (geom);
6052 if (pg_rings != NULL)
6053 {
6054 if (line_max_points <= 0 && max_length <= 0.0)
6055 g = pg_rings;
6056 else
6057 {
6058 /* subdividing Linestrings */
6059 split =
6060 gaiaTopoGeo_SubdivideLines (pg_rings, line_max_points,
6061 max_length);
6062 if (split != NULL)
6063 g = split;
6064 else
6065 g = pg_rings;
6066 }
6067 ln = g->FirstLinestring;
6068 while (ln != NULL)
6069 {
6070 /* looping on Linestrings items */
6071 int ret;
6072 if (mode == GAIA_MODE_TOPO_NO_FACE)
6073 ret = gaiaTopoGeo_AddLineStringNoFace
6074 (accessor, ln, tolerance, &ids, &ids_count);
6075 else
6076 ret = gaiaTopoGeo_AddLineString
6077 (accessor, ln, tolerance, &ids, &ids_count);
6078 if (ret == 0)
6079 {
6080 if (failing_geometry != NULL)
6081 *failing_geometry =
6082 do_build_failing_line (geom->Srid,
6083 geom->DimensionModel, ln);
6084 if (ids != NULL)
6085 free (ids);
6086 gaiaFreeGeomColl (pg_rings);
6087 if (split != NULL)
6088 gaiaFreeGeomColl (split);
6089 return 0;
6090 }
6091 if (ids != NULL)
6092 free (ids);
6093 ln = ln->Next;
6094 }
6095 gaiaFreeGeomColl (pg_rings);
6096 if (split != NULL)
6097 gaiaFreeGeomColl (split);
6098 split = NULL;
6099 }
6100
6101 return 1;
6102 }
6103
6104 #endif /* end ENABLE_RTTOPO conditionals */
6105
6106 SPATIALITE_PRIVATE void
finalize_topologies(const void * p_cache)6107 finalize_topologies (const void *p_cache)
6108 {
6109 /* finalizing all topology related prepared statements */
6110 struct splite_internal_cache *cache =
6111 (struct splite_internal_cache *) p_cache;
6112 if (cache == NULL)
6113 return;
6114
6115 #ifdef ENABLE_RTTOPO /* only if RTTOPO is enabled */
6116 finalize_all_topo_prepared_stmts (p_cache);
6117 #endif /* end ENABLE_RTTOPO conditionals */
6118 }
6119