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