PostGIS  2.5.0beta1dev-r@@SVN_REVISION@@
lwgeom_wrapx.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 2016 Sandro Santilli <strk@kbt.io>
22  *
23  **********************************************************************/
24 
25 #include "../postgis_config.h"
26 /*#define POSTGIS_DEBUG_LEVEL 4*/
27 #include "lwgeom_geos.h"
28 #include "liblwgeom_internal.h"
29 
30 #include <string.h>
31 #include <assert.h>
32 
33 LWGEOM* lwgeom_wrapx(const LWGEOM* lwgeom_in, double cutx, double amount);
34 static LWCOLLECTION* lwcollection_wrapx(const LWCOLLECTION* lwcoll_in, double cutx, double amount);
35 
36 static LWGEOM*
37 lwgeom_split_wrapx(const LWGEOM* geom_in, double cutx, double amount)
38 {
39  LWGEOM *blade, *split;
40  POINTARRAY *bladepa;
41  POINT4D pt;
42  const GBOX *box_in;
43  AFFINE affine = {
44  1, 0, 0,
45  0, 1, 0,
46  0, 0, 1,
47  amount, 0, 0,
48  };
49 
50  /* Extract box */
51  /* TODO: check if the bbox should be force-recomputed */
52  box_in = lwgeom_get_bbox(geom_in);
53  if ( ! box_in ) {
54  /* must be empty */
55  return lwgeom_clone_deep(geom_in);
56  }
57 
58  LWDEBUGF(2, "BOX X range is %g..%g, cutx:%g, amount:%g", box_in->xmin, box_in->xmax, cutx, amount);
59 
60  /* Check if geometry is fully on the side needing shift */
61  if ( ( amount < 0 && box_in->xmin >= cutx ) || ( amount > 0 && box_in->xmax <= cutx ) )
62  {
63  split = lwgeom_clone_deep(geom_in);
64  lwgeom_affine(split, &affine);
65  LWDEBUGG(2, split, "returning the translated geometry");
66  return split;
67  }
68 
69  /* Check if geometry is fully on the side needing no shift */
70  if ( ( amount < 0 && box_in->xmax <= cutx ) || ( amount > 0 && box_in->xmin >= cutx ) )
71  {
72  split = lwgeom_clone_deep(geom_in);
73  LWDEBUGG(2, split, "returning the cloned geometry");
74  return split;
75  }
76 
77  /* We need splitting here */
78 
79  /* construct blade */
80  bladepa = ptarray_construct(0, 0, 2);
81  pt.x = cutx;
82  pt.y = box_in->ymin - 1;
83  ptarray_set_point4d(bladepa, 0, &pt);
84  pt.y = box_in->ymax + 1;
85  ptarray_set_point4d(bladepa, 1, &pt);
86  blade = lwline_as_lwgeom(lwline_construct(geom_in->srid, NULL, bladepa));
87 
88  LWDEBUG(2, "splitting the geometry");
89 
90  /* split by blade */
91  split = lwgeom_split(geom_in, blade);
92  lwgeom_free(blade);
93  if ( ! split ) {
94  lwerror("%s:%d - lwgeom_split_wrapx: %s", __FILE__, __LINE__, lwgeom_geos_errmsg);
95  return NULL;
96  }
97  LWDEBUGG(2, split, "split geometry");
98 
99 
100  /* iterate over components, translate if needed */
101  const LWCOLLECTION *col = lwgeom_as_lwcollection(split);
102  if ( ! col ) {
103  /* not split, this is unexpected */
104  lwnotice("WARNING: unexpected lack of split in lwgeom_split_wrapx");
105  return lwgeom_clone_deep(geom_in);
106  }
107  LWCOLLECTION *col_out = lwcollection_wrapx(col, cutx, amount);
108  lwgeom_free(split);
109 
110  /* unary-union the result (homogenize too ?) */
112  LWDEBUGF(2, "col_out:%p, unaryunion_out:%p", col_out, out);
113  LWDEBUGG(2, out, "unary-unioned");
114 
115  lwcollection_free(col_out);
116 
117  return out;
118 }
119 
120 static LWCOLLECTION*
121 lwcollection_wrapx(const LWCOLLECTION* lwcoll_in, double cutx, double amount)
122 {
123  LWGEOM** wrap_geoms;
124  LWCOLLECTION* out;
125  uint32_t i;
126  int outtype = lwcoll_in->type;
127 
128  wrap_geoms = lwalloc(lwcoll_in->ngeoms * sizeof(LWGEOM*));
129  if ( ! wrap_geoms )
130  {
131  lwerror("Out of virtual memory");
132  return NULL;
133  }
134 
135  for (i=0; i<lwcoll_in->ngeoms; ++i)
136  {
137  LWDEBUGF(3, "Wrapping collection element %d", i);
138  wrap_geoms[i] = lwgeom_wrapx(lwcoll_in->geoms[i], cutx, amount);
139  /* an exception should prevent this from ever returning NULL */
140  if ( ! wrap_geoms[i] ) {
141  uint32_t j;
142  lwnotice("Error wrapping geometry, cleaning up");
143  for (j = 0; j < i; j++)
144  {
145  lwnotice("cleaning geometry %d (%p)", j, wrap_geoms[j]);
146  lwgeom_free(wrap_geoms[j]);
147  }
148  lwfree(wrap_geoms);
149  lwnotice("cleanup complete");
150  return NULL;
151  }
152  if ( outtype != COLLECTIONTYPE ) {
153  if ( MULTITYPE[wrap_geoms[i]->type] != outtype )
154  {
155  outtype = COLLECTIONTYPE;
156  }
157  }
158  }
159 
160  /* Now wrap_geoms has wrap_geoms_size geometries */
161  out = lwcollection_construct(outtype, lwcoll_in->srid, NULL,
162  lwcoll_in->ngeoms, wrap_geoms);
163 
164  return out;
165 }
166 
167 /* exported */
168 LWGEOM*
169 lwgeom_wrapx(const LWGEOM* lwgeom_in, double cutx, double amount)
170 {
171  /* Nothing to wrap in an empty geom */
172  if ( lwgeom_is_empty(lwgeom_in) )
173  {
174  LWDEBUG(2, "geom is empty, cloning");
175  return lwgeom_clone_deep(lwgeom_in);
176  }
177 
178  /* Nothing to wrap if shift amount is zero */
179  if ( amount == 0 )
180  {
181  LWDEBUG(2, "amount is zero, cloning");
182  return lwgeom_clone_deep(lwgeom_in);
183  }
184 
185  switch (lwgeom_in->type)
186  {
187  case LINETYPE:
188  case POLYGONTYPE:
189  LWDEBUG(2, "split-wrapping line or polygon");
190  return lwgeom_split_wrapx(lwgeom_in, cutx, amount);
191 
192  case POINTTYPE:
193  {
194  const LWPOINT *pt = lwgeom_as_lwpoint(lwgeom_clone_deep(lwgeom_in));
195  POINT4D pt4d;
196  getPoint4d_p(pt->point, 0, &pt4d);
197 
198  LWDEBUGF(2, "POINT X is %g, cutx:%g, amount:%g", pt4d.x, cutx, amount);
199 
200  if ( ( amount < 0 && pt4d.x > cutx ) || ( amount > 0 && pt4d.x < cutx ) )
201  {
202  pt4d.x += amount;
203  ptarray_set_point4d(pt->point, 0, &pt4d);
204  }
205  return lwpoint_as_lwgeom(pt);
206  }
207 
208  case MULTIPOINTTYPE:
209  case MULTIPOLYGONTYPE:
210  case MULTILINETYPE:
211  case COLLECTIONTYPE:
212  LWDEBUG(2, "collection-wrapping multi");
213  return lwcollection_as_lwgeom(
214  lwcollection_wrapx((const LWCOLLECTION*)lwgeom_in, cutx, amount)
215  );
216 
217  default:
218  lwerror("Wrapping of %s geometries is unsupported",
219  lwtype_name(lwgeom_in->type));
220  return NULL;
221  }
222 
223 }
double x
Definition: liblwgeom.h:354
#define LINETYPE
Definition: liblwgeom.h:85
POINTARRAY * ptarray_construct(char hasz, char hasm, uint32_t npoints)
Construct an empty pointarray, allocating storage and setting the npoints, but not filling in any inf...
Definition: ptarray.c:62
LWCOLLECTION * lwcollection_construct(uint8_t type, int srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
Definition: lwcollection.c:43
void lwnotice(const char *fmt,...)
Write a notice out to the notice handler.
Definition: lwutil.c:177
void lwfree(void *mem)
Definition: lwutil.c:244
uint8_t type
Definition: liblwgeom.h:505
#define POLYGONTYPE
Definition: liblwgeom.h:86
double xmax
Definition: liblwgeom.h:295
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1144
#define MULTIPOINTTYPE
Definition: liblwgeom.h:87
char lwgeom_geos_errmsg[LWGEOM_GEOS_ERRMSG_MAXSIZE]
void ptarray_set_point4d(POINTARRAY *pa, uint32_t n, const POINT4D *p4d)
Definition: lwgeom_api.c:425
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:83
LWGEOM * lwgeom_clone_deep(const LWGEOM *lwgeom)
Deep clone an LWGEOM, everything is copied.
Definition: lwgeom.c:520
LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
Definition: lwgeom.c:161
uint32_t ngeoms
Definition: liblwgeom.h:509
POINTARRAY * point
Definition: liblwgeom.h:413
int32_t srid
Definition: liblwgeom.h:401
unsigned int uint32_t
Definition: uthash.h:78
static LWCOLLECTION * lwcollection_wrapx(const LWCOLLECTION *lwcoll_in, double cutx, double amount)
Definition: lwgeom_wrapx.c:121
double ymin
Definition: liblwgeom.h:296
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:218
static LWGEOM * lwgeom_split_wrapx(const LWGEOM *geom_in, double cutx, double amount)
Definition: lwgeom_wrapx.c:37
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:330
double xmin
Definition: liblwgeom.h:294
LWLINE * lwline_construct(int srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:42
LWGEOM ** geoms
Definition: liblwgeom.h:511
const GBOX * lwgeom_get_bbox(const LWGEOM *lwgeom)
Get a non-empty geometry bounding box, computing and caching it if not already there.
Definition: lwgeom.c:734
LWGEOM * lwgeom_wrapx(const LWGEOM *lwgeom_in, double cutx, double amount)
wrap geometry on given cut x value
Definition: lwgeom_wrapx.c:169
int32_t srid
Definition: liblwgeom.h:508
double ymax
Definition: liblwgeom.h:297
#define LWDEBUGG(level, geom, msg)
Definition: lwgeom_log.h:93
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
Definition: lwgeom_api.c:113
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:89
uint8_t MULTITYPE[NUMTYPES]
Look-up for the correct MULTI* type promotion for singleton types.
Definition: lwgeom.c:345
LWGEOM * lwgeom_unaryunion(const LWGEOM *geom1)
LWCOLLECTION * lwgeom_as_lwcollection(const LWGEOM *lwgeom)
Definition: lwgeom.c:224
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:84
uint8_t type
Definition: liblwgeom.h:398
type
Definition: ovdump.py:41
void lwcollection_free(LWCOLLECTION *col)
Definition: lwcollection.c:356
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:335
void * lwalloc(size_t size)
Definition: lwutil.c:229
int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members) ...
Definition: lwgeom.c:1393
double y
Definition: liblwgeom.h:354
#define MULTILINETYPE
Definition: liblwgeom.h:88
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
#define COLLECTIONTYPE
Definition: liblwgeom.h:90
void lwgeom_affine(LWGEOM *geom, const AFFINE *affine)
Definition: lwgeom.c:1969
LWGEOM * lwgeom_split(const LWGEOM *lwgeom_in, const LWGEOM *blade_in)
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
Definition: lwgeom.c:300