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^
22 *
23 **********************************************************************/
24
25 #include "postgres.h"
26 #include "utils/geo_decls.h"
27
28 #include "../postgis_config.h"
29
30 #include "liblwgeom.h" /* For standard geometry types. */
31 #include "lwgeom_pg.h" /* For debugging macros. */
32
33
34 Datum geometry_to_point(PG_FUNCTION_ARGS);
35 Datum point_to_geometry(PG_FUNCTION_ARGS);
36 Datum geometry_to_path(PG_FUNCTION_ARGS);
37 Datum path_to_geometry(PG_FUNCTION_ARGS);
38 Datum geometry_to_polygon(PG_FUNCTION_ARGS);
39 Datum polygon_to_geometry(PG_FUNCTION_ARGS);
40
41 /**
42 * Cast a PostgreSQL Point to a PostGIS geometry
43 */
44 PG_FUNCTION_INFO_V1(point_to_geometry);
point_to_geometry(PG_FUNCTION_ARGS)45 Datum point_to_geometry(PG_FUNCTION_ARGS)
46 {
47 Point *point;
48 LWPOINT *lwpoint;
49 GSERIALIZED *geom;
50
51 POSTGIS_DEBUG(2, "point_to_geometry called");
52
53 if ( PG_ARGISNULL(0) )
54 PG_RETURN_NULL();
55
56 point = PG_GETARG_POINT_P(0);
57
58 if ( ! point )
59 PG_RETURN_NULL();
60
61 lwpoint = lwpoint_make2d(SRID_UNKNOWN, point->x, point->y);
62 geom = geometry_serialize(lwpoint_as_lwgeom(lwpoint));
63 lwpoint_free(lwpoint);
64
65 PG_RETURN_POINTER(geom);
66 }
67
68 /**
69 * Cast a PostGIS geometry to a PostgreSQL Point
70 */
71 PG_FUNCTION_INFO_V1(geometry_to_point);
geometry_to_point(PG_FUNCTION_ARGS)72 Datum geometry_to_point(PG_FUNCTION_ARGS)
73 {
74 Point *point;
75 LWGEOM *lwgeom;
76 LWPOINT *lwpoint;
77 GSERIALIZED *geom;
78
79 POSTGIS_DEBUG(2, "geometry_to_point called");
80
81 if ( PG_ARGISNULL(0) )
82 PG_RETURN_NULL();
83
84 geom = PG_GETARG_GSERIALIZED_P(0);
85
86 if ( gserialized_get_type(geom) != POINTTYPE )
87 elog(ERROR, "geometry_to_point only accepts Points");
88
89 lwgeom = lwgeom_from_gserialized(geom);
90
91 if ( lwgeom_is_empty(lwgeom) )
92 PG_RETURN_NULL();
93
94 lwpoint = lwgeom_as_lwpoint(lwgeom);
95
96 point = (Point*)palloc(sizeof(Point));
97 point->x = lwpoint_get_x(lwpoint);
98 point->y = lwpoint_get_y(lwpoint);
99
100 lwpoint_free(lwpoint);
101 PG_FREE_IF_COPY(geom,0);
102
103 PG_RETURN_POINT_P(point);
104 }
105
106 PG_FUNCTION_INFO_V1(geometry_to_path);
geometry_to_path(PG_FUNCTION_ARGS)107 Datum geometry_to_path(PG_FUNCTION_ARGS)
108 {
109 PATH *path;
110 LWLINE *lwline;
111 LWGEOM *lwgeom;
112 GSERIALIZED *geom;
113 POINTARRAY *pa;
114 uint32_t i;
115 const POINT2D *pt;
116 size_t size;
117
118 POSTGIS_DEBUG(2, "geometry_to_path called");
119
120 if ( PG_ARGISNULL(0) )
121 PG_RETURN_NULL();
122
123 geom = PG_GETARG_GSERIALIZED_P(0);
124
125 if ( gserialized_get_type(geom) != LINETYPE )
126 elog(ERROR, "geometry_to_path only accepts LineStrings");
127
128 lwgeom = lwgeom_from_gserialized(geom);
129 if ( lwgeom_is_empty(lwgeom) )
130 PG_RETURN_NULL();
131 lwline = lwgeom_as_lwline(lwgeom);
132
133 pa = lwline->points;
134 size = offsetof(PATH, p[0]) + sizeof(path->p[0]) * pa->npoints;
135 path = (PATH*)palloc(size);
136 SET_VARSIZE(path, size);
137 path->npts = pa->npoints;
138 path->closed = 0;
139 path->dummy = 0;
140
141 for ( i = 0; i < pa->npoints; i++ )
142 {
143 pt = getPoint2d_cp(pa, i);
144 (path->p[i]).x = pt->x;
145 (path->p[i]).y = pt->y;
146 }
147
148 lwgeom_free(lwgeom);
149 PG_FREE_IF_COPY(geom,0);
150
151 PG_RETURN_PATH_P(path);
152 }
153
154
155 PG_FUNCTION_INFO_V1(path_to_geometry);
path_to_geometry(PG_FUNCTION_ARGS)156 Datum path_to_geometry(PG_FUNCTION_ARGS)
157 {
158 PATH *path;
159 LWLINE *lwline;
160 POINTARRAY *pa;
161 GSERIALIZED *geom;
162 POINT4D pt;
163 Point p;
164 int i;
165
166 POSTGIS_DEBUG(2, "path_to_geometry called");
167
168 if ( PG_ARGISNULL(0) )
169 PG_RETURN_NULL();
170
171 path = PG_GETARG_PATH_P(0);
172
173 if ( ! path )
174 PG_RETURN_NULL();
175
176 pa = ptarray_construct_empty(0, 0, path->npts);
177 for ( i = 0; i < path->npts; i++ )
178 {
179 p = path->p[i];
180 pt.x = p.x;
181 pt.y = p.y;
182 ptarray_append_point(pa, &pt, LW_FALSE);
183 }
184 lwline = lwline_construct(SRID_UNKNOWN, NULL, pa);
185 geom = geometry_serialize(lwline_as_lwgeom(lwline));
186 lwline_free(lwline);
187
188 PG_RETURN_POINTER(geom);
189 }
190
191 PG_FUNCTION_INFO_V1(geometry_to_polygon);
geometry_to_polygon(PG_FUNCTION_ARGS)192 Datum geometry_to_polygon(PG_FUNCTION_ARGS)
193 {
194 POLYGON *polygon;
195 LWPOLY *lwpoly;
196 LWGEOM *lwgeom;
197 GSERIALIZED *geom;
198 POINTARRAY *pa;
199 GBOX gbox;
200 uint32_t i;
201 size_t size;
202
203 POSTGIS_DEBUG(2, "geometry_to_polygon called");
204
205 if ( PG_ARGISNULL(0) )
206 PG_RETURN_NULL();
207
208 geom = PG_GETARG_GSERIALIZED_P(0);
209
210 if ( gserialized_get_type(geom) != POLYGONTYPE )
211 elog(ERROR, "geometry_to_polygon only accepts Polygons");
212
213 lwgeom = lwgeom_from_gserialized(geom);
214 if ( lwgeom_is_empty(lwgeom) )
215 PG_RETURN_NULL();
216 lwpoly = lwgeom_as_lwpoly(lwgeom);
217
218 pa = lwpoly->rings[0];
219
220 size = offsetof(POLYGON, p[0]) + sizeof(polygon->p[0]) * pa->npoints;
221 polygon = (POLYGON*)palloc0(size); /* zero any holes */
222 SET_VARSIZE(polygon, size);
223
224 polygon->npts = pa->npoints;
225
226 lwgeom_calculate_gbox(lwgeom, &gbox);
227 polygon->boundbox.low.x = gbox.xmin;
228 polygon->boundbox.low.y = gbox.ymin;
229 polygon->boundbox.high.x = gbox.xmax;
230 polygon->boundbox.high.y = gbox.ymax;
231
232 for ( i = 0; i < pa->npoints; i++ )
233 {
234 const POINT2D *pt = getPoint2d_cp(pa, i);
235 (polygon->p[i]).x = pt->x;
236 (polygon->p[i]).y = pt->y;
237 }
238
239 lwgeom_free(lwgeom);
240 PG_FREE_IF_COPY(geom,0);
241
242 PG_RETURN_POLYGON_P(polygon);
243 }
244
245
246 PG_FUNCTION_INFO_V1(polygon_to_geometry);
polygon_to_geometry(PG_FUNCTION_ARGS)247 Datum polygon_to_geometry(PG_FUNCTION_ARGS)
248 {
249 POLYGON *polygon;
250 LWPOLY *lwpoly;
251 POINTARRAY *pa;
252 POINTARRAY **ppa;
253 GSERIALIZED *geom;
254 Point p;
255 int i = 0, unclosed = 0;
256
257 POSTGIS_DEBUG(2, "polygon_to_geometry called");
258
259 if ( PG_ARGISNULL(0) )
260 PG_RETURN_NULL();
261
262 polygon = PG_GETARG_POLYGON_P(0);
263
264 if ( ! polygon )
265 PG_RETURN_NULL();
266
267 /* Are first and last points different? If so we need to close this ring */
268 if ( memcmp( polygon->p, polygon->p + polygon->npts - 1, sizeof(Point) ) )
269 {
270 unclosed = 1;
271 }
272
273 pa = ptarray_construct_empty(0, 0, polygon->npts + unclosed);
274
275 for ( i = 0; i < (polygon->npts+unclosed); i++ )
276 {
277 POINT4D pt;
278 p = polygon->p[i % polygon->npts];
279 pt.x = p.x;
280 pt.y = p.y;
281 ptarray_append_point(pa, &pt, LW_FALSE);
282 }
283
284 ppa = palloc(sizeof(POINTARRAY*));
285 ppa[0] = pa;
286 lwpoly = lwpoly_construct(SRID_UNKNOWN, NULL, 1, ppa);
287 geom = geometry_serialize(lwpoly_as_lwgeom(lwpoly));
288 lwpoly_free(lwpoly);
289
290 PG_RETURN_POINTER(geom);
291 }
292
293