Coverage Report

Created: 2026-06-09 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgis/liblwgeom/lwcircstring.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
/* basic LWCIRCSTRING functions */
27
28
#include <stdio.h>
29
#include <stdlib.h>
30
#include <string.h>
31
#include "liblwgeom_internal.h"
32
#include "lwgeom_log.h"
33
34
void printLWCIRCSTRING(LWCIRCSTRING *curve);
35
void lwcircstring_release(LWCIRCSTRING *lwcirc);
36
char lwcircstring_same(const LWCIRCSTRING *me, const LWCIRCSTRING *you);
37
LWCIRCSTRING *lwcircstring_from_lwpointarray(int32_t srid, uint32_t npoints, const LWPOINT **points);
38
LWCIRCSTRING *lwcircstring_from_lwmpoint(int32_t srid, LWMPOINT *mpoint);
39
LWCIRCSTRING *lwcircstring_addpoint(LWCIRCSTRING *curve, LWPOINT *point, uint32_t where);
40
LWCIRCSTRING *lwcircstring_removepoint(LWCIRCSTRING *curve, uint32_t index);
41
void lwcircstring_setPoint4d(LWCIRCSTRING *curve, uint32_t index, POINT4D *newpoint);
42
43
44
/*
45
 * Construct a new LWCIRCSTRING.  points will *NOT* be copied
46
 * use SRID=SRID_UNKNOWN for unknown SRID (will have 8bit type's S = 0)
47
 */
48
LWCIRCSTRING *
49
lwcircstring_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
50
658
{
51
658
  LWCIRCSTRING *result;
52
53
  /*
54
  * The first arc requires three points.  Each additional
55
  * arc requires two more points.  Thus the minimum point count
56
  * is three, and the count must be odd.
57
  */
58
658
  if (points->npoints % 2 != 1 || points->npoints < 3)
59
431
  {
60
431
    lwnotice("lwcircstring_construct: invalid point count %d", points->npoints);
61
431
  }
62
63
658
  result = (LWCIRCSTRING*) lwalloc(sizeof(LWCIRCSTRING));
64
65
658
  result->type = CIRCSTRINGTYPE;
66
67
658
  result->flags = points->flags;
68
658
  FLAGS_SET_BBOX(result->flags, bbox?1:0);
69
70
658
  result->srid = srid;
71
658
  result->points = points;
72
658
  result->bbox = bbox;
73
74
658
  return result;
75
658
}
76
77
LWCIRCSTRING *
78
lwcircstring_construct_empty(int32_t srid, char hasz, char hasm)
79
10.2k
{
80
10.2k
  LWCIRCSTRING *result = lwalloc(sizeof(LWCIRCSTRING));
81
10.2k
  result->type = CIRCSTRINGTYPE;
82
10.2k
  result->flags = lwflags(hasz,hasm,0);
83
10.2k
  result->srid = srid;
84
10.2k
  result->points = ptarray_construct_empty(hasz, hasm, 1);
85
10.2k
  result->bbox = NULL;
86
10.2k
  return result;
87
10.2k
}
88
89
void
90
lwcircstring_release(LWCIRCSTRING *lwcirc)
91
0
{
92
0
  lwgeom_release(lwcircstring_as_lwgeom(lwcirc));
93
0
}
94
95
96
void lwcircstring_free(LWCIRCSTRING *curve)
97
10.8k
{
98
10.8k
  if ( ! curve ) return;
99
100
10.8k
  if ( curve->bbox )
101
0
    lwfree(curve->bbox);
102
10.8k
  if ( curve->points )
103
10.8k
    ptarray_free(curve->points);
104
10.8k
  lwfree(curve);
105
10.8k
}
106
107
108
109
void printLWCIRCSTRING(LWCIRCSTRING *curve)
110
0
{
111
0
  lwnotice("LWCIRCSTRING {");
112
0
  lwnotice("    ndims = %i", (int)FLAGS_NDIMS(curve->flags));
113
0
  lwnotice("    srid = %i", (int)curve->srid);
114
0
  printPA(curve->points);
115
0
  lwnotice("}");
116
0
}
117
118
/* @brief Clone LWCIRCSTRING object. Serialized point lists are not copied.
119
 *
120
 * @see ptarray_clone
121
 */
122
LWCIRCSTRING *
123
lwcircstring_clone(const LWCIRCSTRING *g)
124
0
{
125
0
  return (LWCIRCSTRING *)lwline_clone((LWLINE *)g);
126
0
}
127
128
/* check coordinate equality */
129
char
130
lwcircstring_same(const LWCIRCSTRING *me, const LWCIRCSTRING *you)
131
0
{
132
0
  return ptarray_same(me->points, you->points);
133
0
}
134
135
/*
136
 * Construct a LWCIRCSTRING from an array of LWPOINTs
137
 * LWCIRCSTRING dimensions are large enough to host all input dimensions.
138
 */
139
LWCIRCSTRING *
140
lwcircstring_from_lwpointarray(int32_t srid, uint32_t npoints, const LWPOINT **points)
141
0
{
142
0
  uint32_t i;
143
0
  POINTARRAY *pa;
144
0
  int has_z = 0, has_m = 0;
145
0
  POINT4D pt;
146
147
  /*
148
   * Find output dimensions, check integrity
149
   */
150
0
  for (i = 0; i < npoints; i++)
151
0
  {
152
0
    const LWGEOM *lwg = (LWGEOM*)points[i];
153
0
    if (lwg->type != POINTTYPE)
154
0
    {
155
0
      lwerror("%s: invalid input type: %s", __func__, lwtype_name(lwg->type));
156
0
      return NULL;
157
0
    }
158
0
    has_z |= lwgeom_has_z(lwg);
159
0
    has_m |= lwgeom_has_m(lwg);
160
0
    if (has_z && has_m) break;
161
0
  }
162
163
  /*
164
   * Allocate output points array
165
   */
166
0
  pa = ptarray_construct(has_z, has_m, npoints);
167
168
0
  for (i = 0; i < npoints; i++)
169
0
  {
170
0
    const LWPOINT *lwpt = points[i];
171
0
    if (!getPoint4d_p(lwpt->point, 0, &pt))
172
0
    {
173
0
      lwerror("%s: failed getPoint4d_p", __func__);
174
0
      return NULL;
175
0
    }
176
0
    ptarray_set_point4d(pa, i, &pt);
177
0
  }
178
179
0
  return lwcircstring_construct(srid, NULL, pa);
180
0
}
181
182
/*
183
 * Construct a LWCIRCSTRING from a LWMPOINT
184
 */
185
LWCIRCSTRING *
186
lwcircstring_from_lwmpoint(int32_t srid, LWMPOINT *mpoint)
187
0
{
188
0
  uint32_t i;
189
0
  POINTARRAY *pa;
190
0
  char zmflag = FLAGS_GET_ZM(mpoint->flags);
191
0
  size_t ptsize, size;
192
0
  uint8_t *newpoints, *ptr;
193
194
0
  if (zmflag == 0) ptsize = 2 * sizeof(double);
195
0
  else if (zmflag == 3) ptsize = 4 * sizeof(double);
196
0
  else ptsize = 3 * sizeof(double);
197
198
  /* Allocate space for output points */
199
0
  size = ptsize * mpoint->ngeoms;
200
0
  newpoints = lwalloc(size);
201
0
  memset(newpoints, 0, size);
202
203
0
  ptr = newpoints;
204
0
  for (i = 0; i < mpoint->ngeoms; i++)
205
0
  {
206
0
    memcpy(ptr,
207
0
           getPoint_internal(mpoint->geoms[i]->point, 0),
208
0
           ptsize);
209
0
    ptr += ptsize;
210
0
  }
211
212
0
  pa = ptarray_construct_reference_data(zmflag&2, zmflag&1, mpoint->ngeoms, newpoints);
213
214
0
  LWDEBUGF(3, "lwcurve_from_lwmpoint: constructed pointarray for %d points, %d zmflag", mpoint->ngeoms, zmflag);
215
216
0
  return lwcircstring_construct(srid, NULL, pa);
217
0
}
218
219
LWCIRCSTRING *
220
lwcircstring_addpoint(LWCIRCSTRING *curve, LWPOINT *point, uint32_t where)
221
0
{
222
0
  POINTARRAY *newpa;
223
0
  LWCIRCSTRING *ret;
224
225
0
  newpa = ptarray_addPoint(curve->points,
226
0
                           getPoint_internal(point->point, 0),
227
0
                           FLAGS_NDIMS(point->flags), where);
228
0
  ret = lwcircstring_construct(curve->srid, NULL, newpa);
229
230
0
  return ret;
231
0
}
232
233
LWCIRCSTRING *
234
lwcircstring_removepoint(LWCIRCSTRING *curve, uint32_t index)
235
0
{
236
0
  POINTARRAY *newpa;
237
0
  LWCIRCSTRING *ret;
238
239
0
  newpa = ptarray_removePoint(curve->points, index);
240
0
  ret = lwcircstring_construct(curve->srid, NULL, newpa);
241
242
0
  return ret;
243
0
}
244
245
/*
246
 * Note: input will be changed, make sure you have permissions for this.
247
 * */
248
void
249
lwcircstring_setPoint4d(LWCIRCSTRING *curve, uint32_t index, POINT4D *newpoint)
250
0
{
251
0
  ptarray_set_point4d(curve->points, index, newpoint);
252
0
}
253
254
int
255
lwcircstring_is_closed(const LWCIRCSTRING *curve)
256
0
{
257
0
  if (lwgeom_has_z((LWGEOM*)curve))
258
0
    return ptarray_is_closed_3d(curve->points);
259
260
0
  return ptarray_is_closed_2d(curve->points);
261
0
}
262
263
double lwcircstring_length(const LWCIRCSTRING *circ)
264
0
{
265
0
  return lwcircstring_length_2d(circ);
266
0
}
267
268
double lwcircstring_length_2d(const LWCIRCSTRING *circ)
269
0
{
270
0
  if ( lwcircstring_is_empty(circ) )
271
0
    return 0.0;
272
273
0
  return ptarray_arc_length_2d(circ->points);
274
0
}
275
276
/*
277
 * Returns freshly allocated #LWPOINT that corresponds to the index where.
278
 * Returns NULL if the geometry is empty or the index invalid.
279
 */
280
0
LWPOINT* lwcircstring_get_lwpoint(const LWCIRCSTRING *circ, uint32_t where) {
281
0
  POINT4D pt;
282
0
  LWPOINT *lwpoint;
283
0
  POINTARRAY *pa;
284
285
0
  if ( lwcircstring_is_empty(circ) || where >= circ->points->npoints )
286
0
    return NULL;
287
288
0
  pa = ptarray_construct_empty(FLAGS_GET_Z(circ->flags), FLAGS_GET_M(circ->flags), 1);
289
0
  pt = getPoint4d(circ->points, where);
290
0
  ptarray_append_point(pa, &pt, LW_TRUE);
291
  lwpoint = lwpoint_construct(circ->srid, NULL, pa);
292
0
  return lwpoint;
293
0
}
294
295