1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  * http://postgis.net
5  *
6  * PostGIS is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * PostGIS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with PostGIS.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  **********************************************************************
20  *
21  * Copyright (C) 2015-2017 Sandro Santilli <strk@kbt.io>
22  *
23  **********************************************************************/
24 
25 
26 #ifndef LIBLWGEOM_TOPO_H
27 #define LIBLWGEOM_TOPO_H 1
28 
29 #include "liblwgeom.h"
30 
31 /* INT64 */
32 typedef int64_t LWT_INT64;
33 
34 /** Identifier of topology element */
35 typedef LWT_INT64 LWT_ELEMID;
36 
37 /*
38  * ISO primitive elements
39  */
40 
41 /** NODE */
42 typedef struct
43 {
44   LWT_ELEMID node_id;
45   LWT_ELEMID containing_face; /* -1 if not isolated */
46   LWPOINT *geom;
47 }
48 LWT_ISO_NODE;
49 
50 void lwt_iso_node_release(LWT_ISO_NODE* node);
51 
52 /** Node fields */
53 #define LWT_COL_NODE_NODE_ID         1<<0
54 #define LWT_COL_NODE_CONTAINING_FACE 1<<1
55 #define LWT_COL_NODE_GEOM            1<<2
56 #define LWT_COL_NODE_ALL            (1<<3)-1
57 
58 /** EDGE */
59 typedef struct
60 {
61   LWT_ELEMID edge_id;
62   LWT_ELEMID start_node;
63   LWT_ELEMID end_node;
64   LWT_ELEMID face_left;
65   LWT_ELEMID face_right;
66   LWT_ELEMID next_left;
67   LWT_ELEMID next_right;
68   LWLINE *geom;
69 }
70 LWT_ISO_EDGE;
71 
72 /** Edge fields */
73 #define LWT_COL_EDGE_EDGE_ID         1<<0
74 #define LWT_COL_EDGE_START_NODE      1<<1
75 #define LWT_COL_EDGE_END_NODE        1<<2
76 #define LWT_COL_EDGE_FACE_LEFT       1<<3
77 #define LWT_COL_EDGE_FACE_RIGHT      1<<4
78 #define LWT_COL_EDGE_NEXT_LEFT       1<<5
79 #define LWT_COL_EDGE_NEXT_RIGHT      1<<6
80 #define LWT_COL_EDGE_GEOM            1<<7
81 #define LWT_COL_EDGE_ALL            (1<<8)-1
82 
83 /** FACE */
84 typedef struct
85 {
86   LWT_ELEMID face_id;
87   GBOX *mbr;
88 }
89 LWT_ISO_FACE;
90 
91 /** Face fields */
92 #define LWT_COL_FACE_FACE_ID         1<<0
93 #define LWT_COL_FACE_MBR             1<<1
94 #define LWT_COL_FACE_ALL            (1<<2)-1
95 
96 typedef enum LWT_SPATIALTYPE_T {
97   LWT_PUNTAL = 0,
98   LWT_LINEAL = 1,
99   LWT_AREAL = 2,
100   LWT_COLLECTION = 3
101 } LWT_SPATIALTYPE;
102 
103 /*
104  * Backend handling functions
105  */
106 
107 /* opaque pointers referencing native backend objects */
108 
109 /**
110  * Backend private data pointer
111  *
112  * Only the backend handler needs to know what it really is.
113  * It will be passed to all registered callback functions.
114  */
115 typedef struct LWT_BE_DATA_T LWT_BE_DATA;
116 
117 /**
118  * Backend interface handler
119  *
120  * Embeds all registered backend callbacks and private data pointer.
121  * Will need to be passed (directly or indirectly) to al public facing
122  * APIs of this library.
123  */
124 typedef struct LWT_BE_IFACE_T LWT_BE_IFACE;
125 
126 /**
127  * Topology handler.
128  *
129  * Embeds backend interface handler.
130  * Will need to be passed to all topology manipulation APIs
131  * of this library.
132  */
133 typedef struct LWT_BE_TOPOLOGY_T LWT_BE_TOPOLOGY;
134 
135 /**
136  * Structure containing base backend callbacks
137  *
138  * Used for registering into the backend iface
139  */
140 typedef struct LWT_BE_CALLBACKS_T {
141 
142   /**
143    * Read last error message from backend
144    *
145    * @return NULL-terminated error string
146    */
147   const char* (*lastErrorMessage) (const LWT_BE_DATA* be);
148 
149   /**
150    * Create a new topology in the backend
151    *
152    * @param name the topology name
153    * @param srid the topology SRID
154    * @param precision the topology precision/tolerance
155    * @param hasZ non-zero if topology primitives should have a Z ordinate
156    * @return a topology handler, which embeds the backend data/params
157    *         or NULL on error (@see lastErrorMessage)
158    */
159   LWT_BE_TOPOLOGY* (*createTopology) (
160     const LWT_BE_DATA* be,
161     const char* name, int srid, double precision, int hasZ
162   );
163 
164   /**
165    * Load a topology from the backend
166    *
167    * @param name the topology name
168    * @return a topology handler, which embeds the backend data/params
169    *         or NULL on error (@see lastErrorMessage)
170    */
171   LWT_BE_TOPOLOGY* (*loadTopologyByName) (
172     const LWT_BE_DATA* be,
173     const char* name
174   );
175 
176   /**
177    * Release memory associated to a backend topology
178    *
179    * @param topo the backend topology handler
180    * @return 1 on success, 0 on error (@see lastErrorMessage)
181    */
182   int (*freeTopology) (LWT_BE_TOPOLOGY* topo);
183 
184   /**
185    * Get nodes by id
186    *
187    * @param topo the topology to act upon
188    * @param ids an array of element identifiers
189    * @param numelems input/output parameter, pass number of node identifiers
190    *                 in the input array, gets number of node in output array.
191    *	TODO: Should be uint64 to match SPI_processed
192    * @param fields fields to be filled in the returned structure, see
193    *               LWT_COL_NODE_* macros
194    *
195    * @return an array of nodes
196    *         or NULL in the following cases:
197    *         - no edge found ("numelems" is set to 0)
198    *         - error ("numelems" is set to -1)
199    *           (@see lastErrorMessage)
200    *
201    */
202   LWT_ISO_NODE* (*getNodeById) (
203       const LWT_BE_TOPOLOGY* topo,
204       const LWT_ELEMID* ids, int* numelems, int fields
205   );
206 
207   /**
208    * Get nodes within distance by point
209    *
210    * @param topo the topology to act upon
211    * @param pt the query point
212    * @param dist the distance
213    * @param numelems output parameter, gets number of elements found
214    *                 if the return is not null, otherwise see @return
215    *                 section for semantic.
216    *	TODO: Should be uint64 to match SPI_processed
217    * @param fields fields to be filled in the returned structure, see
218    *               LWT_COL_NODE_* macros
219    * @param limit max number of nodes to return, 0 for no limit, -1
220    *              to only check for existance if a matching row.
221    *
222    * @return an array of nodes or null in the following cases:
223    *         - limit=-1 ("numelems" is set to 1 if found, 0 otherwise)
224    *         - limit>0 and no records found ("numelems" is set to 0)
225    *         - error ("numelems" is set to -1)
226    *
227    */
228   LWT_ISO_NODE* (*getNodeWithinDistance2D) (
229       const LWT_BE_TOPOLOGY* topo,
230       const LWPOINT* pt, double dist, int* numelems,
231       int fields, int limit
232   );
233 
234   /**
235    * Insert nodes
236    *
237    * Insert node primitives in the topology, performing no
238    * consistency checks.
239    *
240    * @param topo the topology to act upon
241    * @param nodes the nodes to insert. Those with a node_id set to -1
242    *              it will be replaced to an automatically assigned identifier
243    * @param nelems number of elements in the nodes array
244    *	TODO: Should be uint64 to match SPI_processed
245    *
246    * @return 1 on success, 0 on error (@see lastErrorMessage)
247    */
248   int (*insertNodes) (
249       const LWT_BE_TOPOLOGY* topo,
250       LWT_ISO_NODE* nodes,
251       int numelems
252   );
253 
254   /**
255    * Get edge by id
256    *
257    * @param topo the topology to act upon
258    * @param ids an array of element identifiers
259    * @param numelems input/output parameter, pass number of edge identifiers
260    *                 in the input array, gets number of edges in output array
261    *                 if the return is not null, otherwise see @return
262    *                 section for semantic.
263    * @param fields fields to be filled in the returned structure, see
264    *               LWT_COL_EDGE_* macros
265    *
266    * @return an array of edges or NULL in the following cases:
267    *         - none found ("numelems" is set to 0)
268    *         - error ("numelems" is set to -1)
269    */
270   LWT_ISO_EDGE* (*getEdgeById) (
271       const LWT_BE_TOPOLOGY* topo,
272       const LWT_ELEMID* ids, int* numelems, int fields
273   );
274 
275   /**
276    * Get edges within distance by point
277    *
278    * @param topo the topology to act upon
279    * @param pt the query point
280    * @param dist the distance
281    * @param numelems output parameter, gets number of elements found
282    *                 if the return is not null, otherwise see @return
283    *                 section for semantic.
284    * @param fields fields to be filled in the returned structure, see
285    *               LWT_COL_EDGE_* macros
286    * @param limit max number of edges to return, 0 for no limit, -1
287    *              to only check for existence if a matching row.
288    *
289    * @return an array of edges or null in the following cases:
290    *         - limit=-1 ("numelems" is set to 1 if found, 0 otherwise)
291    *         - limit>0 and no records found ("numelems" is set to 0)
292    *         - error ("numelems" is set to -1)
293    *
294    */
295   LWT_ISO_EDGE* (*getEdgeWithinDistance2D) (
296       const LWT_BE_TOPOLOGY* topo,
297       const LWPOINT* pt, double dist, int* numelems,
298       int fields, int limit
299   );
300 
301   /**
302    * Get next available edge identifier
303    *
304    * Identifiers returned by this function should not be considered
305    * available anymore.
306    *
307    * @param topo the topology to act upon
308    *
309    * @return next available edge identifier or -1 on error
310    */
311   LWT_ELEMID (*getNextEdgeId) (
312       const LWT_BE_TOPOLOGY* topo
313   );
314 
315   /**
316    * Insert edges
317    *
318    * Insert edge primitives in the topology, performing no
319    * consistency checks.
320    *
321    * @param topo the topology to act upon
322    * @param edges the edges to insert. Those with a edge_id set to -1
323    *              it will be replaced to an automatically assigned identifier
324    * @param nelems number of elements in the edges array
325    *	TODO: Should be uint64 to match SPI_processed
326    *
327    * @return number of inserted edges, or -1 (@see lastErrorMessage)
328    */
329   int (*insertEdges) (
330       const LWT_BE_TOPOLOGY* topo,
331       LWT_ISO_EDGE* edges,
332       int numelems
333   );
334 
335   /**
336    * Update edges selected by fields match/mismatch
337    *
338    * @param topo the topology to act upon
339    * @param sel_edge an LWT_ISO_EDGE object with selecting fields set.
340    * @param sel_fields fields used to select edges to be updated,
341    *                   see LWT_COL_EDGE_* macros
342    * @param upd_edge an LWT_ISO_EDGE object with updated fields set.
343    * @param upd_fields fields to be updated for the selected edges,
344    *                   see LWT_COL_EDGE_* macros
345    * @param exc_edge an LWT_ISO_EDGE object with exclusion fields set,
346    *                 can be NULL if no exlusion condition exists.
347    * @param exc_fields fields used for excluding edges from the update,
348    *                   see LWT_COL_EDGE_* macros
349    *
350    * @return number of edges being updated or -1 on error
351    *         (@see lastErroMessage)
352    */
353   int (*updateEdges) (
354       const LWT_BE_TOPOLOGY* topo,
355       const LWT_ISO_EDGE* sel_edge, int sel_fields,
356       const LWT_ISO_EDGE* upd_edge, int upd_fields,
357       const LWT_ISO_EDGE* exc_edge, int exc_fields
358   );
359 
360   /**
361    * Get faces by id
362    *
363    * @param topo the topology to act upon
364    * @param ids an array of element identifiers
365    * @param numelems input/output parameter, pass number of edge identifiers
366    *                 in the input array, gets number of node in output array
367    *                 if the return is not null, otherwise see @return
368    *                 section for semantic.
369    * @param fields fields to be filled in the returned structure, see
370    *               LWT_COL_FACE_* macros
371    *
372    * @return an array of faces or NULL in the following cases:
373    *         - none found ("numelems" is set to 0)
374    *         - error ("numelems" is set to -1)
375    */
376   LWT_ISO_FACE* (*getFaceById) (
377       const LWT_BE_TOPOLOGY* topo,
378       const LWT_ELEMID* ids, int* numelems, int fields
379   );
380 
381   /**
382    * Get face containing point
383    *
384    * @param topo the topology to act upon
385    * @param pt the query point
386    *
387    * @return a face identifier, -1 if no face contains the point
388    *         (could be in universe face or on an edge)
389    *         or -2 on error (@see lastErrorMessage)
390    */
391   LWT_ELEMID (*getFaceContainingPoint) (
392       const LWT_BE_TOPOLOGY* topo,
393       const LWPOINT* pt
394   );
395 
396   /**
397    * Update TopoGeometry objects after an edge split event
398    *
399    * @param topo the topology to act upon
400    * @param split_edge identifier of the edge that was split.
401    * @param new_edge1 identifier of the first new edge that was created
402    *        as a result of edge splitting.
403    * @param new_edge2 identifier of the second new edge that was created
404    *        as a result of edge splitting, or -1 if the old edge was
405    *        modified rather than replaced.
406    *
407 	 * @return 1 on success, 0 on error
408    *
409    * @note on splitting an edge, the new edges both have the
410    *       same direction as the original one. If a second new edge was
411    *       created, its start node will be equal to the first new edge
412    *       end node.
413    */
414   int (*updateTopoGeomEdgeSplit) (
415       const LWT_BE_TOPOLOGY* topo,
416       LWT_ELEMID split_edge, LWT_ELEMID new_edge1, LWT_ELEMID new_edge2
417   );
418 
419   /**
420    * Delete edges
421    *
422    * @param topo the topology to act upon
423    * @param sel_edge an LWT_ISO_EDGE object with selecting fields set.
424    * @param sel_fields fields used to select edges to be deleted,
425    *                   see LWT_COL_EDGE_* macros
426    *
427    * @return number of edges being deleted or -1 on error
428    *         (@see lastErroMessage)
429    */
430   int (*deleteEdges) (
431       const LWT_BE_TOPOLOGY* topo,
432       const LWT_ISO_EDGE* sel_edge, int sel_fields
433   );
434 
435   /**
436    * Get edges whose bounding box overlaps a given 2D bounding box
437    *
438    * @param topo the topology to act upon
439    * @param box the query box
440    * @param numelems output parameter, gets number of elements found
441    *                 if the return is not null, otherwise see @return
442    *                 section for semantic.
443    * @param fields fields to be filled in the returned structure, see
444    *               LWT_COL_NODE_* macros
445    * @param limit max number of nodes to return, 0 for no limit, -1
446    *              to only check for existence if a matching row.
447    *
448    * @return an array of nodes or null in the following cases:
449    *         - limit=-1 ("numelems" is set to 1 if found, 0 otherwise)
450    *         - limit>0 and no records found ("numelems" is set to 0)
451    *         - error ("numelems" is set to -1)
452    *
453    */
454   LWT_ISO_NODE* (*getNodeWithinBox2D) (
455       const LWT_BE_TOPOLOGY* topo,
456       const GBOX* box,
457       int* numelems, int fields, int limit
458   );
459 
460   /**
461    * Get edges whose bounding box overlaps a given 2D bounding box
462    *
463    * @param topo the topology to act upon
464    * @param box the query box, to be considered infinite if NULL
465    * @param numelems output parameter, gets number of elements found
466    *                 if the return is not null, otherwise see @return
467    *                 section for semantic.
468    * @param fields fields to be filled in the returned structure, see
469    *               LWT_COL_EDGE_* macros
470    * @param limit max number of edges to return, 0 for no limit, -1
471    *              to only check for existence if a matching row.
472    *
473    * @return an array of edges or null in the following cases:
474    *         - limit=-1 ("numelems" is set to 1 if found, 0 otherwise)
475    *         - limit>0 and no records found ("numelems" is set to 0)
476    *         - error ("numelems" is set to -1)
477    *
478    */
479   LWT_ISO_EDGE* (*getEdgeWithinBox2D) (
480       const LWT_BE_TOPOLOGY* topo,
481       const GBOX* box,
482       int* numelems, int fields, int limit
483   );
484 
485   /**
486    * Get edges that start or end on any of the given node identifiers
487    *
488    * @param topo the topology to act upon
489    * @param ids an array of node identifiers
490    * @param numelems input/output parameter, pass number of node identifiers
491    *                 in the input array, gets number of edges in output array
492    *                 if the return is not null, otherwise see @return
493    *                 section for semantic.
494    * @param fields fields to be filled in the returned structure, see
495    *               LWT_COL_EDGE_* macros
496    *
497    * @return an array of edges that are incident to a node
498    *         or NULL in the following cases:
499    *         - no edge found ("numelems" is set to 0)
500    *         - error ("numelems" is set to -1)
501    *           (@see lastErrorMessage)
502    */
503   LWT_ISO_EDGE* (*getEdgeByNode) (
504       const LWT_BE_TOPOLOGY* topo,
505       const LWT_ELEMID* ids, int* numelems, int fields
506   );
507 
508   /**
509    * Update nodes selected by fields match/mismatch
510    *
511    * @param topo the topology to act upon
512    * @param sel_node an LWT_ISO_NODE object with selecting fields set.
513    * @param sel_fields fields used to select nodes to be updated,
514    *                   see LWT_COL_NODE_* macros
515    * @param upd_node an LWT_ISO_NODE object with updated fields set.
516    * @param upd_fields fields to be updated for the selected nodes,
517    *                   see LWT_COL_NODE_* macros
518    * @param exc_node an LWT_ISO_NODE object with exclusion fields set,
519    *                 can be NULL if no exclusion condition exists.
520    * @param exc_fields fields used for excluding nodes from the update,
521    *                   see LWT_COL_NODE_* macros
522    *
523    * @return number of nodes being updated or -1 on error
524    *         (@see lastErroMessage)
525    */
526   int (*updateNodes) (
527       const LWT_BE_TOPOLOGY* topo,
528       const LWT_ISO_NODE* sel_node, int sel_fields,
529       const LWT_ISO_NODE* upd_node, int upd_fields,
530       const LWT_ISO_NODE* exc_node, int exc_fields
531   );
532 
533   /**
534    * Update TopoGeometry objects after a face split event
535    *
536    * @param topo the topology to act upon
537    * @param split_face identifier of the face that was split.
538    * @param new_face1 identifier of the first new face that was created
539    *        as a result of face splitting.
540    * @param new_face2 identifier of the second new face that was created
541    *        as a result of face splitting, or -1 if the old face was
542    *        modified rather than replaced.
543    *
544 	 * @return 1 on success, 0 on error (@see lastErroMessage)
545    *
546    */
547   int (*updateTopoGeomFaceSplit) (
548       const LWT_BE_TOPOLOGY* topo,
549       LWT_ELEMID split_face, LWT_ELEMID new_face1, LWT_ELEMID new_face2
550   );
551 
552   /**
553    * Insert faces
554    *
555    * Insert face primitives in the topology, performing no
556    * consistency checks.
557    *
558    * @param topo the topology to act upon
559    * @param faces the faces to insert. Those with a node_id set to -1
560    *              it will be replaced to an automatically assigned identifier
561    * @param nelems number of elements in the faces array
562    *	TODO: Should be uint64 to match SPI_processed
563    *
564    * @return number of inserted faces, or -1 (@see lastErrorMessage)
565    */
566   int (*insertFaces) (
567       const LWT_BE_TOPOLOGY* topo,
568       LWT_ISO_FACE* faces,
569       int numelems
570   );
571 
572   /**
573    * Update faces by id
574    *
575    * @param topo the topology to act upon
576    * @param faces an array of LWT_ISO_FACE object with selecting id
577    *              and setting mbr.
578    * @param numfaces number of faces in the "faces" array
579    *	TODO: Should be uint64 to match SPI_processed
580    *
581    * @return number of faces being updated or -1 on error
582    *         (@see lastErroMessage)
583    */
584   int (*updateFacesById) (
585       const LWT_BE_TOPOLOGY* topo,
586       const LWT_ISO_FACE* faces, int numfaces
587   );
588 
589   /*
590    * Get the ordered list edge visited by a side walk
591    *
592    * The walk starts from the side of an edge and stops when
593    * either the max number of visited edges OR the starting
594    * position is reached. The output list never includes a
595    * duplicated signed edge identifier.
596    *
597    * It is expected that the walk uses the "next_left" and "next_right"
598    * attributes of ISO edges to perform the walk (rather than recomputing
599    * the turns at each node).
600    *
601    * @param topo the topology to operate on
602    * @param edge walk start position and direction:
603    *             abs value identifies the edge, sign expresses
604    *             side (left if positive, right if negative)
605    *             and direction (forward if positive, backward if negative).
606    * @param numedges output parameter, gets the number of edges visited
607    *
608    * @param limit max edges to return (to avoid an infinite loop in case
609    *              of a corrupted topology). 0 is for unlimited.
610    *              The function is expected to error out if the limit is hit.
611    *
612    * @return an array of signed edge identifiers (positive edges being
613    *         walked in their direction, negative ones in opposite) or
614    *         NULL on error (@see lastErrorMessage)
615    */
616   LWT_ELEMID* (*getRingEdges) (
617       const LWT_BE_TOPOLOGY* topo,
618       LWT_ELEMID edge, int *numedges, int limit
619   );
620 
621   /**
622    * Update edges by id
623    *
624    * @param topo the topology to act upon
625    * @param edges an array of LWT_ISO_EDGE object with selecting id
626    *              and updating fields.
627    * @param numedges number of edges in the "edges" array
628    *	TODO: Should be uint64 to match SPI_processed
629    * @param upd_fields fields to be updated for the selected edges,
630    *                   see LWT_COL_EDGE_* macros
631    *
632    * @return number of edges being updated or -1 on error
633    *         (@see lastErrorMessage)
634    */
635   int (*updateEdgesById) (
636       const LWT_BE_TOPOLOGY* topo,
637       const LWT_ISO_EDGE* edges, int numedges,
638       int upd_fields
639   );
640 
641   /**
642    * \brief
643    * Get edges that have any of the given faces on the left or right side
644    * and optionally whose bounding box overlaps the given one.
645    *
646    * @param topo the topology to act upon
647    * @param ids an array of face identifiers
648    * @param numelems input/output parameter, pass number of face identifiers
649    *                 in the input array, gets number of edges in output array
650    *                 if the return is not null, otherwise see @return
651    *                 section for semantic.
652    *	TODO: Should be uint64 to match SPI_processed
653    * @param fields fields to be filled in the returned structure, see
654    *               LWT_COL_EDGE_* macros
655    * @param box optional bounding box to further restrict matches, use
656    *            NULL for no further restriction.
657    *
658    * @return an array of edges identifiers or NULL in the following cases:
659    *         - no edge found ("numelems" is set to 0)
660    *         - error ("numelems" is set to -1)
661    */
662   LWT_ISO_EDGE* (*getEdgeByFace) (
663       const LWT_BE_TOPOLOGY* topo,
664       const LWT_ELEMID* ids, int* numelems, int fields,
665       const GBOX *box
666   );
667 
668   /**
669    * Get isolated nodes contained in any of the given faces
670    *
671    * @param topo the topology to act upon
672    * @param faces an array of face identifiers
673    * @param numelems input/output parameter, pass number of face
674    *                 identifiers in the input array, gets number of
675    *                 nodes in output array if the return is not null,
676    *                 otherwise see @return section for semantic.
677    *	TODO: Should be uint64 to match SPI_processed
678    * @param fields fields to be filled in the returned structure, see
679    *               LWT_COL_NODE_* macros
680    * @param box optional bounding box to further restrict matches, use
681    *            NULL for no further restriction.
682    *
683    * @return an array of nodes or NULL in the following cases:
684    *         - no nod found ("numelems" is set to 0)
685    *         - error ("numelems" is set to -1, @see lastErrorMessage)
686    */
687   LWT_ISO_NODE* (*getNodeByFace) (
688       const LWT_BE_TOPOLOGY* topo,
689       const LWT_ELEMID* faces, int* numelems, int fields,
690       const GBOX *box
691   );
692 
693   /**
694    * Update nodes by id
695    *
696    * @param topo the topology to act upon
697    * @param nodes an array of LWT_ISO_EDGE objects with selecting id
698    *              and updating fields.
699    * @param numnodes number of nodes in the "nodes" array
700    *	TODO: Should be uint64 to match SPI_processed
701    * @param upd_fields fields to be updated for the selected edges,
702    *                   see LWT_COL_NODE_* macros
703    *
704    * @return number of nodes being updated or -1 on error
705    *         (@see lastErrorMessage)
706    */
707   int (*updateNodesById) (
708       const LWT_BE_TOPOLOGY* topo,
709       const LWT_ISO_NODE* nodes, int numnodes,
710       int upd_fields
711   );
712 
713   /**
714    * Delete faces by id
715    *
716    * @param topo the topology to act upon
717    * @param ids an array of face identifiers
718    * @param numelems number of face identifiers in the ids array
719    *	TODO: Should be uint64 to match SPI_processed
720    *
721    * @return number of faces being deleted or -1 on error
722    *         (@see lastErrorMessage)
723    */
724   int (*deleteFacesById) (
725       const LWT_BE_TOPOLOGY* topo,
726       const LWT_ELEMID* ids,
727       int numelems
728   );
729 
730   /**
731    * Get topology SRID
732    * @return 0 for unknown
733    */
734   int (*topoGetSRID) (
735       const LWT_BE_TOPOLOGY* topo
736   );
737 
738   /**
739    * Get topology precision
740    */
741   double (*topoGetPrecision) (
742       const LWT_BE_TOPOLOGY* topo
743   );
744 
745   /**
746    * Get topology Z flag
747    * @return 1 if topology elements do have Z value, 0 otherwise
748    */
749   int (*topoHasZ) (
750       const LWT_BE_TOPOLOGY* topo
751   );
752 
753   /**
754    * Delete nodes by id
755    *
756    * @param topo the topology to act upon
757    * @param ids an array of node identifiers
758    * @param numelems number of node identifiers in the ids array
759    *	TODO: Should be uint64 to match SPI_processed
760    *
761    * @return number of nodes being deleted or -1 on error
762    *         (@see lastErrorMessage)
763    */
764   int (*deleteNodesById) (
765       const LWT_BE_TOPOLOGY* topo,
766       const LWT_ELEMID* ids,
767       int numelems
768   );
769 
770   /**
771    * Check TopoGeometry objects before an edge removal event
772    *
773    * @param topo the topology to act upon
774    * @param rem_edge identifier of the edge that's been removed
775    * @param face_left identifier of the face on the edge's left side
776    * @param face_right identifier of the face on the edge's right side
777    *
778    * @return 1 to allow, 0 to forbid the operation
779    *         (reporting reason via lastErrorMessage)
780    *
781    */
782   int (*checkTopoGeomRemEdge) (
783       const LWT_BE_TOPOLOGY* topo,
784       LWT_ELEMID rem_edge,
785       LWT_ELEMID face_left,
786       LWT_ELEMID face_right
787   );
788 
789   /**
790    * Update TopoGeometry objects after healing two faces
791    *
792    * @param topo the topology to act upon
793    * @param face1 identifier of the first face
794    * @param face2 identifier of the second face
795    * @param newface identifier of the new face
796    *
797    * @note that newface may or may not be equal to face1 or face2,
798    *       while face1 should never be the same as face2.
799    *
800    * @return 1 on success, 0 on error (@see lastErrorMessage)
801    *
802    */
803   int (*updateTopoGeomFaceHeal) (
804       const LWT_BE_TOPOLOGY* topo,
805       LWT_ELEMID face1, LWT_ELEMID face2, LWT_ELEMID newface
806   );
807 
808   /**
809    * Check TopoGeometry objects before a node removal event
810    *
811    * @param topo the topology to act upon
812    * @param rem_node identifier of the node that's been removed
813    * @param e1 identifier of the first connected edge
814    * @param e2 identifier of the second connected edge
815    *
816    * The operation should be forbidden if any TopoGeometry object
817    * exists which contains only one of the two healed edges.
818    *
819    * The operation should also be forbidden if the removed node
820    * takes part in the definition of a TopoGeometry, although
821    * this wasn't the case yet as of PostGIS version 2.1.8:
822    * https://trac.osgeo.org/postgis/ticket/3239
823    *
824    * @return 1 to allow, 0 to forbid the operation
825    *         (reporting reason via lastErrorMessage)
826    *
827    */
828   int (*checkTopoGeomRemNode) (
829       const LWT_BE_TOPOLOGY* topo,
830       LWT_ELEMID rem_node,
831       LWT_ELEMID e1,
832       LWT_ELEMID e2
833   );
834 
835   /**
836    * Update TopoGeometry objects after healing two edges
837    *
838    * @param topo the topology to act upon
839    * @param edge1 identifier of the first edge
840    * @param edge2 identifier of the second edge
841    * @param newedge identifier of the new edge, taking the space
842    *                previously occupied by both original edges
843    *
844    * @note that newedge may or may not be equal to edge1 or edge2,
845    *       while edge1 should never be the same as edge2.
846    *
847    * @return 1 on success, 0 on error (@see lastErrorMessage)
848    *
849    */
850   int (*updateTopoGeomEdgeHeal) (
851       const LWT_BE_TOPOLOGY* topo,
852       LWT_ELEMID edge1, LWT_ELEMID edge2, LWT_ELEMID newedge
853   );
854 
855   /**
856    * Get faces whose bounding box overlaps a given 2D bounding box
857    *
858    * @param topo the topology to act upon
859    * @param box the query box
860    * @param numelems output parameter, gets number of elements found
861    *                 if the return is not null, otherwise see @return
862    *                 section for semantic.
863    *	TODO: Should be uint64 to match SPI_processed
864    * @param fields fields to be filled in the returned structure, see
865    *               LWT_COL_FACE_* macros
866    * @param limit max number of faces to return, 0 for no limit, -1
867    *              to only check for existence if a matching row.
868    *
869    * @return an array of faces or null in the following cases:
870    *         - limit=-1 ("numelems" is set to 1 if found, 0 otherwise)
871    *         - limit>0 and no records found ("numelems" is set to 0)
872    *         - error ("numelems" is set to -1)
873    *
874    */
875   LWT_ISO_FACE* (*getFaceWithinBox2D) (
876       const LWT_BE_TOPOLOGY* topo,
877       const GBOX* box,
878       int* numelems, int fields, int limit
879   );
880 
881 } LWT_BE_CALLBACKS;
882 
883 
884 /**
885  * Create a new backend interface
886  *
887  * Ownership to caller delete with lwt_FreeBackendIface
888  *
889  * @param data Backend data, passed as first parameter to all callback functions
890  */
891 LWT_BE_IFACE* lwt_CreateBackendIface(const LWT_BE_DATA* data);
892 
893 /**
894  * Register backend callbacks into the opaque iface handler
895  *
896  * @param iface the backend interface handler (see lwt_CreateBackendIface)
897  * @param cb a pointer to the callbacks structure; ownership left to caller.
898  */
899 void lwt_BackendIfaceRegisterCallbacks(LWT_BE_IFACE* iface, const LWT_BE_CALLBACKS* cb);
900 
901 /** Release memory associated with an LWT_BE_IFACE */
902 void lwt_FreeBackendIface(LWT_BE_IFACE* iface);
903 
904 /********************************************************************
905  *
906  * End of BE interface
907  *
908  *******************************************************************/
909 
910 /**
911  * Topology errors type
912  */
913 typedef enum LWT_TOPOERR_TYPE_T {
914   LWT_TOPOERR_EDGE_CROSSES_NODE,
915   LWT_TOPOERR_EDGE_INVALID,
916   LWT_TOPOERR_EDGE_NOT_SIMPLE,
917   LWT_TOPOERR_EDGE_CROSSES_EDGE,
918   LWT_TOPOERR_EDGE_STARTNODE_MISMATCH,
919   LWT_TOPOERR_EDGE_ENDNODE_MISMATCH,
920   LWT_TOPOERR_FACE_WITHOUT_EDGES,
921   LWT_TOPOERR_FACE_HAS_NO_RINGS,
922   LWT_TOPOERR_FACE_OVERLAPS_FACE,
923   LWT_TOPOERR_FACE_WITHIN_FACE
924 } LWT_TOPOERR_TYPE;
925 
926 /** Topology error */
927 typedef struct LWT_TOPOERR_T {
928   /** Type of error */
929   LWT_TOPOERR_TYPE err;
930   /** Identifier of first affected element */
931   LWT_ELEMID elem1;
932   /** Identifier of second affected element (0 if inapplicable) */
933   LWT_ELEMID elem2;
934 } LWT_TOPOERR;
935 
936 /*
937  * Topology functions
938  */
939 
940 /** Opaque topology structure
941  *
942  * Embeds backend interface and topology
943  */
944 typedef struct LWT_TOPOLOGY_T LWT_TOPOLOGY;
945 
946 
947 /*******************************************************************
948  *
949  * Non-ISO signatures here
950  *
951  *******************************************************************/
952 
953 /**
954  * Initializes a new topology
955  *
956  * @param iface the backend interface handler (see lwt_CreateBackendIface)
957  * @param name name of the new topology
958  * @param srid the topology SRID
959  * @param prec the topology precision/tolerance
960  * @param hasz non-zero if topology primitives should have a Z ordinate
961  *
962  * @return the handler of the topology, or NULL on error
963  *         (liblwgeom error handler will be invoked with error message)
964  */
965 LWT_TOPOLOGY *lwt_CreateTopology(LWT_BE_IFACE *iface, const char *name,
966                         int srid, double prec, int hasz);
967 
968 /**
969  * Loads an existing topology by name from the database
970  *
971  * @param iface the backend interface handler (see lwt_CreateBackendIface)
972  * @param name name of the topology to load
973  *
974  * @return the handler of the topology, or NULL on error
975  *         (liblwgeom error handler will be invoked with error message)
976  */
977 LWT_TOPOLOGY *lwt_LoadTopology(LWT_BE_IFACE *iface, const char *name);
978 
979 /**
980  * Drop a topology and all its associated objects from the database
981  *
982  * @param topo the topology to drop
983  */
984 void lwt_DropTopology(LWT_TOPOLOGY* topo);
985 
986 /** Release memory associated with an LWT_TOPOLOGY
987  *
988  * @param topo the topology to release (it's not removed from db)
989  */
990 void lwt_FreeTopology(LWT_TOPOLOGY* topo);
991 
992 /**
993  * Retrieve the id of a node at a point location
994  *
995  * @param topo the topology to operate on
996  * @param point the point to use for query
997  * @param tol max distance around the given point to look for a node
998  * @return a node identifier if one is found, 0 if none is found, -1
999  *         on error (multiple nodes within distance).
1000  *         The liblwgeom error handler will be invoked in case of error.
1001  */
1002 LWT_ELEMID lwt_GetNodeByPoint(LWT_TOPOLOGY *topo, LWPOINT *pt, double tol);
1003 
1004 /**
1005  * Find the edge-id of an edge that intersects a given point
1006  *
1007  * @param topo the topology to operate on
1008  * @param point the point to use for query
1009  * @param tol max distance around the given point to look for an
1010  *            intersecting edge
1011  * @return an edge identifier if one is found, 0 if none is found, -1
1012  *         on error (multiple edges within distance).
1013  *         The liblwgeom error handler will be invoked in case of error.
1014  */
1015 LWT_ELEMID lwt_GetEdgeByPoint(LWT_TOPOLOGY *topo, LWPOINT *pt, double tol);
1016 
1017 /**
1018  * Find the face-id of a face containing a given point
1019  *
1020  * @param topo the topology to operate on
1021  * @param point the point to use for query
1022  * @param tol max distance around the given point to look for a
1023  *            containing face
1024  * @return a face identifier if one is found (0 if universe), -1
1025  *         on error (multiple faces within distance or point on node
1026  *         or edge).
1027  *         The liblwgeom error handler will be invoked in case of error.
1028  */
1029 LWT_ELEMID lwt_GetFaceByPoint(LWT_TOPOLOGY *topo, LWPOINT *pt, double tol);
1030 
1031 
1032 /*******************************************************************
1033  *
1034  * Topology population (non-ISO)
1035  *
1036  *******************************************************************/
1037 
1038 /**
1039  * Adds a point to the topology
1040  *
1041  * The given point will snap to existing nodes or edges within given
1042  * tolerance. An existing edge may be split by the point.
1043  *
1044  * @param topo the topology to operate on
1045  * @param point the point to add
1046  * @param tol snap tolerance, the topology tolerance will be used if 0
1047  *
1048  * @return identifier of added (or pre-existing) node or -1 on error
1049  *         (liblwgeom error handler will be invoked with error message)
1050  */
1051 LWT_ELEMID lwt_AddPoint(LWT_TOPOLOGY* topo, LWPOINT* point, double tol);
1052 
1053 /**
1054  * Adds a linestring to the topology
1055  *
1056  * The given line will snap to existing nodes or edges within given
1057  * tolerance. Existing edges or faces may be split by the line.
1058  *
1059  * @param topo the topology to operate on
1060  * @param line the line to add
1061  * @param tol snap tolerance, the topology tolerance will be used if 0
1062  * @param nedges output parameter, will be set to number of edges the
1063  *               line was split into, or -1 on error
1064  *               (liblwgeom error handler will be invoked with error message)
1065  *
1066  * @return an array of <nedges> edge identifiers that sewed togheter
1067  *         will build up the input linestring (after snapping). Caller
1068  *         will need to free the array using lwfree(), if not null.
1069  */
1070 LWT_ELEMID* lwt_AddLine(LWT_TOPOLOGY* topo, LWLINE* line, double tol,
1071                         int* nedges);
1072 
1073 /**
1074  * Adds a linestring to the topology without determining generated faces
1075  *
1076  * The given line will snap to existing nodes or edges within given
1077  * tolerance. Existing edges or faces may be split by the line.
1078  *
1079  * Side faces for the new edges will not be determined and no new
1080  * faces will be created, effectively leaving the topology in an
1081  * invalid state (WARNING!)
1082  *
1083  * @param topo the topology to operate on
1084  * @param line the line to add
1085  * @param tol snap tolerance, the topology tolerance will be used if 0
1086  * @param nedges output parameter, will be set to number of edges the
1087  *               line was split into, or -1 on error
1088  *               (liblwgeom error handler will be invoked with error message)
1089  *
1090  * @return an array of <nedges> edge identifiers that sewed togheter
1091  *         will build up the input linestring (after snapping). Caller
1092  *         will need to free the array using lwfree(), if not null.
1093  */
1094 LWT_ELEMID* lwt_AddLineNoFace(LWT_TOPOLOGY* topo, LWLINE* line, double tol,
1095                         int* nedges);
1096 
1097 /*
1098  * Determine and register all topology faces:
1099  *
1100  *  - Determines which faces are generated by existing
1101  *    edges.
1102  *  - Creates face records with correct mbr
1103  *  - Update edge left/right face attributes
1104  *
1105  *  Precondition:
1106  *     - the topology edges are correctly linked
1107  *     - there are no faces registered in the topology
1108  *
1109  *  Postconditions:
1110  *     - all left/right face attributes of edges
1111  *       reference faces with correct mbr.
1112  *
1113  *  Notes:
1114  *     - does not attempt to assign isolated nodes to their
1115  *       containing faces
1116  *     - does not remove existing face records
1117  *     - loads in memory all the topology edges
1118  *
1119  * @param topo the topology to operate on
1120  *
1121  * @return 0 on success, -1 on error
1122  *         (librtgeom error handler will be invoked with error
1123  *         message)
1124  */
1125 int lwt_Polygonize(LWT_TOPOLOGY* topo);
1126 
1127 /**
1128  * Adds a polygon to the topology
1129  *
1130  * The boundary of the given polygon will snap to existing nodes or
1131  * edges within given tolerance.
1132  * Existing edges or faces may be split by the boundary of the polygon.
1133  *
1134  * @param topo the topology to operate on
1135  * @param poly the polygon to add
1136  * @param tol snap tolerance, the topology tolerance will be used if 0
1137  * @param nfaces output parameter, will be set to number of faces the
1138  *               polygon was split into, or -1 on error
1139  *               (liblwgeom error handler will be invoked with error message)
1140  *
1141  * @return an array of <nfaces> face identifiers that sewed togheter
1142  *         will build up the input polygon (after snapping). Caller
1143  *         will need to free the array using lwfree(), if not null.
1144  */
1145 LWT_ELEMID* lwt_AddPolygon(LWT_TOPOLOGY* topo, LWPOLY* poly, double tol,
1146                         int* nfaces);
1147 
1148 /*******************************************************************
1149  *
1150  * ISO signatures here
1151  *
1152  *******************************************************************/
1153 
1154 /**
1155  * Populate an empty topology with data from a simple geometry
1156  *
1157  * For ST_CreateTopoGeo
1158  *
1159  * @param topo the topology to operate on
1160  * @param geom the geometry to import
1161  *
1162  */
1163 void lwt_CreateTopoGeo(LWT_TOPOLOGY* topo, LWGEOM *geom);
1164 
1165 /**
1166  * Add an isolated node
1167  *
1168  * For ST_AddIsoNode
1169  *
1170  * @param topo the topology to operate on
1171  * @param face the identifier of containing face or -1 for "unknown"
1172  * @param pt the node position
1173  * @param skipChecks if non-zero skips consistency checks
1174  *                   (coincident nodes, crossing edges,
1175  *                    actual face containment)
1176  *
1177  * @return ID of the newly added node, or -1 on error
1178  *         (liblwgeom error handler will be invoked with error message)
1179  *
1180  */
1181 LWT_ELEMID lwt_AddIsoNode(LWT_TOPOLOGY* topo, LWT_ELEMID face,
1182                           LWPOINT* pt, int skipChecks);
1183 
1184 /**
1185  * Move an isolated node
1186  *
1187  * For ST_MoveIsoNode
1188  *
1189  * @param topo the topology to operate on
1190  * @param node the identifier of the nod to be moved
1191  * @param pt the new node position
1192  * @return 0 on success, -1 on error
1193  *         (liblwgeom error handler will be invoked with error message)
1194  *
1195  */
1196 int lwt_MoveIsoNode(LWT_TOPOLOGY* topo,
1197                     LWT_ELEMID node, LWPOINT* pt);
1198 
1199 /**
1200  * Remove an isolated node
1201  *
1202  * For ST_RemoveIsoNode
1203  *
1204  * @param topo the topology to operate on
1205  * @param node the identifier of the node to be moved
1206  * @return 0 on success, -1 on error
1207  *         (liblwgeom error handler will be invoked with error message)
1208  *
1209  */
1210 int lwt_RemoveIsoNode(LWT_TOPOLOGY* topo, LWT_ELEMID node);
1211 
1212 /**
1213  * Remove an isolated edge
1214  *
1215  * For ST_RemIsoEdge
1216  *
1217  * @param topo the topology to operate on
1218  * @param edge the identifier of the edge to be moved
1219  * @return 0 on success, -1 on error
1220  *         (liblwgeom error handler will be invoked with error message)
1221  *
1222  */
1223 int lwt_RemIsoEdge(LWT_TOPOLOGY* topo, LWT_ELEMID edge);
1224 
1225 /**
1226  * Add an isolated edge connecting two existing isolated nodes
1227  *
1228  * For ST_AddIsoEdge
1229  *
1230  * @param topo the topology to operate on
1231  * @param start_node identifier of the starting node
1232  * @param end_node identifier of the ending node
1233  * @param geom the edge geometry
1234  * @return ID of the newly added edge, or -1 on error
1235  *         (liblwgeom error handler will be invoked with error message)
1236  *
1237  */
1238 LWT_ELEMID lwt_AddIsoEdge(LWT_TOPOLOGY* topo,
1239                           LWT_ELEMID startNode, LWT_ELEMID endNode,
1240                           const LWLINE *geom);
1241 
1242 /**
1243  * Add a new edge possibly splitting a face (modifying it)
1244  *
1245  * For ST_AddEdgeModFace
1246  *
1247  * If the new edge splits a face, the face is shrunk and a new one
1248  * is created. Unless the face being split is the Universal Face, the
1249  * new face will be on the right side of the newly added edge.
1250  *
1251  * @param topo the topology to operate on
1252  * @param start_node identifier of the starting node
1253  * @param end_node identifier of the ending node
1254  * @param geom the edge geometry
1255  * @param skipChecks if non-zero skips consistency checks
1256  *                   (curve being simple and valid, start/end nodes
1257  *                    consistency actual face containment)
1258  *
1259  * @return ID of the newly added edge or null on error
1260  *         (liblwgeom error handler will be invoked with error message)
1261  *
1262  */
1263 LWT_ELEMID lwt_AddEdgeModFace(LWT_TOPOLOGY* topo,
1264                               LWT_ELEMID start_node, LWT_ELEMID end_node,
1265                               LWLINE *geom, int skipChecks);
1266 
1267 /**
1268  * Add a new edge possibly splitting a face (replacing with two new faces)
1269  *
1270  * For ST_AddEdgeNewFaces
1271  *
1272  * If the new edge splits a face, the face is replaced by two new faces.
1273  *
1274  * @param topo the topology to operate on
1275  * @param start_node identifier of the starting node
1276  * @param end_node identifier of the ending node
1277  * @param geom the edge geometry
1278  * @param skipChecks if non-zero skips consistency checks
1279  *                   (curve being simple and valid, start/end nodes
1280  *                    consistency actual face containment)
1281  * @return ID of the newly added edge
1282  *
1283  */
1284 LWT_ELEMID lwt_AddEdgeNewFaces(LWT_TOPOLOGY* topo,
1285                               LWT_ELEMID start_node, LWT_ELEMID end_node,
1286                               LWLINE *geom, int skipChecks);
1287 
1288 /**
1289  * Remove an edge, possibly merging two faces (replacing both with a new one)
1290  *
1291  * For ST_RemEdgeNewFace
1292  *
1293  * @param topo the topology to operate on
1294  * @param edge identifier of the edge to be removed
1295  * @return the id of newly created face, 0 if no new face was created
1296  *         or -1 on error
1297  *
1298  */
1299 LWT_ELEMID lwt_RemEdgeNewFace(LWT_TOPOLOGY* topo, LWT_ELEMID edge);
1300 
1301 /**
1302  * Remove an edge, possibly merging two faces (replacing one with the other)
1303  *
1304  * For ST_RemEdgeModFace
1305  *
1306  * Preferentially keep the face on the right, to be symmetric with
1307  * lwt_AddEdgeModFace.
1308  *
1309  * @param topo the topology to operate on
1310  * @param edge identifier of the edge to be removed
1311  * @return the id of the face that takes the space previously occupied
1312  *         by the removed edge, or -1 on error
1313  *         (liblwgeom error handler will be invoked with error message)
1314  *
1315  */
1316 LWT_ELEMID lwt_RemEdgeModFace(LWT_TOPOLOGY* topo, LWT_ELEMID edge);
1317 
1318 /**
1319  * Changes the shape of an edge without affecting the topology structure.
1320  *
1321  * For ST_ChangeEdgeGeom
1322  *
1323  * @param topo the topology to operate on
1324  * @param curve the edge geometry
1325  * @return 0 on success, -1 on error
1326  *         (liblwgeom error handler will be invoked with error message)
1327  *
1328  */
1329 int lwt_ChangeEdgeGeom(LWT_TOPOLOGY* topo, LWT_ELEMID edge, LWLINE* curve);
1330 
1331 /**
1332  * Split an edge by a node, modifying the original edge and adding a new one.
1333  *
1334  * For ST_ModEdgeSplit
1335  *
1336  * @param topo the topology to operate on
1337  * @param edge identifier of the edge to be split
1338  * @param pt geometry of the new node
1339  * @param skipChecks if non-zero skips consistency checks
1340  *                   (coincident node, point not on edge...)
1341  * @return the id of newly created node, or -1 on error
1342  *         (liblwgeom error handler will be invoked with error message)
1343  *
1344  */
1345 LWT_ELEMID lwt_ModEdgeSplit(LWT_TOPOLOGY* topo, LWT_ELEMID edge, LWPOINT* pt, int skipChecks);
1346 
1347 /**
1348  * Split an edge by a node, replacing it with two new edges
1349  *
1350  * For ST_NewEdgesSplit
1351  *
1352  * @param topo the topology to operate on
1353  * @param edge identifier of the edge to be split
1354  * @param pt geometry of the new node
1355  * @param skipChecks if non-zero skips consistency checks
1356  *                   (coincident node, point not on edge...)
1357  * @return the id of newly created node
1358  *
1359  */
1360 LWT_ELEMID lwt_NewEdgesSplit(LWT_TOPOLOGY* topo, LWT_ELEMID edge, LWPOINT* pt, int skipChecks);
1361 
1362 /**
1363  * Merge two edges, modifying the first and deleting the second
1364  *
1365  * For ST_ModEdgeHeal
1366  *
1367  * @param topo the topology to operate on
1368  * @param e1 identifier of first edge
1369  * @param e2 identifier of second edge
1370  * @return the id of the removed node or -1 on error
1371  *         (liblwgeom error handler will be invoked with error message)
1372  *
1373  */
1374 LWT_ELEMID lwt_ModEdgeHeal(LWT_TOPOLOGY* topo, LWT_ELEMID e1, LWT_ELEMID e2);
1375 
1376 /**
1377  * Merge two edges, replacing both with a new one
1378  *
1379  * For ST_NewEdgeHeal
1380  *
1381  * @param topo the topology to operate on
1382  * @param e1 identifier of first edge
1383  * @param e2 identifier of second edge
1384  * @return the id of the new edge or -1 on error
1385  *         (liblwgeom error handler will be invoked with error message)
1386  *
1387  */
1388 LWT_ELEMID lwt_NewEdgeHeal(LWT_TOPOLOGY* topo, LWT_ELEMID e1, LWT_ELEMID e2);
1389 
1390 /**
1391  * Return the list of directed edges bounding a face
1392  *
1393  * For ST_GetFaceEdges
1394  *
1395  * @param topo the topology to operate on
1396  * @param face identifier of the face
1397  * @param edges will be set to an array of signed edge identifiers, will
1398  *              need to be released with lwfree
1399  * @return the number of edges in the edges array, or -1 on error
1400  *         (liblwgeom error handler will be invoked with error message)
1401  *
1402  */
1403 int lwt_GetFaceEdges(LWT_TOPOLOGY* topo, LWT_ELEMID face, LWT_ELEMID **edges);
1404 
1405 /**
1406  * Return the geometry of a face
1407  *
1408  * For ST_GetFaceGeometry
1409  *
1410  * @param topo the topology to operate on
1411  * @param face identifier of the face
1412  * @return a polygon geometry representing the face, ownership to caller,
1413  *         to be released with lwgeom_release, or NULL on error
1414  *         (liblwgeom error handler will be invoked with error message)
1415  */
1416 LWGEOM* lwt_GetFaceGeometry(LWT_TOPOLOGY* topo, LWT_ELEMID face);
1417 
1418 #endif /* LIBLWGEOM_TOPO_H */
1419