PostGIS  3.7.0dev-r@@SVN_REVISION@@
lwt_edgeend_star.c
Go to the documentation of this file.
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) 2024 Sandro Santilli <strk@kbt.io>
22  *
23  **********************************************************************/
24 
25 #include "../postgis_config.h"
26 
27 //#define POSTGIS_DEBUG_LEVEL 1
28 #include "lwgeom_log.h"
29 
30 #include "liblwgeom_internal.h"
32 
33 #include "lwt_edgeend_star.h"
34 #include "lwt_edgeend.h"
35 
36 #include <inttypes.h>
37 
40 {
41  LWT_EDGEEND_STAR *star = lwalloc(sizeof(LWT_EDGEEND_STAR));
42  star->numEdgeEnds = 0;
43  star->edgeEndsCapacity = 0;
44  star->edgeEnds = NULL;
45  star->nodeID = nodeID;
46  star->sorted = 0;
47 
48  return star;
49 }
50 
51 void
53 {
54  uint64_t i;
55  for (i=0; i<star->edgeEndsCapacity; ++i)
56  {
57  lwfree( star->edgeEnds[i] );
58  }
59  if ( star->edgeEndsCapacity ) {
60  lwfree( star->edgeEnds );
61  }
62  lwfree( star );
63 }
64 
65 void
67 {
68  int numEdgeEnds = 0;
69  LWT_EDGEEND *edgeEnds[2];
70  uint64_t newCapacity;
71 
72  if ( edge->start_node == star->nodeID )
73  {
74  LWT_EDGEEND *ee = lwt_edgeEnd_fromEdge( edge, 1 );
75  if ( ! ee ) {
76  lwerror("Could not construct outgoing EdgeEnd for edge %"
77  LWTFMT_ELEMID, edge->edge_id);
78  return;
79  }
80  edgeEnds[numEdgeEnds++] = ee;
81  }
82  if ( edge->end_node == star->nodeID )
83  {
84  LWT_EDGEEND *ee = lwt_edgeEnd_fromEdge( edge, 0 );
85  if ( ! ee ) {
86  lwerror("Could not construct outgoing incoming for edge %"
87  LWTFMT_ELEMID, edge->edge_id);
88  return;
89  }
90  edgeEnds[numEdgeEnds++] = ee;
91  }
92 
93  if ( ! numEdgeEnds )
94  {
95  lwerror("Edge %" LWTFMT_ELEMID
96  " doesn't start nor end on star node %" LWTFMT_ELEMID,
97  edge->edge_id, star->nodeID);
98  return;
99  }
100 
101  LWDEBUGF(1, "Edge %" LWTFMT_ELEMID
102  " got %d" " ends incident to star node %" LWTFMT_ELEMID,
103  edge->edge_id, numEdgeEnds, star->nodeID );
104 
105  newCapacity = star->numEdgeEnds + numEdgeEnds;
106  LWDEBUGF(3, "Current star capacity:%lld, required:%lld",
107  star->edgeEndsCapacity, newCapacity);
108  if ( newCapacity > star->edgeEndsCapacity )
109  {
110  LWDEBUGF(3, "Reallocating edgeEnds from %p to new size %lld", star->edgeEnds, newCapacity * sizeof(LWT_EDGEEND *));
111  if ( star->edgeEnds ) {
112  star->edgeEnds = lwrealloc(star->edgeEnds, newCapacity * sizeof(LWT_EDGEEND *));
113  } else {
114  star->edgeEnds = lwalloc(newCapacity * sizeof(LWT_EDGEEND *));
115  }
116  LWDEBUGF(3, "Reallocated edgeEnds are %p", star->edgeEnds);
117  star->edgeEndsCapacity = newCapacity;
118  LWDEBUGF(3, "New star capacity: %lld", newCapacity);
119  }
120 
121  for (int i=0; i<numEdgeEnds; ++i)
122  {
123  star->edgeEnds[ star->numEdgeEnds++ ] = edgeEnds[i];
124  }
125  star->sorted = 0;
126 }
127 
128 static int
129 lwt_edgeEnd_compare(const void *i1, const void *i2)
130 {
131  const LWT_EDGEEND *ee1 = *(const LWT_EDGEEND **)i1;
132  const LWT_EDGEEND *ee2 = *(const LWT_EDGEEND **)i2;
133  int ret;
134  if ( ee1->azimuth < ee2->azimuth )
135  ret = -1;
136  else if ( ee1->azimuth > ee2->azimuth )
137  ret = 1;
138  else
139  ret = 0;
140 
141  LWDEBUGF(4, "qsort comparator for %s edge %lld with azimuth %g and %s edge %lld with azimuth %g returning %d",
142  ee1->outgoing ? "outgoing" : "incoming", ee1->edge->edge_id, ee1->azimuth,
143  ee2->outgoing ? "outgoing" : "incoming", ee2->edge->edge_id, ee2->azimuth,
144  ret
145  );
146 
147  return ret;
148 }
149 
150 static void
152 {
153  if ( star->sorted ) return; // nothing to do
154  qsort( star->edgeEnds, star->numEdgeEnds, sizeof(LWT_EDGEEND *), lwt_edgeEnd_compare);
155  star->sorted = 1;
156 }
157 
158 void
160 {
161  lwdebug(1, "Star around node %" LWTFMT_ELEMID " has %" PRIu64 " edgeEnds, %s",
162  star->nodeID, star->numEdgeEnds, star->sorted ? "sorted" : "unsorted" );
163  for ( uint64_t i=0; i<star->numEdgeEnds; ++i )
164  {
165  LWT_EDGEEND *ee = star->edgeEnds[i];
166  lwdebug(1, " EdgeEnd %" PRIu64 " is %s edge %" LWTFMT_ELEMID ", azimuth=%.15g",
167  i, ee->outgoing ? "outgoing" : "incoming",
168  ee->edge->edge_id, ee->azimuth
169  );
170  }
171 }
172 
173 const LWT_EDGEEND *
175 {
177 
178  uint64_t i=0;
179  LWT_EDGEEND *thisEdgeEnd = NULL;
180  for ( i=0; i<star->numEdgeEnds; ++i )
181  {
182  LWT_EDGEEND *ee = star->edgeEnds[i];
183  if ( ee->edge == edge && ee->outgoing == outgoing ) {
184  thisEdgeEnd = ee;
185  break;
186  }
187  }
188  if ( ! thisEdgeEnd ) {
189  lwerror("Could not find %s edge %" LWTFMT_ELEMID " in the star",
190  outgoing ? "outgoing" : "incoming", edge->edge_id);
191  return NULL;
192  }
193  LWT_EDGEEND *nextEdgeEnd = i < star->numEdgeEnds-1 ? star->edgeEnds[i+1] : star->edgeEnds[0];
194  return nextEdgeEnd;
195 }
196 
197 const LWT_EDGEEND *
199 {
201 
202  uint64_t i=0;
203  LWT_EDGEEND *thisEdgeEnd = NULL;
204  for ( i=0; i<star->numEdgeEnds; ++i )
205  {
206  LWT_EDGEEND *ee = star->edgeEnds[i];
207  if ( ee->edge == edge && ee->outgoing == outgoing ) {
208  thisEdgeEnd = ee;
209  break;
210  }
211  }
212  if ( ! thisEdgeEnd ) {
213  lwerror("Could not find %s edge %" LWTFMT_ELEMID " in the star",
214  outgoing ? "outgoing" : "incoming", edge->edge_id);
215  return NULL;
216  }
217  LWT_EDGEEND *nextEdgeEnd = i > 0 ? star->edgeEnds[i-1] : star->edgeEnds[star->numEdgeEnds-1];
218  return nextEdgeEnd;
219 }
void * lwrealloc(void *mem, size_t size)
Definition: lwutil.c:242
void lwfree(void *mem)
Definition: lwutil.c:248
void * lwalloc(size_t size)
Definition: lwutil.c:227
LWT_INT64 LWT_ELEMID
Identifier of topology element.
#define LWTFMT_ELEMID
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:106
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
void void void lwdebug(int level, const char *fmt,...) __attribute__((format(printf
Write a debug message out.
LWT_EDGEEND * lwt_edgeEnd_fromEdge(const LWT_ISO_EDGE *edge, int outgoing)
Definition: lwt_edgeend.c:68
static void lwt_edgeEndStar_ensureSorted(LWT_EDGEEND_STAR *star)
const LWT_EDGEEND * lwt_edgeEndStar_getNextCW(LWT_EDGEEND_STAR *star, LWT_ISO_EDGE *edge, int outgoing)
LWT_EDGEEND_STAR * lwt_edgeEndStar_init(LWT_ELEMID nodeID)
static int lwt_edgeEnd_compare(const void *i1, const void *i2)
const LWT_EDGEEND * lwt_edgeEndStar_getNextCCW(LWT_EDGEEND_STAR *star, LWT_ISO_EDGE *edge, int outgoing)
void lwt_edgeEndStar_release(LWT_EDGEEND_STAR *star)
void lwt_EdgeEndStar_debugPrint(const LWT_EDGEEND_STAR *star)
void lwt_edgeEndStar_addEdge(LWT_EDGEEND_STAR *star, const LWT_ISO_EDGE *edge)
LWT_EDGEEND ** edgeEnds
double azimuth
Definition: lwt_edgeend.h:37
const LWT_ISO_EDGE * edge
Definition: lwt_edgeend.h:33
LWT_ELEMID end_node
LWT_ELEMID edge_id
LWT_ELEMID start_node