PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches

◆ ST_ClusterDBSCAN()

Datum ST_ClusterDBSCAN ( PG_FUNCTION_ARGS  )
extern

Definition at line 120 of file lwgeom_window.c.

121{
122 WindowObject win_obj = PG_WINDOW_OBJECT();
123 uint32_t row = WinGetCurrentPosition(win_obj);
124 uint32_t ngeoms = WinGetPartitionRowCount(win_obj);
125 cluster_context* context = fetch_cluster_context(win_obj, ngeoms);
126
127 if (row == 0) /* beginning of the partition; do all of the work now */
128 {
129 uint32_t i;
130 uint32_t* result_ids;
131 LWGEOM** geoms;
132 char* is_in_cluster = NULL;
133 UNIONFIND* uf;
134 bool tolerance_is_null;
135 bool minpoints_is_null;
136 Datum tolerance_datum = WinGetFuncArgCurrent(win_obj, 1, &tolerance_is_null);
137 Datum minpoints_datum = WinGetFuncArgCurrent(win_obj, 2, &minpoints_is_null);
138 double tolerance = DatumGetFloat8(tolerance_datum);
139 int minpoints = DatumGetInt32(minpoints_datum);
140
141 context->is_error = LW_TRUE; /* until proven otherwise */
142
143 /* Validate input parameters */
144 if (tolerance_is_null || tolerance < 0)
145 {
146 lwpgerror("Tolerance must be a positive number, got %g", tolerance);
147 PG_RETURN_NULL();
148 }
149 if (minpoints_is_null || minpoints < 0)
150 {
151 lwpgerror("Minpoints must be a positive number, got %d", minpoints);
152 }
153
154 initGEOS(lwpgnotice, lwgeom_geos_error);
155 geoms = lwalloc(ngeoms * sizeof(LWGEOM*));
156 uf = UF_create(ngeoms);
157 for (i = 0; i < ngeoms; i++)
158 {
159 bool geom_is_null;
160 geoms[i] = read_lwgeom_from_partition(win_obj, i, &geom_is_null);
161 context->clusters[i].is_null = geom_is_null;
162
163 if (!geoms[i]) {
164 /* TODO release memory ? */
165 lwpgerror("Error reading geometry.");
166 PG_RETURN_NULL();
167 }
168 }
169
170 if (union_dbscan(geoms, ngeoms, uf, tolerance, minpoints, minpoints > 1 ? &is_in_cluster : NULL) == LW_SUCCESS)
171 context->is_error = LW_FALSE;
172
173 for (i = 0; i < ngeoms; i++)
174 {
175 lwgeom_free(geoms[i]);
176 }
177 lwfree(geoms);
178
179 if (context->is_error)
180 {
181 UF_destroy(uf);
182 if (is_in_cluster)
183 lwfree(is_in_cluster);
184 lwpgerror("Error during clustering");
185 PG_RETURN_NULL();
186 }
187
188 result_ids = UF_get_collapsed_cluster_ids(uf, is_in_cluster);
189 for (i = 0; i < ngeoms; i++)
190 {
191 if (minpoints > 1 && !is_in_cluster[i])
192 {
193 context->clusters[i].is_null = LW_TRUE;
194 }
195 else
196 {
197 context->clusters[i].cluster_id = result_ids[i];
198 }
199 }
200
201 lwfree(result_ids);
202 UF_destroy(uf);
203 }
204
205 if (context->clusters[row].is_null)
206 PG_RETURN_NULL();
207
208 PG_RETURN_INT32(context->clusters[row].cluster_id);
209}
void lwgeom_geos_error(const char *fmt,...)
int union_dbscan(LWGEOM **geoms, uint32_t num_geoms, UNIONFIND *uf, double eps, uint32_t min_points, char **is_in_cluster_ret)
#define LW_FALSE
Definition liblwgeom.h:94
void lwgeom_free(LWGEOM *geom)
Definition lwgeom.c:1246
#define LW_SUCCESS
Definition liblwgeom.h:97
void * lwalloc(size_t size)
Definition lwutil.c:227
void lwfree(void *mem)
Definition lwutil.c:248
#define LW_TRUE
Return types for functions with status returns.
Definition liblwgeom.h:93
static LWGEOM * read_lwgeom_from_partition(WindowObject win_obj, uint32_t i, bool *is_null)
static cluster_context * fetch_cluster_context(WindowObject win_obj, uint32_t ngeoms)
void UF_destroy(UNIONFIND *uf)
Definition lwunionfind.c:54
UNIONFIND * UF_create(uint32_t N)
Definition lwunionfind.c:35
uint32_t * UF_get_collapsed_cluster_ids(UNIONFIND *uf, const char *is_in_cluster)
cluster_entry clusters[1]
uint32_t cluster_id
char is_null

References cluster_entry::cluster_id, cluster_context::clusters, fetch_cluster_context(), cluster_context::is_error, cluster_entry::is_null, LW_FALSE, LW_SUCCESS, LW_TRUE, lwalloc(), lwfree(), lwgeom_free(), lwgeom_geos_error(), read_lwgeom_from_partition(), UF_create(), UF_destroy(), UF_get_collapsed_cluster_ids(), and union_dbscan().

Here is the call graph for this function: