Coverage Report

Created: 2026-08-14 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgis/liblwgeom/lwhomogenize.c
Line
Count
Source
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 2010 Olivier Courtin <olivier.courtin@oslandia.com>
22
 *
23
 **********************************************************************/
24
25
26
#include <stdlib.h>
27
#include "liblwgeom_internal.h"
28
#include "lwgeom_log.h"
29
30
31
typedef struct {
32
  int cnt[NUMTYPES];
33
  LWCOLLECTION* buf[NUMTYPES];
34
} HomogenizeBuffer;
35
36
static void
37
init_homogenizebuffer(HomogenizeBuffer *buffer)
38
0
{
39
0
  int i;
40
0
  for ( i = 0; i < NUMTYPES; i++ )
41
0
  {
42
0
    buffer->cnt[i] = 0;
43
0
    buffer->buf[i] = NULL;
44
0
  }
45
0
}
46
47
/*
48
static void
49
free_homogenizebuffer(HomogenizeBuffer *buffer)
50
{
51
  int i;
52
  for ( i = 0; i < NUMTYPES; i++ )
53
  {
54
    if ( buffer->buf[i] )
55
    {
56
      lwcollection_free(buffer->buf[i]);
57
    }
58
  }
59
}
60
*/
61
62
/*
63
** Given a generic collection, return the "simplest" form.
64
**
65
** eg: GEOMETRYCOLLECTION(MULTILINESTRING()) => MULTILINESTRING()
66
**
67
**     GEOMETRYCOLLECTION(MULTILINESTRING(), MULTILINESTRING(), POINT())
68
**      => GEOMETRYCOLLECTION(MULTILINESTRING(), POINT())
69
**
70
** In general, if the subcomponents are homogeneous, return a properly
71
** typed collection.
72
** Otherwise, return a generic collection, with the subtypes in minimal
73
** typed collections.
74
*/
75
static void
76
lwcollection_build_buffer(const LWCOLLECTION *col, HomogenizeBuffer *buffer)
77
0
{
78
0
  uint32_t i;
79
80
0
  if (!col || lwcollection_is_empty(col))
81
0
    return;
82
83
0
  for (i = 0; i < col->ngeoms; i++)
84
0
  {
85
0
    LWGEOM *geom = col->geoms[i];
86
0
    switch (geom->type)
87
0
    {
88
0
    case POINTTYPE:
89
0
    case LINETYPE:
90
0
    case CIRCSTRINGTYPE:
91
0
    case COMPOUNDTYPE:
92
0
    case NURBSCURVETYPE:
93
0
    case TRIANGLETYPE:
94
0
    case CURVEPOLYTYPE:
95
0
    case POLYGONTYPE:
96
      /* Init if necessary */
97
0
      if (!buffer->buf[geom->type])
98
0
      {
99
0
        LWCOLLECTION *bufcol = lwcollection_construct_empty(
100
0
            COLLECTIONTYPE, col->srid, FLAGS_GET_Z(col->flags), FLAGS_GET_M(col->flags));
101
0
        bufcol->type = lwtype_get_collectiontype(geom->type);
102
0
        buffer->buf[geom->type] = bufcol;
103
0
      }
104
      /* Add sub-geom to buffer */
105
0
      lwcollection_add_lwgeom(buffer->buf[geom->type], lwgeom_clone_deep(geom));
106
      /* Increment count for this singleton type */
107
0
      buffer->cnt[geom->type]++;
108
0
      break;
109
0
    default:
110
0
      lwcollection_build_buffer(lwgeom_as_lwcollection(geom), buffer);
111
0
      break;
112
0
    }
113
0
  }
114
0
}
115
116
static LWGEOM*
117
lwcollection_homogenize(const LWCOLLECTION *col)
118
0
{
119
0
  int i;
120
0
  int ntypes = 0;
121
0
  int type = 0;
122
0
  LWGEOM *outgeom = NULL;
123
124
0
  HomogenizeBuffer buffer;
125
126
  /* Sort all the parts into a buffer */
127
0
  init_homogenizebuffer(&buffer);
128
0
  lwcollection_build_buffer(col, &buffer);
129
130
  /* Check for homogeneity */
131
0
  for ( i = 0; i < NUMTYPES; i++ )
132
0
  {
133
0
    if ( buffer.cnt[i] > 0 )
134
0
    {
135
0
      ntypes++;
136
0
      type = i;
137
0
    }
138
0
  }
139
140
  /* No types? Huh. Return empty. */
141
0
  if ( ntypes == 0 )
142
0
  {
143
0
    LWCOLLECTION *outcol;
144
0
    outcol = lwcollection_construct_empty(COLLECTIONTYPE, col->srid, FLAGS_GET_Z(col->flags), FLAGS_GET_M(col->flags));
145
0
    outgeom = lwcollection_as_lwgeom(outcol);
146
0
  }
147
  /* One type, return homogeneous collection */
148
0
  else if ( ntypes == 1 )
149
0
  {
150
0
    LWCOLLECTION *outcol;
151
0
    outcol = buffer.buf[type];
152
0
    if ( outcol->ngeoms == 1 )
153
0
    {
154
0
      outgeom = outcol->geoms[0];
155
0
      outcol->ngeoms=0; lwcollection_free(outcol);
156
0
    }
157
0
    else
158
0
    {
159
0
      outgeom = lwcollection_as_lwgeom(outcol);
160
0
    }
161
0
    outgeom->srid = col->srid;
162
0
  }
163
  /* Bah, more than out type, return anonymous collection */
164
0
  else if ( ntypes > 1 )
165
0
  {
166
0
    int j;
167
0
    LWCOLLECTION *outcol;
168
0
    outcol = lwcollection_construct_empty(COLLECTIONTYPE, col->srid, FLAGS_GET_Z(col->flags), FLAGS_GET_M(col->flags));
169
0
    for ( j = 0; j < NUMTYPES; j++ )
170
0
    {
171
0
      if ( buffer.buf[j] )
172
0
      {
173
0
        LWCOLLECTION *bcol = buffer.buf[j];
174
0
        if ( bcol->ngeoms == 1 )
175
0
        {
176
0
          lwcollection_add_lwgeom(outcol, bcol->geoms[0]);
177
0
          bcol->ngeoms=0; lwcollection_free(bcol);
178
0
        }
179
0
        else
180
0
        {
181
0
          lwcollection_add_lwgeom(outcol, lwcollection_as_lwgeom(bcol));
182
0
        }
183
0
      }
184
0
    }
185
0
    outgeom = lwcollection_as_lwgeom(outcol);
186
0
  }
187
188
0
  return outgeom;
189
0
}
190
191
192
193
194
195
/*
196
** Given a generic geometry, return the "simplest" form.
197
**
198
** eg:
199
**     LINESTRING() => LINESTRING()
200
**
201
**     MULTILINESTRING(with a single line) => LINESTRING()
202
**
203
**     GEOMETRYCOLLECTION(MULTILINESTRING()) => MULTILINESTRING()
204
**
205
**     GEOMETRYCOLLECTION(MULTILINESTRING(), MULTILINESTRING(), POINT())
206
**      => GEOMETRYCOLLECTION(MULTILINESTRING(), POINT())
207
*/
208
LWGEOM *
209
lwgeom_homogenize(const LWGEOM *geom)
210
0
{
211
0
  LWGEOM *hgeom;
212
213
  /* EMPTY Geometry */
214
0
  if (lwgeom_is_empty(geom))
215
0
  {
216
0
    if( lwgeom_is_collection(geom) )
217
0
    {
218
0
      return lwcollection_as_lwgeom(lwcollection_construct_empty(geom->type, geom->srid, lwgeom_has_z(geom), lwgeom_has_m(geom)));
219
0
    }
220
221
0
    return lwgeom_clone_deep(geom);
222
0
  }
223
224
0
  switch (geom->type)
225
0
  {
226
227
    /* Return simple geometries untouched */
228
0
    case POINTTYPE:
229
0
    case LINETYPE:
230
0
    case CIRCSTRINGTYPE:
231
0
    case COMPOUNDTYPE:
232
0
    case NURBSCURVETYPE:
233
0
    case TRIANGLETYPE:
234
0
    case CURVEPOLYTYPE:
235
0
    case POLYGONTYPE:
236
0
      return lwgeom_clone_deep(geom);
237
238
    /* Process homogeneous geometries lightly */
239
0
    case MULTIPOINTTYPE:
240
0
    case MULTILINETYPE:
241
0
    case MULTIPOLYGONTYPE:
242
0
    case MULTICURVETYPE:
243
0
    case MULTISURFACETYPE:
244
0
    case POLYHEDRALSURFACETYPE:
245
0
    case TINTYPE:
246
0
    {
247
0
      LWCOLLECTION *col = (LWCOLLECTION*)geom;
248
249
      /* Strip single-entry multi-geometries down to singletons */
250
0
      if ( col->ngeoms == 1 )
251
0
      {
252
0
        hgeom = lwgeom_clone_deep((LWGEOM *)(col->geoms[0]));
253
0
        hgeom->srid = geom->srid;
254
0
        if (geom->bbox)
255
0
          hgeom->bbox = gbox_copy(geom->bbox);
256
0
        return hgeom;
257
0
      }
258
259
      /* Return proper multigeometry untouched */
260
0
      return lwgeom_clone_deep(geom);
261
0
    }
262
263
    /* Work on anonymous collections separately */
264
0
    case COLLECTIONTYPE:
265
0
      return lwcollection_homogenize((LWCOLLECTION *) geom);
266
0
  }
267
268
  /* Unknown type */
269
0
  lwerror("lwgeom_homogenize: Geometry Type not supported (%s)",
270
0
          lwtype_name(geom->type));
271
272
  return NULL; /* Never get here! */
273
0
}