Coverage Report

Created: 2026-04-16 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgis/liblwgeom/lwpsurface.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 (C) 2001-2006 Refractions Research Inc.
22
 *
23
 **********************************************************************/
24
25
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <string.h>
29
#include "liblwgeom_internal.h"
30
#include "lwgeom_log.h"
31
32
33
LWPSURFACE* lwpsurface_add_lwpoly(LWPSURFACE *mobj, const LWPOLY *obj)
34
0
{
35
0
  return (LWPSURFACE*)lwcollection_add_lwgeom((LWCOLLECTION*)mobj, (LWGEOM*)obj);
36
0
}
37
38
39
void lwpsurface_free(LWPSURFACE *psurf)
40
2.99k
{
41
2.99k
  uint32_t i;
42
2.99k
  if ( ! psurf ) return;
43
2.99k
  if ( psurf->bbox )
44
0
    lwfree(psurf->bbox);
45
46
25.2k
  for ( i = 0; i < psurf->ngeoms; i++ )
47
22.2k
    if ( psurf->geoms && psurf->geoms[i] )
48
22.2k
      lwpoly_free(psurf->geoms[i]);
49
50
2.99k
  if ( psurf->geoms )
51
2.99k
    lwfree(psurf->geoms);
52
53
2.99k
  lwfree(psurf);
54
2.99k
}
55
56
57
void printLWPSURFACE(LWPSURFACE *psurf)
58
0
{
59
0
  uint32_t i, j;
60
0
  LWPOLY *patch;
61
62
0
  if (psurf->type != POLYHEDRALSURFACETYPE)
63
0
    lwerror("printLWPSURFACE called with something else than a POLYHEDRALSURFACE");
64
65
0
  lwnotice("LWPSURFACE {");
66
0
  lwnotice("    ndims = %i", (int)FLAGS_NDIMS(psurf->flags));
67
0
  lwnotice("    SRID = %i", (int)psurf->srid);
68
0
  lwnotice("    ngeoms = %i", (int)psurf->ngeoms);
69
70
0
  for (i=0; i<psurf->ngeoms; i++)
71
0
  {
72
0
    patch = (LWPOLY *) psurf->geoms[i];
73
0
    for (j=0; j<patch->nrings; j++)
74
0
    {
75
0
      lwnotice("    RING # %i :",j);
76
0
      printPA(patch->rings[j]);
77
0
    }
78
0
  }
79
0
  lwnotice("}");
80
0
}
81
82
83
84
85
/*
86
 * TODO rewrite all this stuff to be based on a truly topological model
87
 */
88
89
struct struct_psurface_arcs
90
{
91
  double ax, ay, az;
92
  double bx, by, bz;
93
  uint32_t cnt, face;
94
};
95
typedef struct struct_psurface_arcs *psurface_arcs;
96
97
/* We supposed that the geometry is valid
98
   we could have wrong result if not */
99
int lwpsurface_is_closed(const LWPSURFACE *psurface)
100
0
{
101
0
  uint32_t i, j, k;
102
0
  uint32_t narcs, carc;
103
0
  int found;
104
0
  psurface_arcs arcs;
105
0
  POINT4D pa, pb;
106
0
  LWPOLY *patch;
107
108
  /* If surface is not 3D, it's can't be closed */
109
0
  if (!FLAGS_GET_Z(psurface->flags)) return 0;
110
111
  /* If surface is less than 4 faces hard to be closed too */
112
0
  if (psurface->ngeoms < 4) return 0;
113
114
  /* Max theoretical arcs number if no one is shared ... */
115
0
  for (i=0, narcs=0 ; i < psurface->ngeoms ; i++)
116
0
  {
117
0
    patch = (LWPOLY *) psurface->geoms[i];
118
0
    narcs += patch->rings[0]->npoints - 1;
119
0
  }
120
121
0
  arcs = lwalloc(sizeof(struct struct_psurface_arcs) * narcs);
122
0
  for (i=0, carc=0; i < psurface->ngeoms ; i++)
123
0
  {
124
125
0
    patch = (LWPOLY *) psurface->geoms[i];
126
0
    for (j=0; j < patch->rings[0]->npoints - 1; j++)
127
0
    {
128
129
0
      getPoint4d_p(patch->rings[0], j,   &pa);
130
0
      getPoint4d_p(patch->rings[0], j+1, &pb);
131
132
      /* remove redundant points if any */
133
0
      if (pa.x == pb.x && pa.y == pb.y && pa.z == pb.z) continue;
134
135
      /* Make sure to order the 'lower' point first */
136
0
      if ( (pa.x > pb.x) ||
137
0
              (pa.x == pb.x && pa.y > pb.y) ||
138
0
              (pa.x == pb.x && pa.y == pb.y && pa.z > pb.z) )
139
0
      {
140
0
        pa = pb;
141
0
        getPoint4d_p(patch->rings[0], j, &pb);
142
0
      }
143
144
0
      for (found=0, k=0; k < carc ; k++)
145
0
      {
146
147
0
        if (  ( arcs[k].ax == pa.x && arcs[k].ay == pa.y &&
148
0
                arcs[k].az == pa.z && arcs[k].bx == pb.x &&
149
0
                arcs[k].by == pb.y && arcs[k].bz == pb.z &&
150
0
                arcs[k].face != i) )
151
0
        {
152
0
          arcs[k].cnt++;
153
0
          found = 1;
154
155
          /* Look like an invalid PolyhedralSurface
156
                anyway not a closed one */
157
0
          if (arcs[k].cnt > 2)
158
0
          {
159
0
            lwfree(arcs);
160
0
            return 0;
161
0
          }
162
0
        }
163
0
      }
164
165
0
      if (!found)
166
0
      {
167
0
        arcs[carc].cnt=1;
168
0
        arcs[carc].face=i;
169
0
        arcs[carc].ax = pa.x;
170
0
        arcs[carc].ay = pa.y;
171
0
        arcs[carc].az = pa.z;
172
0
        arcs[carc].bx = pb.x;
173
0
        arcs[carc].by = pb.y;
174
0
        arcs[carc].bz = pb.z;
175
0
        carc++;
176
177
        /* Look like an invalid PolyhedralSurface
178
              anyway not a closed one */
179
0
        if (carc > narcs)
180
0
        {
181
0
          lwfree(arcs);
182
0
          return 0;
183
0
        }
184
0
      }
185
0
    }
186
0
  }
187
188
  /* A polyhedron is closed if each edge
189
         is shared by exactly 2 faces */
190
0
  for (k=0; k < carc ; k++)
191
0
  {
192
0
    if (arcs[k].cnt != 2)
193
0
    {
194
0
      lwfree(arcs);
195
0
      return 0;
196
0
    }
197
0
  }
198
0
  lwfree(arcs);
199
200
  /* Invalid Polyhedral case */
201
0
  if (carc < psurface->ngeoms) return 0;
202
203
0
  return 1;
204
0
}