Coverage Report

Created: 2026-06-23 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgis/liblwgeom/lwtin.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
30
#include "liblwgeom_internal.h"
31
#include "lwgeom_log.h"
32
33
34
LWTIN* lwtin_add_lwtriangle(LWTIN *mobj, const LWTRIANGLE *obj)
35
0
{
36
0
  return (LWTIN*)lwcollection_add_lwgeom((LWCOLLECTION*)mobj, (LWGEOM*)obj);
37
0
}
38
39
void lwtin_free(LWTIN *tin)
40
7.76k
{
41
7.76k
  uint32_t i;
42
7.76k
  if ( ! tin ) return;
43
7.76k
  if ( tin->bbox )
44
0
    lwfree(tin->bbox);
45
46
9.06k
  for ( i = 0; i < tin->ngeoms; i++ )
47
1.30k
    if ( tin->geoms && tin->geoms[i] )
48
1.30k
      lwtriangle_free(tin->geoms[i]);
49
50
7.76k
  if ( tin->geoms )
51
7.76k
    lwfree(tin->geoms);
52
53
7.76k
  lwfree(tin);
54
7.76k
}
55
56
57
void printLWTIN(LWTIN *tin)
58
0
{
59
0
  uint32_t i;
60
0
  LWTRIANGLE *triangle;
61
62
0
  if (tin->type != TINTYPE)
63
0
    lwerror("printLWTIN called with something else than a TIN");
64
65
0
  lwnotice("LWTIN {");
66
0
  lwnotice("    ndims = %i", (int)FLAGS_NDIMS(tin->flags));
67
0
  lwnotice("    SRID = %i", (int)tin->srid);
68
0
  lwnotice("    ngeoms = %i", (int)tin->ngeoms);
69
70
0
  for (i=0; i<tin->ngeoms; i++)
71
0
  {
72
0
    triangle = (LWTRIANGLE *) tin->geoms[i];
73
0
    printPA(triangle->points);
74
0
  }
75
0
  lwnotice("}");
76
0
}
77
78
79
/*
80
 * TODO rewrite all this stuff to be based on a truly topological model
81
 */
82
83
struct struct_tin_arcs
84
{
85
  double ax, ay, az;
86
  double bx, by, bz;
87
  uint32_t cnt, face;
88
};
89
typedef struct struct_tin_arcs *tin_arcs;
90
91
/* We supposed that the geometry is valid
92
   we could have wrong result if not */
93
int lwtin_is_closed(const LWTIN *tin)
94
0
{
95
0
  uint32_t i, j, k;
96
0
  uint32_t narcs, carc;
97
0
  int found;
98
0
  tin_arcs arcs;
99
0
  POINT4D pa, pb;
100
0
  LWTRIANGLE *patch;
101
102
  /* If surface is not 3D, it's can't be closed */
103
0
  if (!FLAGS_GET_Z(tin->flags)) return 0;
104
105
  /* Max theoretical arcs number if no one is shared ... */
106
0
  narcs = 3 * tin->ngeoms;
107
108
0
  arcs = lwalloc(sizeof(struct struct_tin_arcs) * narcs);
109
0
  for (i=0, carc=0; i < tin->ngeoms ; i++)
110
0
  {
111
112
0
    patch = (LWTRIANGLE *) tin->geoms[i];
113
0
    for (j=0; j < 3 ; j++)
114
0
    {
115
116
0
      getPoint4d_p(patch->points, j,   &pa);
117
0
      getPoint4d_p(patch->points, j+1, &pb);
118
119
      /* Make sure to order the 'lower' point first */
120
0
      if ( (pa.x > pb.x) ||
121
0
              (pa.x == pb.x && pa.y > pb.y) ||
122
0
              (pa.x == pb.x && pa.y == pb.y && pa.z > pb.z) )
123
0
      {
124
0
        pa = pb;
125
0
        getPoint4d_p(patch->points, j, &pb);
126
0
      }
127
128
0
      for (found=0, k=0; k < carc ; k++)
129
0
      {
130
131
0
        if (  ( arcs[k].ax == pa.x && arcs[k].ay == pa.y &&
132
0
                arcs[k].az == pa.z && arcs[k].bx == pb.x &&
133
0
                arcs[k].by == pb.y && arcs[k].bz == pb.z &&
134
0
                arcs[k].face != i) )
135
0
        {
136
0
          arcs[k].cnt++;
137
0
          found = 1;
138
139
          /* Look like an invalid TIN
140
                anyway not a closed one */
141
0
          if (arcs[k].cnt > 2)
142
0
          {
143
0
            lwfree(arcs);
144
0
            return 0;
145
0
          }
146
0
        }
147
0
      }
148
149
0
      if (!found)
150
0
      {
151
0
        arcs[carc].cnt=1;
152
0
        arcs[carc].face=i;
153
0
        arcs[carc].ax = pa.x;
154
0
        arcs[carc].ay = pa.y;
155
0
        arcs[carc].az = pa.z;
156
0
        arcs[carc].bx = pb.x;
157
0
        arcs[carc].by = pb.y;
158
0
        arcs[carc].bz = pb.z;
159
0
        carc++;
160
161
        /* Look like an invalid TIN
162
              anyway not a closed one */
163
0
        if (carc > narcs)
164
0
        {
165
0
          lwfree(arcs);
166
0
          return 0;
167
0
        }
168
0
      }
169
0
    }
170
0
  }
171
172
  /* A TIN is closed if each edge
173
         is shared by exactly 2 faces */
174
0
  for (k=0; k < carc ; k++)
175
0
  {
176
0
    if (arcs[k].cnt != 2)
177
0
    {
178
0
      lwfree(arcs);
179
0
      return 0;
180
0
    }
181
0
  }
182
0
  lwfree(arcs);
183
184
  /* Invalid TIN case */
185
0
  if (carc < tin->ngeoms) return 0;
186
187
0
  return 1;
188
0
}