PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
lwunionfind.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 2015 Daniel Baston <dbaston@gmail.com>
22 *
23 **********************************************************************/
24
25
26#include "liblwgeom.h"
27#include "lwunionfind.h"
28#include <string.h>
29#include <stdlib.h>
30
31static int cmp_int(const void *a, const void *b);
32static int cmp_int_ptr(const void *a, const void *b);
33
35UF_create(uint32_t N)
36{
37 size_t i;
38 UNIONFIND* uf = lwalloc(sizeof(UNIONFIND));
39 uf->N = N;
40 uf->num_clusters = N;
41 uf->clusters = lwalloc(N * sizeof(uint32_t));
42 uf->cluster_sizes = lwalloc(N * sizeof(uint32_t));
43
44 for (i = 0; i < N; i++)
45 {
46 uf->clusters[i] = i;
47 uf->cluster_sizes[i] = 1;
48 }
49
50 return uf;
51}
52
53void
55{
56 lwfree(uf->clusters);
58 lwfree(uf);
59}
60
61uint32_t
62UF_find (UNIONFIND* uf, uint32_t i)
63{
64 uint32_t base = i;
65 while (uf->clusters[base] != base) {
66 base = uf->clusters[base];
67 }
68
69 while (i != base) {
70 uint32_t next = uf->clusters[i];
71 uf->clusters[i] = base;
72 i = next;
73 }
74
75 return i;
76}
77
78uint32_t
79UF_size (UNIONFIND* uf, uint32_t i)
80{
81 return uf->cluster_sizes[UF_find(uf, i)];
82}
83
84void
85UF_union(UNIONFIND* uf, uint32_t i, uint32_t j)
86{
87 uint32_t a = UF_find(uf, i);
88 uint32_t b = UF_find(uf, j);
89
90 if (a == b)
91 {
92 return;
93 }
94
95 if (uf->cluster_sizes[a] < uf->cluster_sizes[b] ||
96 (uf->cluster_sizes[a] == uf->cluster_sizes[b] && a > b))
97 {
98 uf->clusters[a] = uf->clusters[b];
99 uf->cluster_sizes[b] += uf->cluster_sizes[a];
100 uf->cluster_sizes[a] = 0;
101 }
102 else
103 {
104 uf->clusters[b] = uf->clusters[a];
105 uf->cluster_sizes[a] += uf->cluster_sizes[b];
106 uf->cluster_sizes[b] = 0;
107 }
108
109 uf->num_clusters--;
110}
111
112uint32_t*
114{
115 size_t i;
116 uint32_t** cluster_id_ptr_by_elem_id = lwalloc(uf->N * sizeof (uint32_t*));
117 uint32_t* ordered_ids = lwalloc(uf->N * sizeof (uint32_t));
118
119 for (i = 0; i < uf->N; i++)
120 {
121 /* Make sure each value in uf->clusters is pointing to the
122 * root of the cluster.
123 * */
124 UF_find(uf, i);
125 cluster_id_ptr_by_elem_id[i] = &(uf->clusters[i]);
126 }
127
128 /* Sort the array of cluster id pointers, so that pointers to the
129 * same cluster id are grouped together.
130 * */
131 qsort(cluster_id_ptr_by_elem_id, uf->N, sizeof (uint32_t*), &cmp_int_ptr);
132
133 /* Recover the input element ids from the cluster id pointers, so
134 * we can return element ids grouped by cluster id.
135 * */
136 for (i = 0; i < uf-> N; i++)
137 {
138 ordered_ids[i] = (cluster_id_ptr_by_elem_id[i] - uf->clusters);
139 }
140
141 lwfree(cluster_id_ptr_by_elem_id);
142 return ordered_ids;
143}
144
145uint32_t*
146UF_get_collapsed_cluster_ids(UNIONFIND* uf, const char* is_in_cluster)
147{
148 uint32_t* ordered_components = UF_ordered_by_cluster(uf);
149 uint32_t* new_ids = lwalloc(uf->N * sizeof(uint32_t));
150 uint32_t last_old_id, current_new_id, i;
151 char encountered_cluster = LW_FALSE;
152
153 current_new_id = 0; last_old_id = 0;
154 for (i = 0; i < uf->N; i++)
155 {
156 uint32_t j = ordered_components[i];
157 if (!is_in_cluster || is_in_cluster[j])
158 {
159 uint32_t current_old_id = UF_find(uf, j);
160 if (!encountered_cluster)
161 {
162 encountered_cluster = LW_TRUE;
163 last_old_id = current_old_id;
164 }
165
166 if (current_old_id != last_old_id)
167 current_new_id++;
168
169 new_ids[j] = current_new_id;
170 last_old_id = current_old_id;
171 }
172 }
173
174 lwfree(ordered_components);
175
176 return new_ids;
177}
178
179static int
180cmp_int(const void *a, const void *b)
181{
182 if (*((uint32_t*) a) > *((uint32_t*) b))
183 {
184 return 1;
185 }
186 else if (*((uint32_t*) a) < *((uint32_t*) b))
187 {
188 return -1;
189 }
190 else
191 {
192 return 0;
193 }
194}
195
196static int
197cmp_int_ptr(const void *a, const void *b)
198{
199 int val_cmp = cmp_int(*((uint32_t**) a), *((uint32_t**) b));
200 if (val_cmp != 0)
201 {
202 return val_cmp;
203 }
204 if (a > b)
205 {
206 return 1;
207 }
208 if (a < b)
209 {
210 return -1;
211 }
212 return 0;
213}
#define LW_FALSE
Definition liblwgeom.h:94
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
This library is the generic geometry handling section of PostGIS.
void UF_destroy(UNIONFIND *uf)
Definition lwunionfind.c:54
static int cmp_int_ptr(const void *a, const void *b)
uint32_t UF_find(UNIONFIND *uf, uint32_t i)
Definition lwunionfind.c:62
uint32_t UF_size(UNIONFIND *uf, uint32_t i)
Definition lwunionfind.c:79
uint32_t * UF_ordered_by_cluster(UNIONFIND *uf)
static int cmp_int(const void *a, const void *b)
UNIONFIND * UF_create(uint32_t N)
Definition lwunionfind.c:35
uint32_t * UF_get_collapsed_cluster_ids(UNIONFIND *uf, const char *is_in_cluster)
void UF_union(UNIONFIND *uf, uint32_t i, uint32_t j)
Definition lwunionfind.c:85
uint32_t N
Definition lwunionfind.h:36
uint32_t * cluster_sizes
Definition lwunionfind.h:34
uint32_t * clusters
Definition lwunionfind.h:33
uint32_t num_clusters
Definition lwunionfind.h:35