PostGIS  3.0.6dev-r@@SVN_REVISION@@
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 
31 static int cmp_int(const void *a, const void *b);
32 static int cmp_int_ptr(const void *a, const void *b);
33 
34 UNIONFIND*
35 UF_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 
53 void
55 {
56  lwfree(uf->clusters);
57  lwfree(uf->cluster_sizes);
58  lwfree(uf);
59 }
60 
61 uint32_t
62 UF_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 
78 uint32_t
79 UF_size (UNIONFIND* uf, uint32_t i)
80 {
81  return uf->cluster_sizes[UF_find(uf, i)];
82 }
83 
84 void
85 UF_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 
112 uint32_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 
145 uint32_t*
146 UF_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 
179 static int
180 cmp_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 
196 static int
197 cmp_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:108
void lwfree(void *mem)
Definition: lwutil.c:242
void * lwalloc(size_t size)
Definition: lwutil.c:227
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:107
This library is the generic geometry handling section of PostGIS.
uint32_t * UF_get_collapsed_cluster_ids(UNIONFIND *uf, const char *is_in_cluster)
Definition: lwunionfind.c:146
void UF_destroy(UNIONFIND *uf)
Definition: lwunionfind.c:54
static int cmp_int_ptr(const void *a, const void *b)
Definition: lwunionfind.c:197
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
static int cmp_int(const void *a, const void *b)
Definition: lwunionfind.c:180
UNIONFIND * UF_create(uint32_t N)
Definition: lwunionfind.c:35
uint32_t * UF_ordered_by_cluster(UNIONFIND *uf)
Definition: lwunionfind.c:113
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