2004-04-26 23:05:20 +00:00
|
|
|
#include <math.h>
|
|
|
|
#include <float.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
2004-09-29 10:50:30 +00:00
|
|
|
#include "postgres.h"
|
2004-04-26 23:05:20 +00:00
|
|
|
#include "fmgr.h"
|
|
|
|
#include "utils/elog.h"
|
2004-08-27 16:01:48 +00:00
|
|
|
#include "utils/array.h"
|
2004-09-29 10:50:30 +00:00
|
|
|
#include "utils/geo_decls.h"
|
2004-04-26 23:05:20 +00:00
|
|
|
|
2004-09-29 10:50:30 +00:00
|
|
|
#include "liblwgeom.h"
|
|
|
|
#include "lwgeom_pg.h"
|
2004-09-22 11:42:45 +00:00
|
|
|
#include "profile.h"
|
2004-04-26 23:05:20 +00:00
|
|
|
|
2004-08-27 14:35:26 +00:00
|
|
|
//#define DEBUG
|
2004-04-26 23:05:20 +00:00
|
|
|
|
2004-08-24 10:01:16 +00:00
|
|
|
Datum LWGEOM_mem_size(PG_FUNCTION_ARGS);
|
|
|
|
Datum LWGEOM_summary(PG_FUNCTION_ARGS);
|
|
|
|
Datum LWGEOM_npoints(PG_FUNCTION_ARGS);
|
2004-08-26 16:44:01 +00:00
|
|
|
Datum LWGEOM_nrings(PG_FUNCTION_ARGS);
|
2004-08-25 12:32:12 +00:00
|
|
|
Datum LWGEOM_area_polygon(PG_FUNCTION_ARGS);
|
2004-08-23 15:37:16 +00:00
|
|
|
Datum postgis_uses_stats(PG_FUNCTION_ARGS);
|
|
|
|
Datum postgis_scripts_released(PG_FUNCTION_ARGS);
|
|
|
|
Datum postgis_lib_version(PG_FUNCTION_ARGS);
|
2004-08-25 12:32:12 +00:00
|
|
|
Datum LWGEOM_length2d_linestring(PG_FUNCTION_ARGS);
|
|
|
|
Datum LWGEOM_length_linestring(PG_FUNCTION_ARGS);
|
|
|
|
Datum LWGEOM_perimeter2d_poly(PG_FUNCTION_ARGS);
|
|
|
|
Datum LWGEOM_perimeter_poly(PG_FUNCTION_ARGS);
|
|
|
|
Datum LWGEOM_force_2d(PG_FUNCTION_ARGS);
|
2004-10-05 16:28:34 +00:00
|
|
|
Datum LWGEOM_force_3dm(PG_FUNCTION_ARGS);
|
|
|
|
Datum LWGEOM_force_3dz(PG_FUNCTION_ARGS);
|
2004-09-20 17:03:41 +00:00
|
|
|
Datum LWGEOM_force_4d(PG_FUNCTION_ARGS);
|
2004-08-25 15:28:46 +00:00
|
|
|
Datum LWGEOM_force_collection(PG_FUNCTION_ARGS);
|
2004-08-26 16:44:01 +00:00
|
|
|
Datum LWGEOM_force_multi(PG_FUNCTION_ARGS);
|
2004-08-26 12:55:30 +00:00
|
|
|
Datum LWGEOM_mindistance2d(PG_FUNCTION_ARGS);
|
2004-08-26 15:02:59 +00:00
|
|
|
Datum LWGEOM_maxdistance2d_linestring(PG_FUNCTION_ARGS);
|
2004-08-27 08:13:16 +00:00
|
|
|
Datum LWGEOM_translate(PG_FUNCTION_ARGS);
|
|
|
|
Datum LWGEOM_inside_circle_point(PG_FUNCTION_ARGS);
|
2004-08-27 14:35:26 +00:00
|
|
|
Datum LWGEOM_collect(PG_FUNCTION_ARGS);
|
2004-08-27 16:01:48 +00:00
|
|
|
Datum LWGEOM_accum(PG_FUNCTION_ARGS);
|
|
|
|
Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS);
|
2004-09-06 09:13:13 +00:00
|
|
|
Datum LWGEOM_expand(PG_FUNCTION_ARGS);
|
2004-09-06 10:37:09 +00:00
|
|
|
Datum LWGEOM_to_BOX(PG_FUNCTION_ARGS);
|
|
|
|
Datum LWGEOM_envelope(PG_FUNCTION_ARGS);
|
2004-09-06 12:24:17 +00:00
|
|
|
Datum LWGEOM_isempty(PG_FUNCTION_ARGS);
|
2004-09-08 14:19:25 +00:00
|
|
|
Datum LWGEOM_segmentize2d(PG_FUNCTION_ARGS);
|
2004-09-28 08:22:20 +00:00
|
|
|
Datum LWGEOM_reverse(PG_FUNCTION_ARGS);
|
2004-09-28 09:01:17 +00:00
|
|
|
Datum LWGEOM_forceRHR_poly(PG_FUNCTION_ARGS);
|
2004-10-04 09:25:23 +00:00
|
|
|
Datum LWGEOM_noop(PG_FUNCTION_ARGS);
|
2004-10-06 08:53:24 +00:00
|
|
|
Datum LWGEOM_zmflag(PG_FUNCTION_ARGS);
|
2004-08-24 10:01:16 +00:00
|
|
|
|
2004-08-26 12:55:30 +00:00
|
|
|
|
2004-08-25 12:32:12 +00:00
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
|
2004-08-26 12:55:30 +00:00
|
|
|
// pt_in_ring_2d(): crossing number test for a point in a polygon
|
|
|
|
// input: p = a point,
|
|
|
|
// pa = vertex points of a ring V[n+1] with V[n]=V[0]
|
|
|
|
// returns: 0 = outside, 1 = inside
|
|
|
|
//
|
|
|
|
// Our polygons have first and last point the same,
|
|
|
|
//
|
|
|
|
int pt_in_ring_2d(POINT2D *p, POINTARRAY *ring)
|
|
|
|
{
|
|
|
|
int cn = 0; // the crossing number counter
|
|
|
|
int i;
|
|
|
|
POINT2D *v1;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, "pt_in_ring_2d called");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// loop through all edges of the polygon
|
|
|
|
v1 = (POINT2D *)getPoint(ring, 0);
|
|
|
|
for (i=0; i<ring->npoints-2; i++)
|
|
|
|
{
|
|
|
|
double vt;
|
|
|
|
POINT2D *v2 = (POINT2D *)getPoint(ring, i+1);
|
|
|
|
|
|
|
|
// edge from vertex i to vertex i+1
|
|
|
|
if
|
|
|
|
(
|
|
|
|
// an upward crossing
|
|
|
|
((v1->y <= p->y) && (v2->y > p->y))
|
|
|
|
// a downward crossing
|
|
|
|
|| ((v1->y > p->y) && (v2->y <= p->y))
|
|
|
|
)
|
|
|
|
{
|
|
|
|
|
|
|
|
vt = (double)(p->y - v1->y) / (v2->y - v1->y);
|
|
|
|
|
|
|
|
// P.x <intersect
|
|
|
|
if (p->x < v1->x + vt * (v2->x - v1->x))
|
|
|
|
{
|
|
|
|
// a valid crossing of y=p.y right of p.x
|
|
|
|
++cn;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
v1 = v2;
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, "pt_in_ring_2d returning %d", cn&1);
|
|
|
|
#endif
|
|
|
|
return (cn&1); // 0 if even (out), and 1 if odd (in)
|
|
|
|
}
|
|
|
|
|
|
|
|
// true if point is in poly (and not in its holes)
|
|
|
|
int pt_in_poly_2d(POINT2D *p, LWPOLY *poly)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// Not in outer ring
|
|
|
|
if ( ! pt_in_ring_2d(p, poly->rings[0]) ) return 0;
|
|
|
|
|
|
|
|
// Check holes
|
|
|
|
for (i=1; i<poly->nrings; i++)
|
|
|
|
{
|
|
|
|
// Inside a hole
|
|
|
|
if ( pt_in_ring_2d(p, poly->rings[i]) ) return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1; // In outer ring, not in holes
|
|
|
|
}
|
|
|
|
|
|
|
|
double distance2d_pt_pt(POINT2D *p1, POINT2D *p2)
|
|
|
|
{
|
|
|
|
return sqrt(
|
|
|
|
(p2->x-p1->x) * (p2->x-p1->x) + (p2->y-p1->y) * (p2->y-p1->y)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
//distance2d from p to line A->B
|
|
|
|
double distance2d_pt_seg(POINT2D *p, POINT2D *A, POINT2D *B)
|
|
|
|
{
|
|
|
|
double r,s;
|
|
|
|
|
|
|
|
//if start==end, then use pt distance
|
|
|
|
if ( ( A->x == B->x) && (A->y == B->y) )
|
|
|
|
return distance2d_pt_pt(p,A);
|
|
|
|
|
|
|
|
//otherwise, we use comp.graphics.algorithms Frequently Asked Questions method
|
|
|
|
|
|
|
|
/*(1) AC dot AB
|
|
|
|
r = ---------
|
|
|
|
||AB||^2
|
|
|
|
r has the following meaning:
|
|
|
|
r=0 P = A
|
|
|
|
r=1 P = B
|
|
|
|
r<0 P is on the backward extension of AB
|
|
|
|
r>1 P is on the forward extension of AB
|
|
|
|
0<r<1 P is interior to AB
|
|
|
|
*/
|
|
|
|
|
|
|
|
r = ( (p->x-A->x) * (B->x-A->x) + (p->y-A->y) * (B->y-A->y) )/( (B->x-A->x)*(B->x-A->x) +(B->y-A->y)*(B->y-A->y) );
|
|
|
|
|
|
|
|
if (r<0) return distance2d_pt_pt(p,A);
|
|
|
|
if (r>1) return distance2d_pt_pt(p,B);
|
|
|
|
|
|
|
|
|
|
|
|
/*(2)
|
|
|
|
(Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)
|
|
|
|
s = -----------------------------
|
|
|
|
L^2
|
|
|
|
|
|
|
|
Then the distance from C to P = |s|*L.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
s = ( (A->y-p->y)*(B->x-A->x)- (A->x-p->x)*(B->y-A->y) ) /
|
|
|
|
( (B->x-A->x)*(B->x-A->x) +(B->y-A->y)*(B->y-A->y) );
|
|
|
|
|
|
|
|
return abs(s) * sqrt(
|
|
|
|
(B->x-A->x)*(B->x-A->x) + (B->y-A->y)*(B->y-A->y)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// find the minimum 2d distance from AB to CD
|
|
|
|
double distance2d_seg_seg(POINT2D *A, POINT2D *B, POINT2D *C, POINT2D *D)
|
|
|
|
{
|
|
|
|
|
|
|
|
double s_top, s_bot,s;
|
|
|
|
double r_top, r_bot,r;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, "distance2d_seg_seg [%g,%g]->[%g,%g] by [%g,%g]->[%g,%g]",
|
|
|
|
A->x,A->y,B->x,B->y, C->x,C->y, D->x, D->y);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
//A and B are the same point
|
|
|
|
if ( ( A->x == B->x) && (A->y == B->y) )
|
|
|
|
return distance2d_pt_seg(A,C,D);
|
|
|
|
|
|
|
|
//U and V are the same point
|
|
|
|
|
|
|
|
if ( ( C->x == D->x) && (C->y == D->y) )
|
|
|
|
return distance2d_pt_seg(D,A,B);
|
|
|
|
|
|
|
|
// AB and CD are line segments
|
|
|
|
/* from comp.graphics.algo
|
|
|
|
|
|
|
|
Solving the above for r and s yields
|
|
|
|
(Ay-Cy)(Dx-Cx)-(Ax-Cx)(Dy-Cy)
|
|
|
|
r = ----------------------------- (eqn 1)
|
|
|
|
(Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx)
|
|
|
|
|
|
|
|
(Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)
|
|
|
|
s = ----------------------------- (eqn 2)
|
|
|
|
(Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx)
|
|
|
|
Let P be the position vector of the intersection point, then
|
|
|
|
P=A+r(B-A) or
|
|
|
|
Px=Ax+r(Bx-Ax)
|
|
|
|
Py=Ay+r(By-Ay)
|
|
|
|
By examining the values of r & s, you can also determine some other limiting conditions:
|
|
|
|
If 0<=r<=1 & 0<=s<=1, intersection exists
|
|
|
|
r<0 or r>1 or s<0 or s>1 line segments do not intersect
|
|
|
|
If the denominator in eqn 1 is zero, AB & CD are parallel
|
|
|
|
If the numerator in eqn 1 is also zero, AB & CD are collinear.
|
|
|
|
|
|
|
|
*/
|
|
|
|
r_top = (A->y-C->y)*(D->x-C->x) - (A->x-C->x)*(D->y-C->y) ;
|
|
|
|
r_bot = (B->x-A->x)*(D->y-C->y) - (B->y-A->y)*(D->x-C->x) ;
|
|
|
|
|
|
|
|
s_top = (A->y-C->y)*(B->x-A->x) - (A->x-C->x)*(B->y-A->y);
|
|
|
|
s_bot = (B->x-A->x)*(D->y-C->y) - (B->y-A->y)*(D->x-C->x);
|
|
|
|
|
|
|
|
if ( (r_bot==0) || (s_bot == 0) )
|
|
|
|
{
|
|
|
|
return (
|
|
|
|
min(distance2d_pt_seg(A,C,D),
|
|
|
|
min(distance2d_pt_seg(B,C,D),
|
|
|
|
min(distance2d_pt_seg(C,A,B),
|
|
|
|
distance2d_pt_seg(D,A,B))
|
|
|
|
)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
s = s_top/s_bot;
|
|
|
|
r= r_top/r_bot;
|
|
|
|
|
|
|
|
if ((r<0) || (r>1) || (s<0) || (s>1) )
|
|
|
|
{
|
|
|
|
//no intersection
|
|
|
|
return (
|
|
|
|
min(distance2d_pt_seg(A,C,D),
|
|
|
|
min(distance2d_pt_seg(B,C,D),
|
|
|
|
min(distance2d_pt_seg(C,A,B),
|
|
|
|
distance2d_pt_seg(D,A,B))
|
|
|
|
)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return -0; //intersection exists
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//search all the segments of pointarray to see which one is closest to p1
|
|
|
|
//Returns minimum distance between point and pointarray
|
|
|
|
double distance2d_pt_ptarray(POINT2D *p, POINTARRAY *pa)
|
|
|
|
{
|
|
|
|
double result = 0;
|
|
|
|
int t;
|
|
|
|
POINT2D *start, *end;
|
|
|
|
|
|
|
|
start = (POINT2D *)getPoint(pa, 0);
|
|
|
|
|
|
|
|
for (t=1; t<pa->npoints; t++)
|
|
|
|
{
|
|
|
|
double dist;
|
|
|
|
end = (POINT2D *)getPoint(pa, t);
|
|
|
|
dist = distance2d_pt_seg(p, start, end);
|
|
|
|
if (t==1) result = dist;
|
|
|
|
else result = min(result, dist);
|
|
|
|
|
|
|
|
if ( result == 0 ) return 0;
|
|
|
|
|
|
|
|
start = end;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// test each segment of l1 against each segment of l2. Return min
|
|
|
|
double distance2d_ptarray_ptarray(POINTARRAY *l1, POINTARRAY *l2)
|
|
|
|
{
|
|
|
|
double result = 99999999999.9;
|
|
|
|
bool result_okay = FALSE; //result is a valid min
|
|
|
|
int t,u;
|
|
|
|
POINT2D *start,*end;
|
|
|
|
POINT2D *start2,*end2;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, "distance2d_ptarray_ptarray called (points: %d-%d)",
|
|
|
|
l1->npoints, l2->npoints);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
start = (POINT2D *)getPoint(l1, 0);
|
|
|
|
for (t=1; t<l1->npoints; t++) //for each segment in L1
|
|
|
|
{
|
|
|
|
end = (POINT2D *)getPoint(l1, t);
|
|
|
|
|
|
|
|
start2 = (POINT2D *)getPoint(l2, 0);
|
|
|
|
for (u=1; u<l2->npoints; u++) //for each segment in L2
|
|
|
|
{
|
|
|
|
double dist;
|
|
|
|
|
|
|
|
end2 = (POINT2D *)getPoint(l2, u);
|
|
|
|
|
|
|
|
dist = distance2d_seg_seg(start, end, start2, end2);
|
|
|
|
//printf("line_line; seg %i * seg %i, dist = %g\n",t,u,dist_this);
|
|
|
|
|
|
|
|
if (result_okay)
|
|
|
|
result = min(result,dist);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
result_okay = TRUE;
|
|
|
|
result = dist;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, " seg%d-seg%d dist: %f, mindist: %f",
|
|
|
|
t, u, dist, result);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (result <= 0) return 0; //intersection
|
|
|
|
|
|
|
|
start2 = end2;
|
|
|
|
}
|
|
|
|
start = end;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Brute force.
|
|
|
|
// Test line-ring distance against each ring.
|
|
|
|
// If there's an intersection (distance==0) then return 0 (crosses boundary).
|
|
|
|
// Otherwise, test to see if any point is inside outer rings of polygon,
|
|
|
|
// but not in inner rings.
|
|
|
|
// If so, return 0 (line inside polygon),
|
|
|
|
// otherwise return min distance to a ring (could be outside
|
|
|
|
// polygon or inside a hole)
|
|
|
|
double distance2d_ptarray_poly(POINTARRAY *pa, LWPOLY *poly)
|
|
|
|
{
|
|
|
|
POINT2D *pt;
|
|
|
|
int i;
|
|
|
|
double mindist = 0;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, "distance2d_ptarray_poly called (%d rings)", poly->nrings);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for (i=0; i<poly->nrings; i++)
|
|
|
|
{
|
|
|
|
double dist = distance2d_ptarray_ptarray(pa, poly->rings[i]);
|
|
|
|
if (i) mindist = min(mindist, dist);
|
|
|
|
else mindist = dist;
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, " distance from ring %d: %f, mindist: %f",
|
|
|
|
i, dist, mindist);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if ( mindist <= 0 ) return 0.0; // intersection
|
|
|
|
}
|
|
|
|
|
|
|
|
// No intersection, have to check if a point is
|
|
|
|
// inside polygon
|
|
|
|
pt = (POINT2D *)getPoint(pa, 0);
|
|
|
|
|
|
|
|
// Outside outer ring, so min distance to a ring
|
|
|
|
// is the actual min distance
|
|
|
|
if ( ! pt_in_ring_2d(pt, poly->rings[0]) ) return mindist;
|
|
|
|
|
|
|
|
// Its in the outer ring.
|
|
|
|
// Have to check if its inside a hole
|
|
|
|
for (i=1; i<poly->nrings; i++)
|
|
|
|
{
|
|
|
|
if ( pt_in_ring_2d(pt, poly->rings[i]) )
|
|
|
|
{
|
|
|
|
// Its inside a hole, then the actual
|
|
|
|
// distance is the min ring distance
|
|
|
|
return mindist;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0.0; // Not in hole, so inside polygon
|
|
|
|
}
|
|
|
|
|
|
|
|
double distance2d_point_point(LWPOINT *point1, LWPOINT *point2)
|
|
|
|
{
|
|
|
|
POINT2D *p1 = (POINT2D *)getPoint(point1->point, 0);
|
|
|
|
POINT2D *p2 = (POINT2D *)getPoint(point2->point, 0);
|
|
|
|
return distance2d_pt_pt(p1, p2);
|
|
|
|
}
|
|
|
|
|
|
|
|
double distance2d_point_line(LWPOINT *point, LWLINE *line)
|
|
|
|
{
|
|
|
|
POINT2D *p = (POINT2D *)getPoint(point->point, 0);
|
|
|
|
POINTARRAY *pa = line->points;
|
|
|
|
return distance2d_pt_ptarray(p, pa);
|
|
|
|
}
|
|
|
|
|
|
|
|
double distance2d_line_line(LWLINE *line1, LWLINE *line2)
|
|
|
|
{
|
|
|
|
POINTARRAY *pa1 = line1->points;
|
|
|
|
POINTARRAY *pa2 = line2->points;
|
|
|
|
return distance2d_ptarray_ptarray(pa1, pa2);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 1. see if pt in outer boundary. if no, then treat the outer ring like a line
|
|
|
|
// 2. if in the boundary, test to see if its in a hole.
|
|
|
|
// if so, then return dist to hole, else return 0 (point in polygon)
|
|
|
|
double distance2d_point_poly(LWPOINT *point, LWPOLY *poly)
|
|
|
|
{
|
|
|
|
POINT2D *p = (POINT2D *)getPoint(point->point, 0);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, "distance2d_point_poly called");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Return distance to outer ring if not inside it
|
|
|
|
if ( ! pt_in_ring_2d(p, poly->rings[0]) )
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, " not inside outer-ring");
|
|
|
|
#endif
|
|
|
|
return distance2d_pt_ptarray(p, poly->rings[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Inside the outer ring.
|
|
|
|
// Scan though each of the inner rings looking to
|
|
|
|
// see if its inside. If not, distance==0.
|
|
|
|
// Otherwise, distance = pt to ring distance
|
|
|
|
for (i=1; i<poly->nrings; i++)
|
|
|
|
{
|
|
|
|
// Inside a hole. Distance = pt -> ring
|
|
|
|
if ( pt_in_ring_2d(p, poly->rings[i]) )
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, " inside an hole");
|
|
|
|
#endif
|
|
|
|
return distance2d_pt_ptarray(p, poly->rings[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, " inside the polygon");
|
|
|
|
#endif
|
|
|
|
return 0.0; // Is inside the polygon
|
|
|
|
}
|
|
|
|
|
|
|
|
// Brute force.
|
|
|
|
// Test to see if any rings intersect.
|
|
|
|
// If yes, dist=0.
|
|
|
|
// Test to see if one inside the other and if they are inside holes.
|
|
|
|
// Find min distance ring-to-ring.
|
|
|
|
double distance2d_poly_poly(LWPOLY *poly1, LWPOLY *poly2)
|
|
|
|
{
|
|
|
|
POINT2D *pt;
|
|
|
|
double mindist = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, "distance2d_poly_poly called");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// if poly1 inside poly2 return 0
|
|
|
|
pt = (POINT2D *)getPoint(poly1->rings[0], 0);
|
|
|
|
if ( pt_in_poly_2d(pt, poly2) ) return 0.0;
|
|
|
|
|
|
|
|
// if poly2 inside poly1 return 0
|
|
|
|
pt = (POINT2D *)getPoint(poly2->rings[0], 0);
|
|
|
|
if ( pt_in_poly_2d(pt, poly1) ) return 0.0;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, " polys not inside each other");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//foreach ring in Poly1
|
|
|
|
// foreach ring in Poly2
|
|
|
|
// if intersect, return 0
|
|
|
|
for (i=0; i<poly1->nrings; i++)
|
|
|
|
{
|
|
|
|
double dist = distance2d_ptarray_poly(poly1->rings[i], poly2);
|
|
|
|
if (i) mindist = min(mindist, dist);
|
|
|
|
else mindist = dist;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, " ring%d dist: %f, mindist: %f", i, dist, mindist);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if ( mindist <= 0 ) return 0.0; // intersection
|
|
|
|
}
|
|
|
|
|
|
|
|
// otherwise return closest approach of rings (no intersection)
|
|
|
|
return mindist;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
double distance2d_line_poly(LWLINE *line, LWPOLY *poly)
|
|
|
|
{
|
|
|
|
return distance2d_ptarray_poly(line->points, poly);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-08-25 12:32:12 +00:00
|
|
|
//find the 2d length of the given POINTARRAY (even if it's 3d)
|
|
|
|
double lwgeom_pointarray_length2d(POINTARRAY *pts)
|
|
|
|
{
|
|
|
|
double dist = 0.0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if ( pts->npoints < 2 ) return 0.0;
|
|
|
|
for (i=0; i<pts->npoints-1;i++)
|
|
|
|
{
|
|
|
|
POINT2D *frm = (POINT2D *)getPoint(pts, i);
|
|
|
|
POINT2D *to = (POINT2D *)getPoint(pts, i+1);
|
|
|
|
dist += sqrt( ( (frm->x - to->x)*(frm->x - to->x) ) +
|
|
|
|
((frm->y - to->y)*(frm->y - to->y) ) );
|
|
|
|
}
|
|
|
|
return dist;
|
|
|
|
}
|
|
|
|
|
|
|
|
//find the 3d/2d length of the given POINTARRAY (depending on its dimensions)
|
2004-10-05 16:28:34 +00:00
|
|
|
double
|
|
|
|
lwgeom_pointarray_length(POINTARRAY *pts)
|
2004-08-25 12:32:12 +00:00
|
|
|
{
|
|
|
|
double dist = 0.0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if ( pts->npoints < 2 ) return 0.0;
|
|
|
|
|
|
|
|
// compute 2d length if 3d is not available
|
2004-10-05 16:28:34 +00:00
|
|
|
if ( ! TYPE_HASZ(pts->dims) ) return lwgeom_pointarray_length2d(pts);
|
2004-08-25 12:32:12 +00:00
|
|
|
|
|
|
|
for (i=0; i<pts->npoints-1;i++)
|
|
|
|
{
|
2004-10-05 16:28:34 +00:00
|
|
|
POINT3DZ *frm = (POINT3DZ *)getPoint(pts, i);
|
|
|
|
POINT3DZ *to = (POINT3DZ *)getPoint(pts, i+1);
|
2004-08-25 12:32:12 +00:00
|
|
|
dist += sqrt( ( (frm->x - to->x)*(frm->x - to->x) ) +
|
|
|
|
((frm->y - to->y)*(frm->y - to->y) ) +
|
|
|
|
((frm->z - to->z)*(frm->z - to->z) ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
return dist;
|
|
|
|
}
|
|
|
|
|
|
|
|
//find the area of the outer ring - sum (area of inner rings)
|
|
|
|
// Could use a more numerically stable calculator...
|
|
|
|
double lwgeom_polygon_area(LWPOLY *poly)
|
|
|
|
{
|
|
|
|
double poly_area=0.0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
//elog(NOTICE,"in lwgeom_polygon_area (%d rings)", poly->nrings);
|
|
|
|
|
|
|
|
for (i=0; i<poly->nrings; i++)
|
|
|
|
{
|
|
|
|
int j;
|
|
|
|
POINTARRAY *ring = poly->rings[i];
|
|
|
|
double ringarea = 0.0;
|
|
|
|
|
|
|
|
//elog(NOTICE," rings %d has %d points", i, ring->npoints);
|
|
|
|
for (j=0; j<ring->npoints-1; j++)
|
|
|
|
{
|
|
|
|
POINT2D *p1 = (POINT2D *)getPoint(ring, j);
|
|
|
|
POINT2D *p2 = (POINT2D *)getPoint(ring, j+1);
|
|
|
|
ringarea += ( p1->x * p2->y ) - ( p1->y * p2->x );
|
|
|
|
}
|
|
|
|
|
|
|
|
ringarea /= 2.0;
|
|
|
|
//elog(NOTICE," ring 1 has area %lf",ringarea);
|
|
|
|
ringarea = fabs(ringarea );
|
|
|
|
if (i != 0) //outer
|
|
|
|
ringarea = -1.0*ringarea ; // its a hole
|
|
|
|
|
|
|
|
poly_area += ringarea;
|
|
|
|
}
|
|
|
|
|
|
|
|
return poly_area;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compute the sum of polygon rings length.
|
|
|
|
// Could use a more numerically stable calculator...
|
|
|
|
double lwgeom_polygon_perimeter(LWPOLY *poly)
|
|
|
|
{
|
|
|
|
double result=0.0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
//elog(NOTICE,"in lwgeom_polygon_perimeter (%d rings)", poly->nrings);
|
|
|
|
|
|
|
|
for (i=0; i<poly->nrings; i++)
|
|
|
|
result += lwgeom_pointarray_length(poly->rings[i]);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compute the sum of polygon rings length (forcing 2d computation).
|
|
|
|
// Could use a more numerically stable calculator...
|
|
|
|
double lwgeom_polygon_perimeter2d(LWPOLY *poly)
|
|
|
|
{
|
|
|
|
double result=0.0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
//elog(NOTICE,"in lwgeom_polygon_perimeter (%d rings)", poly->nrings);
|
|
|
|
|
|
|
|
for (i=0; i<poly->nrings; i++)
|
|
|
|
result += lwgeom_pointarray_length2d(poly->rings[i]);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2004-08-26 12:55:30 +00:00
|
|
|
double
|
|
|
|
lwgeom_mindistance2d_recursive(char *lw1, char *lw2)
|
|
|
|
{
|
|
|
|
LWGEOM_INSPECTED *in1, *in2;
|
|
|
|
int i, j;
|
|
|
|
double mindist = -1;
|
|
|
|
|
|
|
|
in1 = lwgeom_inspect(lw1);
|
|
|
|
in2 = lwgeom_inspect(lw2);
|
|
|
|
|
|
|
|
for (i=0; i<in1->ngeometries; i++)
|
|
|
|
{
|
|
|
|
char *g1 = lwgeom_getsubgeometry_inspected(in1, i);
|
|
|
|
int t1 = lwgeom_getType(g1[0]);
|
|
|
|
double dist=0;
|
|
|
|
|
|
|
|
// it's a multitype... recurse
|
|
|
|
if ( t1 >= 4 )
|
|
|
|
{
|
|
|
|
dist = lwgeom_mindistance2d_recursive(g1, lw2);
|
|
|
|
if ( dist == 0 ) return 0.0; // can't be closer
|
|
|
|
if ( mindist == -1 ) mindist = dist;
|
|
|
|
else mindist = min(dist, mindist);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (j=0; j<in2->ngeometries; j++)
|
|
|
|
{
|
|
|
|
char *g2 = lwgeom_getsubgeometry_inspected(in2, j);
|
|
|
|
int t2 = lwgeom_getType(g2[0]);
|
|
|
|
|
|
|
|
if ( t1 == POINTTYPE )
|
|
|
|
{
|
|
|
|
if ( t2 == POINTTYPE )
|
|
|
|
{
|
|
|
|
dist = distance2d_point_point(
|
|
|
|
lwpoint_deserialize(g1),
|
|
|
|
lwpoint_deserialize(g2)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
else if ( t2 == LINETYPE )
|
|
|
|
{
|
|
|
|
dist = distance2d_point_line(
|
|
|
|
lwpoint_deserialize(g1),
|
|
|
|
lwline_deserialize(g2)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
else if ( t2 == POLYGONTYPE )
|
|
|
|
{
|
|
|
|
dist = distance2d_point_poly(
|
|
|
|
lwpoint_deserialize(g1),
|
|
|
|
lwpoly_deserialize(g2)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( t1 == LINETYPE )
|
|
|
|
{
|
|
|
|
if ( t2 == POINTTYPE )
|
|
|
|
{
|
|
|
|
dist = distance2d_point_line(
|
|
|
|
lwpoint_deserialize(g2),
|
|
|
|
lwline_deserialize(g1)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
else if ( t2 == LINETYPE )
|
|
|
|
{
|
|
|
|
dist = distance2d_line_line(
|
|
|
|
lwline_deserialize(g1),
|
|
|
|
lwline_deserialize(g2)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
else if ( t2 == POLYGONTYPE )
|
|
|
|
{
|
|
|
|
dist = distance2d_line_poly(
|
|
|
|
lwline_deserialize(g1),
|
|
|
|
lwpoly_deserialize(g2)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( t1 == POLYGONTYPE )
|
|
|
|
{
|
|
|
|
if ( t2 == POLYGONTYPE )
|
|
|
|
{
|
|
|
|
dist = distance2d_poly_poly(
|
|
|
|
lwpoly_deserialize(g2),
|
|
|
|
lwpoly_deserialize(g1)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
else if ( t2 == POINTTYPE )
|
|
|
|
{
|
|
|
|
dist = distance2d_point_poly(
|
|
|
|
lwpoint_deserialize(g2),
|
|
|
|
lwpoly_deserialize(g1)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
else if ( t2 == LINETYPE )
|
|
|
|
{
|
|
|
|
dist = distance2d_line_poly(
|
|
|
|
lwline_deserialize(g2),
|
|
|
|
lwpoly_deserialize(g1)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else // it's a multitype... recurse
|
|
|
|
{
|
|
|
|
dist = lwgeom_mindistance2d_recursive(g1, g2);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mindist == -1 ) mindist = dist;
|
|
|
|
else mindist = min(dist, mindist);
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, "dist %d-%d: %f - mindist: %f",
|
|
|
|
t1, t2, dist, mindist);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
if (mindist <= 0.0) return 0.0; // can't be closer
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mindist<0) mindist = 0;
|
|
|
|
|
|
|
|
return mindist;
|
|
|
|
}
|
|
|
|
|
2004-08-27 08:13:16 +00:00
|
|
|
int
|
|
|
|
lwgeom_pt_inside_circle(POINT2D *p, double cx, double cy, double rad)
|
|
|
|
{
|
|
|
|
POINT2D center;
|
|
|
|
|
|
|
|
center.x = cx;
|
|
|
|
center.y = cy;
|
|
|
|
|
|
|
|
if ( distance2d_pt_pt(p, ¢er) < rad ) return 1;
|
|
|
|
else return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2004-08-24 10:01:16 +00:00
|
|
|
/*------------------------------------------------------------------*/
|
2004-08-17 15:27:47 +00:00
|
|
|
|
2004-08-19 13:56:30 +00:00
|
|
|
//find the size of geometry
|
2004-08-24 10:01:16 +00:00
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_mem_size);
|
|
|
|
Datum LWGEOM_mem_size(PG_FUNCTION_ARGS)
|
2004-08-19 13:56:30 +00:00
|
|
|
{
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom = (PG_LWGEOM *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
2004-08-23 10:49:08 +00:00
|
|
|
int32 size = geom->size;
|
2004-09-22 16:09:54 +00:00
|
|
|
int32 computed_size = lwgeom_size(SERIALIZED_FORM(geom));
|
2004-08-23 10:49:08 +00:00
|
|
|
computed_size += 4; // varlena size
|
|
|
|
if ( size != computed_size )
|
|
|
|
{
|
|
|
|
elog(NOTICE, "varlena size (%d) != computed size+4 (%d)",
|
|
|
|
size, computed_size);
|
|
|
|
}
|
|
|
|
|
2004-08-20 09:31:32 +00:00
|
|
|
PG_FREE_IF_COPY(geom,0);
|
|
|
|
PG_RETURN_INT32(size);
|
2004-08-19 13:56:30 +00:00
|
|
|
}
|
2004-08-23 08:32:14 +00:00
|
|
|
|
2004-08-27 08:13:16 +00:00
|
|
|
/*
|
|
|
|
* Translate a pointarray.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
lwgeom_translate_ptarray(POINTARRAY *pa, double xoff, double yoff, double zoff)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2004-10-05 16:28:34 +00:00
|
|
|
if ( TYPE_HASZ(pa->dims) )
|
|
|
|
{
|
2004-08-27 08:13:16 +00:00
|
|
|
for (i=0; i<pa->npoints; i++) {
|
2004-10-05 16:28:34 +00:00
|
|
|
POINT3DZ *p = (POINT3DZ *)getPoint(pa, i);
|
2004-08-27 08:13:16 +00:00
|
|
|
p->x += xoff;
|
|
|
|
p->y += yoff;
|
|
|
|
p->z += zoff;
|
|
|
|
}
|
2004-10-05 16:28:34 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-08-27 08:13:16 +00:00
|
|
|
for (i=0; i<pa->npoints; i++) {
|
|
|
|
POINT2D *p = (POINT2D *)getPoint(pa, i);
|
|
|
|
p->x += xoff;
|
|
|
|
p->y += yoff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
lwgeom_translate_recursive(char *serialized,
|
|
|
|
double xoff, double yoff, double zoff)
|
|
|
|
{
|
|
|
|
LWGEOM_INSPECTED *inspected;
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
inspected = lwgeom_inspect(serialized);
|
|
|
|
|
|
|
|
// scan each object translating it
|
|
|
|
for (i=0; i<inspected->ngeometries; i++)
|
|
|
|
{
|
|
|
|
LWLINE *line=NULL;
|
|
|
|
LWPOINT *point=NULL;
|
|
|
|
LWPOLY *poly=NULL;
|
|
|
|
char *subgeom=NULL;
|
|
|
|
|
|
|
|
point = lwgeom_getpoint_inspected(inspected, i);
|
|
|
|
if (point !=NULL)
|
|
|
|
{
|
|
|
|
lwgeom_translate_ptarray(point->point,
|
|
|
|
xoff, yoff, zoff);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
poly = lwgeom_getpoly_inspected(inspected, i);
|
|
|
|
if (poly !=NULL)
|
|
|
|
{
|
|
|
|
for (j=0; j<poly->nrings; j++)
|
|
|
|
{
|
|
|
|
lwgeom_translate_ptarray(poly->rings[j],
|
|
|
|
xoff, yoff, zoff);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
line = lwgeom_getline_inspected(inspected, i);
|
|
|
|
if (line != NULL)
|
|
|
|
{
|
|
|
|
lwgeom_translate_ptarray(line->points,
|
|
|
|
xoff, yoff, zoff);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
subgeom = lwgeom_getsubgeometry_inspected(inspected, i);
|
|
|
|
if ( subgeom == NULL )
|
|
|
|
{
|
|
|
|
elog(ERROR, "lwgeom_getsubgeometry_inspected returned NULL??");
|
|
|
|
}
|
|
|
|
lwgeom_translate_recursive(subgeom, xoff, yoff, zoff);
|
|
|
|
}
|
|
|
|
|
|
|
|
pfree_inspected(inspected);
|
|
|
|
}
|
|
|
|
|
2004-08-23 08:32:14 +00:00
|
|
|
//get summary info on a GEOMETRY
|
2004-08-24 10:01:16 +00:00
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_summary);
|
|
|
|
Datum LWGEOM_summary(PG_FUNCTION_ARGS)
|
2004-08-23 08:32:14 +00:00
|
|
|
{
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
2004-08-23 08:32:14 +00:00
|
|
|
char *result;
|
|
|
|
text *mytext;
|
2004-09-29 15:25:21 +00:00
|
|
|
LWGEOM *lwgeom;
|
|
|
|
|
|
|
|
init_pg_func();
|
|
|
|
|
|
|
|
lwgeom = lwgeom_deserialize(SERIALIZED_FORM(geom));
|
2004-08-23 08:32:14 +00:00
|
|
|
|
2004-09-29 15:25:21 +00:00
|
|
|
result = lwgeom_summary(lwgeom, 0);
|
2004-08-23 08:32:14 +00:00
|
|
|
|
|
|
|
// create a text obj to return
|
2004-09-30 11:45:40 +00:00
|
|
|
mytext = (text *) lwalloc(VARHDRSZ + strlen(result) + 1);
|
|
|
|
VARATT_SIZEP(mytext) = VARHDRSZ + strlen(result) + 1;
|
|
|
|
VARDATA(mytext)[0] = '\n';
|
|
|
|
memcpy(VARDATA(mytext)+1, result, strlen(result) );
|
2004-09-29 15:25:21 +00:00
|
|
|
lwfree(result);
|
2004-08-23 08:32:14 +00:00
|
|
|
PG_RETURN_POINTER(mytext);
|
|
|
|
}
|
2004-08-23 15:37:16 +00:00
|
|
|
|
|
|
|
PG_FUNCTION_INFO_V1(postgis_lib_version);
|
|
|
|
Datum postgis_lib_version(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *ver = POSTGIS_LIB_VERSION;
|
|
|
|
text *result;
|
2004-09-29 15:25:21 +00:00
|
|
|
result = (text *) lwalloc(VARHDRSZ + strlen(ver));
|
2004-08-23 15:37:16 +00:00
|
|
|
VARATT_SIZEP(result) = VARHDRSZ + strlen(ver) ;
|
|
|
|
memcpy(VARDATA(result), ver, strlen(ver));
|
|
|
|
PG_RETURN_POINTER(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_FUNCTION_INFO_V1(postgis_scripts_released);
|
|
|
|
Datum postgis_scripts_released(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *ver = POSTGIS_SCRIPTS_VERSION;
|
|
|
|
text *result;
|
2004-09-29 15:25:21 +00:00
|
|
|
result = (text *) lwalloc(VARHDRSZ + strlen(ver));
|
2004-08-23 15:37:16 +00:00
|
|
|
VARATT_SIZEP(result) = VARHDRSZ + strlen(ver) ;
|
|
|
|
memcpy(VARDATA(result), ver, strlen(ver));
|
|
|
|
PG_RETURN_POINTER(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_FUNCTION_INFO_V1(postgis_uses_stats);
|
|
|
|
Datum postgis_uses_stats(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
#ifdef USE_STATS
|
|
|
|
PG_RETURN_BOOL(TRUE);
|
|
|
|
#else
|
|
|
|
PG_RETURN_BOOL(FALSE);
|
|
|
|
#endif
|
|
|
|
}
|
2004-08-24 09:34:33 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Recursively count points in a SERIALIZED lwgeom
|
|
|
|
*/
|
|
|
|
int32
|
2004-09-22 11:42:45 +00:00
|
|
|
lwgeom_npoints(char *serialized)
|
2004-08-24 09:34:33 +00:00
|
|
|
{
|
|
|
|
LWGEOM_INSPECTED *inspected = lwgeom_inspect(serialized);
|
|
|
|
int i, j;
|
|
|
|
int npoints=0;
|
|
|
|
|
|
|
|
//now have to do a scan of each object
|
|
|
|
for (i=0; i<inspected->ngeometries; i++)
|
|
|
|
{
|
|
|
|
LWLINE *line=NULL;
|
|
|
|
LWPOINT *point=NULL;
|
|
|
|
LWPOLY *poly=NULL;
|
|
|
|
char *subgeom=NULL;
|
|
|
|
|
|
|
|
point = lwgeom_getpoint_inspected(inspected, i);
|
|
|
|
if (point !=NULL)
|
|
|
|
{
|
|
|
|
npoints++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
poly = lwgeom_getpoly_inspected(inspected, i);
|
|
|
|
if (poly !=NULL)
|
|
|
|
{
|
|
|
|
for (j=0; j<poly->nrings; j++)
|
|
|
|
{
|
|
|
|
npoints += poly->rings[j]->npoints;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
line = lwgeom_getline_inspected(inspected, i);
|
|
|
|
if (line != NULL)
|
|
|
|
{
|
|
|
|
npoints += line->points->npoints;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
subgeom = lwgeom_getsubgeometry_inspected(inspected, i);
|
|
|
|
if ( subgeom != NULL )
|
|
|
|
{
|
2004-09-22 11:42:45 +00:00
|
|
|
npoints += lwgeom_npoints(subgeom);
|
2004-08-24 09:34:33 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
elog(ERROR, "What ? lwgeom_getsubgeometry_inspected returned NULL??");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return npoints;
|
|
|
|
}
|
|
|
|
|
2004-08-26 16:44:01 +00:00
|
|
|
/*
|
|
|
|
* Recursively count rings in a SERIALIZED lwgeom
|
|
|
|
*/
|
|
|
|
int32
|
|
|
|
lwgeom_nrings_recursive(char *serialized)
|
|
|
|
{
|
|
|
|
LWGEOM_INSPECTED *inspected;
|
|
|
|
int i;
|
|
|
|
int nrings=0;
|
|
|
|
|
|
|
|
inspected = lwgeom_inspect(serialized);
|
|
|
|
|
|
|
|
//now have to do a scan of each object
|
|
|
|
for (i=0; i<inspected->ngeometries; i++)
|
|
|
|
{
|
|
|
|
LWPOLY *poly=NULL;
|
|
|
|
char *subgeom=NULL;
|
|
|
|
|
|
|
|
subgeom = lwgeom_getsubgeometry_inspected(inspected, i);
|
|
|
|
|
|
|
|
if ( lwgeom_getType(subgeom[0]) == POLYGONTYPE )
|
|
|
|
{
|
|
|
|
poly = lwpoly_deserialize(subgeom);
|
|
|
|
nrings += poly->nrings;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( lwgeom_getType(subgeom[0]) == COLLECTIONTYPE )
|
|
|
|
{
|
|
|
|
nrings += lwgeom_nrings_recursive(subgeom);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pfree_inspected(inspected);
|
|
|
|
|
|
|
|
return nrings;
|
|
|
|
}
|
|
|
|
|
2004-08-24 09:34:33 +00:00
|
|
|
//number of points in an object
|
2004-08-24 10:01:16 +00:00
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_npoints);
|
|
|
|
Datum LWGEOM_npoints(PG_FUNCTION_ARGS)
|
2004-08-24 09:34:33 +00:00
|
|
|
{
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
2004-08-24 09:34:33 +00:00
|
|
|
int32 npoints = 0;
|
|
|
|
|
2004-09-22 11:42:45 +00:00
|
|
|
npoints = lwgeom_npoints(SERIALIZED_FORM(geom));
|
2004-08-24 09:34:33 +00:00
|
|
|
|
|
|
|
PG_RETURN_INT32(npoints);
|
|
|
|
}
|
|
|
|
|
2004-08-26 16:44:01 +00:00
|
|
|
//number of rings in an object
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_nrings);
|
|
|
|
Datum LWGEOM_nrings(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
2004-08-26 16:44:01 +00:00
|
|
|
int32 nrings = 0;
|
|
|
|
|
|
|
|
nrings = lwgeom_nrings_recursive(SERIALIZED_FORM(geom));
|
|
|
|
|
|
|
|
PG_RETURN_INT32(nrings);
|
|
|
|
}
|
|
|
|
|
2004-08-25 12:32:12 +00:00
|
|
|
// Calculate the area of all the subobj in a polygon
|
|
|
|
// area(point) = 0
|
|
|
|
// area (line) = 0
|
|
|
|
// area(polygon) = find its 2d area
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_area_polygon);
|
|
|
|
Datum LWGEOM_area_polygon(PG_FUNCTION_ARGS)
|
2004-08-25 07:29:32 +00:00
|
|
|
{
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
2004-08-25 12:32:12 +00:00
|
|
|
LWGEOM_INSPECTED *inspected = lwgeom_inspect(SERIALIZED_FORM(geom));
|
|
|
|
LWPOLY *poly;
|
|
|
|
double area = 0.0;
|
2004-08-25 07:29:32 +00:00
|
|
|
int i;
|
|
|
|
|
2004-08-25 12:32:12 +00:00
|
|
|
//elog(NOTICE, "in LWGEOM_area_polygon");
|
2004-08-25 07:29:32 +00:00
|
|
|
|
2004-08-25 12:32:12 +00:00
|
|
|
for (i=0; i<inspected->ngeometries; i++)
|
2004-08-25 07:29:32 +00:00
|
|
|
{
|
2004-08-25 12:32:12 +00:00
|
|
|
poly = lwgeom_getpoly_inspected(inspected, i);
|
|
|
|
if ( poly == NULL ) continue;
|
|
|
|
area += lwgeom_polygon_area(poly);
|
|
|
|
//elog(NOTICE, " LWGEOM_area_polygon found a poly (%f)", area);
|
|
|
|
}
|
|
|
|
|
|
|
|
pfree_inspected(inspected);
|
2004-08-25 07:29:32 +00:00
|
|
|
|
2004-08-25 12:32:12 +00:00
|
|
|
PG_RETURN_FLOAT8(area);
|
|
|
|
}
|
2004-08-25 07:29:32 +00:00
|
|
|
|
2004-08-25 12:32:12 +00:00
|
|
|
//find the "length of a geometry"
|
|
|
|
// length2d(point) = 0
|
|
|
|
// length2d(line) = length of line
|
|
|
|
// length2d(polygon) = 0 -- could make sense to return sum(ring perimeter)
|
|
|
|
// uses euclidian 2d length (even if input is 3d)
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_length2d_linestring);
|
|
|
|
Datum LWGEOM_length2d_linestring(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
2004-08-25 12:32:12 +00:00
|
|
|
LWGEOM_INSPECTED *inspected = lwgeom_inspect(SERIALIZED_FORM(geom));
|
|
|
|
LWLINE *line;
|
|
|
|
double dist = 0.0;
|
|
|
|
int i;
|
2004-08-25 07:29:32 +00:00
|
|
|
|
2004-08-25 12:32:12 +00:00
|
|
|
//elog(NOTICE, "in LWGEOM_length2d");
|
|
|
|
|
|
|
|
for (i=0; i<inspected->ngeometries; i++)
|
|
|
|
{
|
|
|
|
line = lwgeom_getline_inspected(inspected, i);
|
|
|
|
if ( line == NULL ) continue;
|
|
|
|
dist += lwgeom_pointarray_length2d(line->points);
|
|
|
|
//elog(NOTICE, " LWGEOM_length2d found a line (%f)", dist);
|
2004-08-25 07:29:32 +00:00
|
|
|
}
|
|
|
|
|
2004-08-25 12:32:12 +00:00
|
|
|
pfree_inspected(inspected);
|
|
|
|
|
|
|
|
PG_RETURN_FLOAT8(dist);
|
2004-08-25 07:29:32 +00:00
|
|
|
}
|
|
|
|
|
2004-08-25 12:32:12 +00:00
|
|
|
//find the "length of a geometry"
|
|
|
|
// length(point) = 0
|
|
|
|
// length(line) = length of line
|
|
|
|
// length(polygon) = 0 -- could make sense to return sum(ring perimeter)
|
|
|
|
// uses euclidian 3d/2d length depending on input dimensions.
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_length_linestring);
|
|
|
|
Datum LWGEOM_length_linestring(PG_FUNCTION_ARGS)
|
2004-08-25 07:29:32 +00:00
|
|
|
{
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
2004-08-25 07:29:32 +00:00
|
|
|
LWGEOM_INSPECTED *inspected = lwgeom_inspect(SERIALIZED_FORM(geom));
|
2004-08-25 12:32:12 +00:00
|
|
|
LWLINE *line;
|
|
|
|
double dist = 0.0;
|
2004-08-25 07:29:32 +00:00
|
|
|
int i;
|
|
|
|
|
2004-08-25 12:32:12 +00:00
|
|
|
for (i=0; i<inspected->ngeometries; i++)
|
|
|
|
{
|
|
|
|
line = lwgeom_getline_inspected(inspected, i);
|
|
|
|
if ( line == NULL ) continue;
|
|
|
|
dist += lwgeom_pointarray_length(line->points);
|
|
|
|
}
|
|
|
|
|
|
|
|
pfree_inspected(inspected);
|
|
|
|
|
|
|
|
PG_RETURN_FLOAT8(dist);
|
|
|
|
}
|
|
|
|
|
|
|
|
// find the "perimeter of a geometry"
|
|
|
|
// perimeter(point) = 0
|
|
|
|
// perimeter(line) = 0
|
|
|
|
// perimeter(polygon) = sum of ring perimeters
|
|
|
|
// uses euclidian 3d/2d computation depending on input dimension.
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_perimeter_poly);
|
|
|
|
Datum LWGEOM_perimeter_poly(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
2004-08-25 12:32:12 +00:00
|
|
|
LWGEOM_INSPECTED *inspected = lwgeom_inspect(SERIALIZED_FORM(geom));
|
|
|
|
double ret = 0.0;
|
|
|
|
int i;
|
2004-08-25 07:29:32 +00:00
|
|
|
|
|
|
|
for (i=0; i<inspected->ngeometries; i++)
|
|
|
|
{
|
2004-08-25 12:32:12 +00:00
|
|
|
LWPOLY *poly;
|
2004-08-25 07:29:32 +00:00
|
|
|
poly = lwgeom_getpoly_inspected(inspected, i);
|
|
|
|
if ( poly == NULL ) continue;
|
2004-08-25 12:32:12 +00:00
|
|
|
ret += lwgeom_polygon_perimeter(poly);
|
2004-08-25 07:29:32 +00:00
|
|
|
}
|
2004-08-25 12:32:12 +00:00
|
|
|
|
2004-08-25 07:29:32 +00:00
|
|
|
pfree_inspected(inspected);
|
|
|
|
|
2004-08-25 12:32:12 +00:00
|
|
|
PG_RETURN_FLOAT8(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
// find the "perimeter of a geometry"
|
|
|
|
// perimeter(point) = 0
|
|
|
|
// perimeter(line) = 0
|
|
|
|
// perimeter(polygon) = sum of ring perimeters
|
|
|
|
// uses euclidian 2d computation even if input is 3d
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_perimeter2d_poly);
|
|
|
|
Datum LWGEOM_perimeter2d_poly(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
2004-08-25 12:32:12 +00:00
|
|
|
LWGEOM_INSPECTED *inspected = lwgeom_inspect(SERIALIZED_FORM(geom));
|
|
|
|
double ret = 0.0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i=0; i<inspected->ngeometries; i++)
|
|
|
|
{
|
|
|
|
LWPOLY *poly;
|
|
|
|
poly = lwgeom_getpoly_inspected(inspected, i);
|
|
|
|
if ( poly == NULL ) continue;
|
|
|
|
ret += lwgeom_polygon_perimeter2d(poly);
|
|
|
|
}
|
|
|
|
|
|
|
|
pfree_inspected(inspected);
|
|
|
|
|
|
|
|
PG_RETURN_FLOAT8(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write to already allocated memory 'optr' a 2d version of
|
|
|
|
* the given serialized form.
|
2004-08-25 13:41:43 +00:00
|
|
|
* Higher dimensions in input geometry are discarder.
|
2004-08-25 12:32:12 +00:00
|
|
|
* Return number bytes written in given int pointer.
|
|
|
|
*/
|
|
|
|
void
|
2004-10-05 16:28:34 +00:00
|
|
|
lwgeom_force2d_recursive(char *serialized, char *optr, size_t *retsize)
|
2004-08-25 12:32:12 +00:00
|
|
|
{
|
|
|
|
LWGEOM_INSPECTED *inspected;
|
|
|
|
int i;
|
|
|
|
int totsize=0;
|
|
|
|
int size=0;
|
|
|
|
int type;
|
|
|
|
LWPOINT *point = NULL;
|
|
|
|
LWLINE *line = NULL;
|
|
|
|
LWPOLY *poly = NULL;
|
|
|
|
char *loc;
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, "lwgeom_force2d_recursive: call");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
type = lwgeom_getType(serialized[0]);
|
|
|
|
|
|
|
|
if ( type == POINTTYPE )
|
|
|
|
{
|
|
|
|
point = lwpoint_deserialize(serialized);
|
2004-10-04 13:53:42 +00:00
|
|
|
TYPE_SETZM(point->type, 0, 0);
|
2004-08-25 12:32:12 +00:00
|
|
|
lwpoint_serialize_buf(point, optr, retsize);
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, "lwgeom_force2d_recursive: it's a point, size:%d", *retsize);
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( type == LINETYPE )
|
|
|
|
{
|
|
|
|
line = lwline_deserialize(serialized);
|
2004-10-04 13:53:42 +00:00
|
|
|
TYPE_SETZM(line->type, 0, 0);
|
2004-08-25 12:32:12 +00:00
|
|
|
lwline_serialize_buf(line, optr, retsize);
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, "lwgeom_force2d_recursive: it's a line, size:%d", *retsize);
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( type == POLYGONTYPE )
|
|
|
|
{
|
|
|
|
poly = lwpoly_deserialize(serialized);
|
2004-10-04 13:53:42 +00:00
|
|
|
TYPE_SETZM(poly->type, 0, 0);
|
2004-08-25 12:32:12 +00:00
|
|
|
lwpoly_serialize_buf(poly, optr, retsize);
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, "lwgeom_force2d_recursive: it's a poly, size:%d", *retsize);
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// OK, this is a collection, so we write down its metadata
|
|
|
|
// first and then call us again
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, "lwgeom_force2d_recursive: it's a collection (type:%d)", type);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Add type
|
2004-10-05 16:28:34 +00:00
|
|
|
*optr = lwgeom_makeType_full(0, 0, lwgeom_hasSRID(serialized[0]),
|
2004-08-25 12:32:12 +00:00
|
|
|
type, lwgeom_hasBBOX(serialized[0]));
|
|
|
|
optr++;
|
|
|
|
totsize++;
|
|
|
|
loc=serialized+1;
|
|
|
|
|
|
|
|
// Add BBOX if any
|
|
|
|
if (lwgeom_hasBBOX(serialized[0]))
|
|
|
|
{
|
|
|
|
memcpy(optr, loc, sizeof(BOX2DFLOAT4));
|
|
|
|
optr += sizeof(BOX2DFLOAT4);
|
|
|
|
totsize += sizeof(BOX2DFLOAT4);
|
|
|
|
loc += sizeof(BOX2DFLOAT4);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add SRID if any
|
|
|
|
if (lwgeom_hasSRID(serialized[0]))
|
|
|
|
{
|
|
|
|
memcpy(optr, loc, 4);
|
|
|
|
optr += 4;
|
|
|
|
totsize += 4;
|
|
|
|
loc += 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add numsubobjects
|
|
|
|
memcpy(optr, loc, 4);
|
|
|
|
optr += 4;
|
|
|
|
totsize += 4;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, " collection header size:%d", totsize);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Now recurse for each suboject
|
|
|
|
inspected = lwgeom_inspect(serialized);
|
|
|
|
for (i=0; i<inspected->ngeometries; i++)
|
|
|
|
{
|
|
|
|
char *subgeom = lwgeom_getsubgeometry_inspected(inspected, i);
|
|
|
|
lwgeom_force2d_recursive(subgeom, optr, &size);
|
|
|
|
totsize += size;
|
|
|
|
optr += size;
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, " elem %d size: %d (tot: %d)", i, size, totsize);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
pfree_inspected(inspected);
|
|
|
|
|
|
|
|
*retsize = totsize;
|
|
|
|
}
|
|
|
|
|
2004-08-25 13:41:43 +00:00
|
|
|
/*
|
2004-10-05 16:28:34 +00:00
|
|
|
* Write to already allocated memory 'optr' a 3dz version of
|
2004-08-25 13:41:43 +00:00
|
|
|
* the given serialized form.
|
|
|
|
* Higher dimensions in input geometry are discarder.
|
|
|
|
* If the given version is 2d Z is set to 0.
|
|
|
|
* Return number bytes written in given int pointer.
|
|
|
|
*/
|
|
|
|
void
|
2004-10-05 16:28:34 +00:00
|
|
|
lwgeom_force3dz_recursive(char *serialized, char *optr, size_t *retsize)
|
2004-08-25 13:41:43 +00:00
|
|
|
{
|
|
|
|
LWGEOM_INSPECTED *inspected;
|
|
|
|
int i,j,k;
|
|
|
|
int totsize=0;
|
|
|
|
int size=0;
|
|
|
|
int type;
|
|
|
|
LWPOINT *point = NULL;
|
|
|
|
LWLINE *line = NULL;
|
|
|
|
LWPOLY *poly = NULL;
|
|
|
|
POINTARRAY newpts;
|
|
|
|
POINTARRAY **nrings;
|
|
|
|
char *loc;
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
2004-10-05 16:28:34 +00:00
|
|
|
elog(NOTICE, "lwgeom_force3dz_recursive: call");
|
2004-08-25 13:41:43 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
type = lwgeom_getType(serialized[0]);
|
|
|
|
|
|
|
|
if ( type == POINTTYPE )
|
|
|
|
{
|
|
|
|
point = lwpoint_deserialize(serialized);
|
2004-10-05 16:28:34 +00:00
|
|
|
TYPE_SETZM(newpts.dims, 1, 0);
|
|
|
|
newpts.npoints = 1;
|
|
|
|
newpts.serialized_pointlist = lwalloc(sizeof(POINT3DZ));
|
|
|
|
loc = newpts.serialized_pointlist;
|
|
|
|
getPoint3dz_p(point->point, 0, (POINT3DZ *)loc);
|
|
|
|
point->point = &newpts;
|
2004-10-04 13:53:42 +00:00
|
|
|
TYPE_SETZM(point->type, 1, 0);
|
2004-08-25 13:41:43 +00:00
|
|
|
lwpoint_serialize_buf(point, optr, retsize);
|
|
|
|
#ifdef DEBUG
|
2004-10-05 16:28:34 +00:00
|
|
|
elog(NOTICE, "lwgeom_force3dz_recursive: it's a point, size:%d", *retsize);
|
2004-08-25 13:41:43 +00:00
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( type == LINETYPE )
|
|
|
|
{
|
2004-10-05 16:28:34 +00:00
|
|
|
line = lwline_deserialize(serialized);
|
2004-08-25 13:41:43 +00:00
|
|
|
#ifdef DEBUG
|
2004-10-05 16:28:34 +00:00
|
|
|
elog(NOTICE, "lwgeom_force3dz_recursive: it's a line");
|
2004-08-25 13:41:43 +00:00
|
|
|
#endif
|
2004-10-05 16:28:34 +00:00
|
|
|
TYPE_SETZM(newpts.dims, 1, 0);
|
|
|
|
newpts.npoints = line->points->npoints;
|
|
|
|
newpts.serialized_pointlist = lwalloc(sizeof(POINT3DZ)*line->points->npoints);
|
|
|
|
loc = newpts.serialized_pointlist;
|
|
|
|
for (j=0; j<line->points->npoints; j++)
|
2004-08-25 13:41:43 +00:00
|
|
|
{
|
2004-10-05 16:28:34 +00:00
|
|
|
getPoint3dz_p(line->points, j, (POINT3DZ *)loc);
|
|
|
|
loc+=sizeof(POINT3DZ);
|
2004-08-25 13:41:43 +00:00
|
|
|
}
|
2004-10-05 16:28:34 +00:00
|
|
|
line->points = &newpts;
|
2004-10-04 13:53:42 +00:00
|
|
|
TYPE_SETZM(line->type, 1, 0);
|
2004-08-25 13:41:43 +00:00
|
|
|
lwline_serialize_buf(line, optr, retsize);
|
|
|
|
#ifdef DEBUG
|
2004-10-05 16:28:34 +00:00
|
|
|
elog(NOTICE, "lwgeom_force3dz_recursive: it's a line, size:%d", *retsize);
|
2004-08-25 13:41:43 +00:00
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( type == POLYGONTYPE )
|
|
|
|
{
|
|
|
|
poly = lwpoly_deserialize(serialized);
|
2004-10-05 16:28:34 +00:00
|
|
|
TYPE_SETZM(newpts.dims, 1, 0);
|
|
|
|
newpts.npoints = 0;
|
|
|
|
newpts.serialized_pointlist = lwalloc(1);
|
|
|
|
nrings = lwalloc(sizeof(POINTARRAY *)*poly->nrings);
|
|
|
|
loc = newpts.serialized_pointlist;
|
|
|
|
for (j=0; j<poly->nrings; j++)
|
2004-08-25 13:41:43 +00:00
|
|
|
{
|
2004-10-05 16:28:34 +00:00
|
|
|
POINTARRAY *ring = poly->rings[j];
|
|
|
|
POINTARRAY *nring = lwalloc(sizeof(POINTARRAY));
|
|
|
|
TYPE_SETZM(nring->dims, 1, 0);
|
|
|
|
nring->npoints = ring->npoints;
|
|
|
|
nring->serialized_pointlist =
|
|
|
|
lwalloc(ring->npoints*sizeof(POINT3DZ));
|
|
|
|
loc = nring->serialized_pointlist;
|
|
|
|
for (k=0; k<ring->npoints; k++)
|
2004-08-25 13:41:43 +00:00
|
|
|
{
|
2004-10-05 16:28:34 +00:00
|
|
|
getPoint3dz_p(ring, k, (POINT3DZ *)loc);
|
|
|
|
loc+=sizeof(POINT3DZ);
|
2004-08-25 13:41:43 +00:00
|
|
|
}
|
2004-10-05 16:28:34 +00:00
|
|
|
nrings[j] = nring;
|
2004-08-25 13:41:43 +00:00
|
|
|
}
|
2004-10-05 16:28:34 +00:00
|
|
|
poly->rings = nrings;
|
2004-10-04 13:53:42 +00:00
|
|
|
TYPE_SETZM(poly->type, 1, 0);
|
2004-08-25 13:41:43 +00:00
|
|
|
lwpoly_serialize_buf(poly, optr, retsize);
|
|
|
|
#ifdef DEBUG
|
2004-10-05 16:28:34 +00:00
|
|
|
elog(NOTICE, "lwgeom_force3dz_recursive: it's a poly, size:%d", *retsize);
|
2004-08-25 13:41:43 +00:00
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// OK, this is a collection, so we write down its metadata
|
|
|
|
// first and then call us again
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
2004-10-05 16:28:34 +00:00
|
|
|
elog(NOTICE, "lwgeom_force3dz_recursive: it's a collection (type:%d)", type);
|
2004-08-25 13:41:43 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// Add type
|
2004-10-05 16:28:34 +00:00
|
|
|
*optr = lwgeom_makeType_full(1, 0, lwgeom_hasSRID(serialized[0]),
|
2004-08-25 13:41:43 +00:00
|
|
|
type, lwgeom_hasBBOX(serialized[0]));
|
|
|
|
optr++;
|
|
|
|
totsize++;
|
|
|
|
loc=serialized+1;
|
|
|
|
|
|
|
|
// Add BBOX if any
|
|
|
|
if (lwgeom_hasBBOX(serialized[0]))
|
|
|
|
{
|
|
|
|
memcpy(optr, loc, sizeof(BOX2DFLOAT4));
|
|
|
|
optr += sizeof(BOX2DFLOAT4);
|
|
|
|
totsize += sizeof(BOX2DFLOAT4);
|
|
|
|
loc += sizeof(BOX2DFLOAT4);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add SRID if any
|
|
|
|
if (lwgeom_hasSRID(serialized[0]))
|
|
|
|
{
|
|
|
|
memcpy(optr, loc, 4);
|
|
|
|
optr += 4;
|
|
|
|
totsize += 4;
|
|
|
|
loc += 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add numsubobjects
|
|
|
|
memcpy(optr, loc, 4);
|
|
|
|
optr += 4;
|
|
|
|
totsize += 4;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, " collection header size:%d", totsize);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Now recurse for each suboject
|
|
|
|
inspected = lwgeom_inspect(serialized);
|
|
|
|
for (i=0; i<inspected->ngeometries; i++)
|
|
|
|
{
|
|
|
|
char *subgeom = lwgeom_getsubgeometry_inspected(inspected, i);
|
2004-10-05 16:28:34 +00:00
|
|
|
lwgeom_force3dz_recursive(subgeom, optr, &size);
|
2004-08-25 13:41:43 +00:00
|
|
|
totsize += size;
|
|
|
|
optr += size;
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, " elem %d size: %d (tot: %d)", i, size, totsize);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
pfree_inspected(inspected);
|
|
|
|
|
|
|
|
*retsize = totsize;
|
|
|
|
}
|
|
|
|
|
2004-09-20 17:03:41 +00:00
|
|
|
/*
|
2004-10-05 16:28:34 +00:00
|
|
|
* Write to already allocated memory 'optr' a 3dm version of
|
2004-09-20 17:03:41 +00:00
|
|
|
* the given serialized form.
|
2004-10-05 16:28:34 +00:00
|
|
|
* Higher dimensions in input geometry are discarder.
|
|
|
|
* If the given version is 2d M is set to 0.
|
2004-09-20 17:03:41 +00:00
|
|
|
* Return number bytes written in given int pointer.
|
|
|
|
*/
|
|
|
|
void
|
2004-10-05 21:08:38 +00:00
|
|
|
lwgeom_force3dm_recursive(unsigned char *serialized, char *optr, size_t *retsize)
|
2004-09-20 17:03:41 +00:00
|
|
|
{
|
|
|
|
LWGEOM_INSPECTED *inspected;
|
|
|
|
int i,j,k;
|
|
|
|
int totsize=0;
|
|
|
|
int size=0;
|
|
|
|
int type;
|
2004-10-05 21:08:38 +00:00
|
|
|
unsigned char newtypefl;
|
2004-09-20 17:03:41 +00:00
|
|
|
LWPOINT *point = NULL;
|
|
|
|
LWLINE *line = NULL;
|
|
|
|
LWPOLY *poly = NULL;
|
|
|
|
POINTARRAY newpts;
|
|
|
|
POINTARRAY **nrings;
|
2004-10-05 16:28:34 +00:00
|
|
|
POINT3DM *p3dm;
|
2004-09-20 17:03:41 +00:00
|
|
|
char *loc;
|
2004-10-05 16:28:34 +00:00
|
|
|
char check;
|
2004-09-20 17:03:41 +00:00
|
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
2004-10-05 16:28:34 +00:00
|
|
|
elog(NOTICE, "lwgeom_force3dm_recursive: call");
|
2004-09-20 17:03:41 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
type = lwgeom_getType(serialized[0]);
|
|
|
|
|
|
|
|
if ( type == POINTTYPE )
|
|
|
|
{
|
|
|
|
point = lwpoint_deserialize(serialized);
|
2004-10-05 16:28:34 +00:00
|
|
|
TYPE_SETZM(newpts.dims, 0, 1);
|
|
|
|
newpts.npoints = 1;
|
|
|
|
newpts.serialized_pointlist = lwalloc(sizeof(POINT3DM));
|
|
|
|
loc = newpts.serialized_pointlist;
|
|
|
|
p3dm = (POINT3DM *)loc;
|
|
|
|
getPoint3dm_p(point->point, 0, p3dm);
|
|
|
|
point->point = &newpts;
|
|
|
|
TYPE_SETZM(point->type, 0, 1);
|
|
|
|
lwpoint_serialize_buf(point, optr, retsize);
|
2004-10-05 21:08:38 +00:00
|
|
|
lwfree(newpts.serialized_pointlist);
|
|
|
|
lwfree(point);
|
2004-10-05 16:28:34 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
lwnotice("lwgeom_force3dm_recursive returning");
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( type == LINETYPE )
|
|
|
|
{
|
|
|
|
line = lwline_deserialize(serialized);
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, "lwgeom_force3dm_recursive: it's a line with %d points", line->points->npoints);
|
|
|
|
#endif
|
|
|
|
TYPE_SETZM(newpts.dims, 0, 1);
|
|
|
|
newpts.npoints = line->points->npoints;
|
|
|
|
newpts.serialized_pointlist = lwalloc(sizeof(POINT3DM)*line->points->npoints);
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, "lwgeom_force3dm_recursive: %d bytes pointlist allocated", sizeof(POINT3DM)*line->points->npoints);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
loc = newpts.serialized_pointlist;
|
|
|
|
check = TYPE_NDIMS(line->points->dims);
|
|
|
|
for (j=0; j<line->points->npoints; j++)
|
2004-09-20 17:03:41 +00:00
|
|
|
{
|
2004-10-05 16:28:34 +00:00
|
|
|
getPoint3dm_p(line->points, j, (POINT3DM *)loc);
|
|
|
|
if ( check != TYPE_NDIMS(line->points->dims) )
|
|
|
|
{
|
|
|
|
lwerror("getPoint3dm_p messed with input pointarray");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
loc+=sizeof(POINT3DM);
|
2004-09-20 17:03:41 +00:00
|
|
|
}
|
2004-10-05 16:28:34 +00:00
|
|
|
line->points = &newpts;
|
|
|
|
TYPE_SETZM(line->type, 0, 1);
|
|
|
|
lwline_serialize_buf(line, optr, retsize);
|
2004-10-05 21:08:38 +00:00
|
|
|
lwfree(newpts.serialized_pointlist);
|
|
|
|
lwfree(line);
|
2004-10-05 16:28:34 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
lwnotice("lwgeom_force3dm_recursive returning");
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( type == POLYGONTYPE )
|
|
|
|
{
|
|
|
|
poly = lwpoly_deserialize(serialized);
|
|
|
|
TYPE_SETZM(newpts.dims, 0, 1);
|
|
|
|
newpts.npoints = 0;
|
|
|
|
newpts.serialized_pointlist = lwalloc(1);
|
|
|
|
nrings = lwalloc(sizeof(POINTARRAY *)*poly->nrings);
|
|
|
|
loc = newpts.serialized_pointlist;
|
|
|
|
for (j=0; j<poly->nrings; j++)
|
|
|
|
{
|
|
|
|
POINTARRAY *ring = poly->rings[j];
|
|
|
|
POINTARRAY *nring = lwalloc(sizeof(POINTARRAY));
|
|
|
|
TYPE_SETZM(nring->dims, 0, 1);
|
|
|
|
nring->npoints = ring->npoints;
|
|
|
|
nring->serialized_pointlist =
|
|
|
|
lwalloc(ring->npoints*sizeof(POINT3DM));
|
|
|
|
loc = nring->serialized_pointlist;
|
|
|
|
for (k=0; k<ring->npoints; k++)
|
|
|
|
{
|
|
|
|
getPoint3dm_p(ring, k, (POINT3DM *)loc);
|
|
|
|
loc+=sizeof(POINT3DM);
|
|
|
|
}
|
|
|
|
nrings[j] = nring;
|
|
|
|
}
|
|
|
|
poly->rings = nrings;
|
|
|
|
TYPE_SETZM(poly->type, 0, 1);
|
|
|
|
lwpoly_serialize_buf(poly, optr, retsize);
|
2004-10-05 21:08:38 +00:00
|
|
|
lwfree(poly);
|
|
|
|
// TODO: free nrigs[*]->serialized_pointlist
|
2004-10-05 16:28:34 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
lwnotice("lwgeom_force3dm_recursive returning");
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( type != MULTIPOINTTYPE && type != MULTIPOLYGONTYPE &&
|
|
|
|
type != MULTILINETYPE && type != COLLECTIONTYPE )
|
|
|
|
{
|
|
|
|
lwerror("lwgeom_force3dm_recursive: unknown geometry: %d",
|
|
|
|
type);
|
|
|
|
}
|
|
|
|
|
|
|
|
// OK, this is a collection, so we write down its metadata
|
|
|
|
// first and then call us again
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
lwnotice("lwgeom_force3dm_recursive: it's a collection (%s)", lwgeom_typename(type));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
// Add type
|
2004-10-05 21:08:38 +00:00
|
|
|
newtypefl = lwgeom_makeType_full(0, 1, lwgeom_hasSRID(serialized[0]),
|
2004-10-05 16:28:34 +00:00
|
|
|
type, lwgeom_hasBBOX(serialized[0]));
|
2004-10-05 21:08:38 +00:00
|
|
|
optr[0] = newtypefl;
|
2004-10-05 16:28:34 +00:00
|
|
|
optr++;
|
|
|
|
totsize++;
|
|
|
|
loc=serialized+1;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
2004-10-05 21:08:38 +00:00
|
|
|
lwnotice("lwgeom_force3dm_recursive: added collection type (%s[%s]) - size:%d", lwgeom_typename(type), lwgeom_typeflags(newtypefl), totsize);
|
2004-10-05 16:28:34 +00:00
|
|
|
#endif
|
|
|
|
|
2004-10-05 21:08:38 +00:00
|
|
|
if ( lwgeom_hasBBOX(serialized[0]) != lwgeom_hasBBOX(newtypefl) )
|
|
|
|
lwerror("typeflag mismatch in BBOX");
|
|
|
|
if ( lwgeom_hasSRID(serialized[0]) != lwgeom_hasSRID(newtypefl) )
|
|
|
|
lwerror("typeflag mismatch in SRID");
|
|
|
|
|
2004-10-05 16:28:34 +00:00
|
|
|
// Add BBOX if any
|
|
|
|
if (lwgeom_hasBBOX(serialized[0]))
|
|
|
|
{
|
|
|
|
memcpy(optr, loc, sizeof(BOX2DFLOAT4));
|
|
|
|
optr += sizeof(BOX2DFLOAT4);
|
|
|
|
totsize += sizeof(BOX2DFLOAT4);
|
|
|
|
loc += sizeof(BOX2DFLOAT4);
|
|
|
|
#ifdef DEBUG
|
|
|
|
lwnotice("lwgeom_force3dm_recursive: added collection bbox - size:%d", totsize);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add SRID if any
|
|
|
|
if (lwgeom_hasSRID(serialized[0]))
|
|
|
|
{
|
|
|
|
memcpy(optr, loc, 4);
|
|
|
|
optr += 4;
|
|
|
|
totsize += 4;
|
|
|
|
loc += 4;
|
|
|
|
#ifdef DEBUG
|
|
|
|
lwnotice("lwgeom_force3dm_recursive: added collection SRID - size:%d", totsize);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add numsubobjects
|
|
|
|
memcpy(optr, loc, sizeof(uint32));
|
|
|
|
optr += sizeof(uint32);
|
|
|
|
totsize += sizeof(uint32);
|
|
|
|
loc += sizeof(uint32);
|
|
|
|
#ifdef DEBUG
|
|
|
|
lwnotice("lwgeom_force3dm_recursive: added collection ngeoms - size:%d", totsize);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
lwnotice("lwgeom_force3dm_recursive: inspecting subgeoms");
|
|
|
|
#endif
|
2004-10-05 21:08:38 +00:00
|
|
|
// Now recurse for each subobject
|
2004-10-05 16:28:34 +00:00
|
|
|
inspected = lwgeom_inspect(serialized);
|
|
|
|
for (i=0; i<inspected->ngeometries; i++)
|
|
|
|
{
|
|
|
|
char *subgeom = lwgeom_getsubgeometry_inspected(inspected, i);
|
|
|
|
lwgeom_force3dm_recursive(subgeom, optr, &size);
|
|
|
|
totsize += size;
|
|
|
|
optr += size;
|
|
|
|
#ifdef DEBUG
|
|
|
|
lwnotice("lwgeom_force3dm_recursive: added elem %d size: %d (tot: %d)",
|
|
|
|
i, size, totsize);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
pfree_inspected(inspected);
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
lwnotice("lwgeom_force3dm_recursive returning");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if ( retsize ) *retsize = totsize;
|
|
|
|
}
|
|
|
|
|
2004-10-05 21:08:38 +00:00
|
|
|
|
2004-10-05 16:28:34 +00:00
|
|
|
/*
|
|
|
|
* Write to already allocated memory 'optr' a 4d version of
|
|
|
|
* the given serialized form.
|
|
|
|
* Pad dimensions are set to 0 (this might be z, m or both).
|
|
|
|
* Return number bytes written in given int pointer.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
lwgeom_force4d_recursive(char *serialized, char *optr, size_t *retsize)
|
|
|
|
{
|
|
|
|
LWGEOM_INSPECTED *inspected;
|
|
|
|
int i,j,k;
|
|
|
|
int totsize=0;
|
|
|
|
int size=0;
|
|
|
|
int type;
|
|
|
|
LWPOINT *point = NULL;
|
|
|
|
LWLINE *line = NULL;
|
|
|
|
LWPOLY *poly = NULL;
|
|
|
|
POINTARRAY newpts;
|
|
|
|
POINTARRAY **nrings;
|
|
|
|
char *loc;
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, "lwgeom_force4d_recursive: call");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
type = lwgeom_getType(serialized[0]);
|
|
|
|
|
|
|
|
if ( type == POINTTYPE )
|
|
|
|
{
|
|
|
|
point = lwpoint_deserialize(serialized);
|
|
|
|
TYPE_SETZM(newpts.dims, 1, 1);
|
|
|
|
newpts.npoints = 1;
|
|
|
|
newpts.serialized_pointlist = lwalloc(sizeof(POINT4D));
|
|
|
|
loc = newpts.serialized_pointlist;
|
|
|
|
getPoint4d_p(point->point, 0, (POINT4D *)loc);
|
|
|
|
point->point = &newpts;
|
2004-10-04 13:53:42 +00:00
|
|
|
TYPE_SETZM(point->type, 1, 1);
|
2004-09-20 17:03:41 +00:00
|
|
|
lwpoint_serialize_buf(point, optr, retsize);
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, "lwgeom_force4d_recursive: it's a point, size:%d", *retsize);
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( type == LINETYPE )
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, "lwgeom_force4d_recursive: it's a line");
|
|
|
|
#endif
|
|
|
|
line = lwline_deserialize(serialized);
|
2004-10-05 16:28:34 +00:00
|
|
|
TYPE_SETZM(newpts.dims, 1, 1);
|
|
|
|
newpts.npoints = line->points->npoints;
|
|
|
|
newpts.serialized_pointlist = lwalloc(sizeof(POINT4D)*line->points->npoints);
|
|
|
|
loc = newpts.serialized_pointlist;
|
|
|
|
for (j=0; j<line->points->npoints; j++)
|
2004-09-20 17:03:41 +00:00
|
|
|
{
|
2004-10-05 16:28:34 +00:00
|
|
|
getPoint4d_p(line->points, j, (POINT4D *)loc);
|
|
|
|
loc+=sizeof(POINT4D);
|
2004-09-20 17:03:41 +00:00
|
|
|
}
|
2004-10-05 16:28:34 +00:00
|
|
|
line->points = &newpts;
|
2004-10-04 13:53:42 +00:00
|
|
|
TYPE_SETZM(line->type, 1, 1);
|
2004-09-20 17:03:41 +00:00
|
|
|
lwline_serialize_buf(line, optr, retsize);
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, "lwgeom_force4d_recursive: it's a line, size:%d", *retsize);
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( type == POLYGONTYPE )
|
|
|
|
{
|
|
|
|
poly = lwpoly_deserialize(serialized);
|
2004-10-05 16:28:34 +00:00
|
|
|
TYPE_SETZM(newpts.dims, 1, 1);
|
|
|
|
newpts.npoints = 0;
|
|
|
|
newpts.serialized_pointlist = lwalloc(1);
|
|
|
|
nrings = lwalloc(sizeof(POINTARRAY *)*poly->nrings);
|
|
|
|
loc = newpts.serialized_pointlist;
|
|
|
|
for (j=0; j<poly->nrings; j++)
|
2004-09-20 17:03:41 +00:00
|
|
|
{
|
2004-10-05 16:28:34 +00:00
|
|
|
POINTARRAY *ring = poly->rings[j];
|
|
|
|
POINTARRAY *nring = lwalloc(sizeof(POINTARRAY));
|
|
|
|
TYPE_SETZM(nring->dims, 1, 1);
|
|
|
|
nring->npoints = ring->npoints;
|
|
|
|
nring->serialized_pointlist =
|
|
|
|
lwalloc(ring->npoints*sizeof(POINT4D));
|
|
|
|
loc = nring->serialized_pointlist;
|
|
|
|
for (k=0; k<ring->npoints; k++)
|
2004-09-20 17:03:41 +00:00
|
|
|
{
|
2004-10-05 16:28:34 +00:00
|
|
|
getPoint4d_p(ring, k, (POINT4D *)loc);
|
|
|
|
loc+=sizeof(POINT4D);
|
2004-09-20 17:03:41 +00:00
|
|
|
}
|
2004-10-05 16:28:34 +00:00
|
|
|
nrings[j] = nring;
|
2004-09-20 17:03:41 +00:00
|
|
|
}
|
2004-10-05 16:28:34 +00:00
|
|
|
poly->rings = nrings;
|
2004-10-04 13:53:42 +00:00
|
|
|
TYPE_SETZM(poly->type, 1, 1);
|
2004-09-20 17:03:41 +00:00
|
|
|
lwpoly_serialize_buf(poly, optr, retsize);
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, "lwgeom_force4d_recursive: it's a poly, size:%d", *retsize);
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// OK, this is a collection, so we write down its metadata
|
|
|
|
// first and then call us again
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, "lwgeom_force4d_recursive: it's a collection (type:%d)", type);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Add type
|
2004-10-05 16:28:34 +00:00
|
|
|
*optr = lwgeom_makeType_full(
|
|
|
|
1, 1,
|
|
|
|
lwgeom_hasSRID(serialized[0]),
|
2004-09-20 17:03:41 +00:00
|
|
|
type, lwgeom_hasBBOX(serialized[0]));
|
|
|
|
optr++;
|
|
|
|
totsize++;
|
|
|
|
loc=serialized+1;
|
|
|
|
|
|
|
|
// Add BBOX if any
|
|
|
|
if (lwgeom_hasBBOX(serialized[0]))
|
|
|
|
{
|
|
|
|
memcpy(optr, loc, sizeof(BOX2DFLOAT4));
|
|
|
|
optr += sizeof(BOX2DFLOAT4);
|
|
|
|
totsize += sizeof(BOX2DFLOAT4);
|
|
|
|
loc += sizeof(BOX2DFLOAT4);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add SRID if any
|
|
|
|
if (lwgeom_hasSRID(serialized[0]))
|
|
|
|
{
|
|
|
|
memcpy(optr, loc, 4);
|
|
|
|
optr += 4;
|
|
|
|
totsize += 4;
|
|
|
|
loc += 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add numsubobjects
|
|
|
|
memcpy(optr, loc, 4);
|
|
|
|
optr += 4;
|
|
|
|
totsize += 4;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, " collection header size:%d", totsize);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Now recurse for each suboject
|
|
|
|
inspected = lwgeom_inspect(serialized);
|
|
|
|
for (i=0; i<inspected->ngeometries; i++)
|
|
|
|
{
|
|
|
|
char *subgeom = lwgeom_getsubgeometry_inspected(inspected, i);
|
|
|
|
lwgeom_force4d_recursive(subgeom, optr, &size);
|
|
|
|
totsize += size;
|
|
|
|
optr += size;
|
|
|
|
#ifdef DEBUG
|
|
|
|
elog(NOTICE, " elem %d size: %d (tot: %d)", i, size, totsize);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
pfree_inspected(inspected);
|
|
|
|
|
|
|
|
*retsize = totsize;
|
|
|
|
}
|
|
|
|
|
2004-08-25 12:32:12 +00:00
|
|
|
// transform input geometry to 2d if not 2d already
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_force_2d);
|
|
|
|
Datum LWGEOM_force_2d(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
|
|
|
PG_LWGEOM *result;
|
2004-08-25 12:32:12 +00:00
|
|
|
int32 size = 0;
|
|
|
|
|
|
|
|
// already 2d
|
|
|
|
if ( lwgeom_ndims(geom->type) == 2 ) PG_RETURN_POINTER(geom);
|
|
|
|
|
|
|
|
// allocate a larger for safety and simplicity
|
2004-09-29 15:25:21 +00:00
|
|
|
result = (PG_LWGEOM *) lwalloc(geom->size);
|
2004-08-25 12:32:12 +00:00
|
|
|
|
|
|
|
lwgeom_force2d_recursive(SERIALIZED_FORM(geom),
|
|
|
|
SERIALIZED_FORM(result), &size);
|
|
|
|
|
|
|
|
// we can safely avoid this... memory will be freed at
|
|
|
|
// end of query processing anyway.
|
2004-09-29 15:25:21 +00:00
|
|
|
//result = lwrealloc(result, size+4);
|
2004-08-25 12:32:12 +00:00
|
|
|
|
|
|
|
result->size = size+4;
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(result);
|
2004-08-25 07:29:32 +00:00
|
|
|
}
|
2004-08-25 13:41:43 +00:00
|
|
|
|
2004-10-05 16:28:34 +00:00
|
|
|
// transform input geometry to 3dz if not 3dz already
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_force_3dz);
|
|
|
|
Datum LWGEOM_force_3dz(PG_FUNCTION_ARGS)
|
2004-08-25 13:41:43 +00:00
|
|
|
{
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
|
|
|
PG_LWGEOM *result;
|
2004-08-25 13:41:43 +00:00
|
|
|
int olddims;
|
|
|
|
int32 size = 0;
|
|
|
|
|
|
|
|
olddims = lwgeom_ndims(geom->type);
|
|
|
|
|
|
|
|
// already 3d
|
2004-10-05 16:28:34 +00:00
|
|
|
if ( olddims == 3 && TYPE_HASZ(geom->type) ) PG_RETURN_POINTER(geom);
|
2004-08-25 13:41:43 +00:00
|
|
|
|
|
|
|
if ( olddims > 3 ) {
|
2004-09-29 15:25:21 +00:00
|
|
|
result = (PG_LWGEOM *) lwalloc(geom->size);
|
2004-08-25 13:41:43 +00:00
|
|
|
} else {
|
|
|
|
// allocate double as memory a larger for safety
|
2004-09-29 15:25:21 +00:00
|
|
|
result = (PG_LWGEOM *) lwalloc(geom->size*1.5);
|
2004-08-25 13:41:43 +00:00
|
|
|
}
|
|
|
|
|
2004-10-05 16:28:34 +00:00
|
|
|
lwgeom_force3dz_recursive(SERIALIZED_FORM(geom),
|
|
|
|
SERIALIZED_FORM(result), &size);
|
|
|
|
|
|
|
|
// we can safely avoid this... memory will be freed at
|
|
|
|
// end of query processing anyway.
|
|
|
|
//result = lwrealloc(result, size+4);
|
|
|
|
|
|
|
|
result->size = size+4;
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
// transform input geometry to 3dm if not 3dm already
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_force_3dm);
|
|
|
|
Datum LWGEOM_force_3dm(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0));
|
|
|
|
PG_LWGEOM *result;
|
|
|
|
int olddims;
|
2004-10-05 21:08:38 +00:00
|
|
|
size_t size = 0;
|
2004-10-05 16:28:34 +00:00
|
|
|
|
|
|
|
olddims = lwgeom_ndims(geom->type);
|
|
|
|
|
|
|
|
// already 3dm
|
|
|
|
if ( olddims == 3 && TYPE_HASM(geom->type) ) PG_RETURN_POINTER(geom);
|
|
|
|
|
|
|
|
if ( olddims > 3 ) {
|
2004-10-05 21:08:38 +00:00
|
|
|
size = geom->size;
|
2004-10-05 16:28:34 +00:00
|
|
|
} else {
|
|
|
|
// allocate double as memory a larger for safety
|
2004-10-05 21:08:38 +00:00
|
|
|
size = geom->size * 1.5;
|
2004-10-05 16:28:34 +00:00
|
|
|
}
|
2004-10-05 21:08:38 +00:00
|
|
|
result = (PG_LWGEOM *)lwalloc(size);
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
lwnotice("LWGEOM_force_3dm: allocated %d bytes for result", size);
|
|
|
|
#endif
|
2004-10-05 16:28:34 +00:00
|
|
|
|
|
|
|
lwgeom_force3dm_recursive(SERIALIZED_FORM(geom),
|
2004-08-25 13:41:43 +00:00
|
|
|
SERIALIZED_FORM(result), &size);
|
|
|
|
|
2004-10-05 17:15:42 +00:00
|
|
|
#ifdef DEBUG
|
2004-10-05 21:08:38 +00:00
|
|
|
lwnotice("LWGEOM_force_3dm: lwgeom_force3dm_recursive returned a %d sized geom", size);
|
2004-10-05 17:15:42 +00:00
|
|
|
#endif
|
|
|
|
|
2004-08-25 13:41:43 +00:00
|
|
|
// we can safely avoid this... memory will be freed at
|
|
|
|
// end of query processing anyway.
|
2004-09-29 15:25:21 +00:00
|
|
|
//result = lwrealloc(result, size+4);
|
2004-08-25 13:41:43 +00:00
|
|
|
|
|
|
|
result->size = size+4;
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(result);
|
|
|
|
}
|
2004-08-25 15:28:46 +00:00
|
|
|
|
2004-09-20 17:03:41 +00:00
|
|
|
// transform input geometry to 4d if not 4d already
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_force_4d);
|
|
|
|
Datum LWGEOM_force_4d(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
|
|
|
PG_LWGEOM *result;
|
2004-09-20 17:03:41 +00:00
|
|
|
int olddims;
|
|
|
|
int32 size = 0;
|
|
|
|
|
|
|
|
olddims = lwgeom_ndims(geom->type);
|
|
|
|
|
|
|
|
// already 4d
|
|
|
|
if ( olddims == 4 ) PG_RETURN_POINTER(geom);
|
|
|
|
|
|
|
|
// allocate double as memory a larger for safety
|
2004-09-29 15:25:21 +00:00
|
|
|
result = (PG_LWGEOM *) lwalloc(geom->size*2);
|
2004-09-20 17:03:41 +00:00
|
|
|
|
|
|
|
lwgeom_force4d_recursive(SERIALIZED_FORM(geom),
|
|
|
|
SERIALIZED_FORM(result), &size);
|
|
|
|
|
|
|
|
// we can safely avoid this... memory will be freed at
|
|
|
|
// end of query processing anyway.
|
2004-09-29 15:25:21 +00:00
|
|
|
//result = lwrealloc(result, size+4);
|
2004-09-20 17:03:41 +00:00
|
|
|
|
|
|
|
result->size = size+4;
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(result);
|
|
|
|
}
|
|
|
|
|
2004-08-25 15:28:46 +00:00
|
|
|
// transform input geometry to a collection type
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_force_collection);
|
|
|
|
Datum LWGEOM_force_collection(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
|
|
|
PG_LWGEOM *result;
|
2004-08-25 15:28:46 +00:00
|
|
|
int oldtype;
|
|
|
|
int32 size = 0;
|
|
|
|
char *iptr, *optr;
|
|
|
|
int32 nsubgeoms = 1;
|
|
|
|
|
|
|
|
oldtype = lwgeom_getType(geom->type);
|
|
|
|
|
|
|
|
// already a collection
|
|
|
|
if ( oldtype == COLLECTIONTYPE ) PG_RETURN_POINTER(geom);
|
|
|
|
|
|
|
|
// alread a multi*, just make it a collection
|
|
|
|
if ( oldtype > 3 )
|
|
|
|
{
|
2004-09-29 15:25:21 +00:00
|
|
|
result = (PG_LWGEOM *)lwalloc(geom->size);
|
2004-08-25 15:28:46 +00:00
|
|
|
result->size = geom->size;
|
2004-10-07 20:39:30 +00:00
|
|
|
result->type = geom->type;
|
|
|
|
TYPE_SETTYPE(result->type, COLLECTIONTYPE);
|
2004-08-25 15:28:46 +00:00
|
|
|
memcpy(result->data, geom->data, geom->size-5);
|
|
|
|
PG_RETURN_POINTER(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
// not a multi*, must add header and
|
|
|
|
// transfer eventual BBOX and SRID to first object
|
|
|
|
|
|
|
|
size = geom->size+5; // 4 for numgeoms, 1 for type
|
|
|
|
|
2004-09-29 15:25:21 +00:00
|
|
|
result = (PG_LWGEOM *)lwalloc(size); // 4 for numgeoms, 1 for type
|
2004-08-25 15:28:46 +00:00
|
|
|
result->size = size;
|
|
|
|
|
2004-10-07 20:39:30 +00:00
|
|
|
result->type = geom->type;
|
|
|
|
TYPE_SETTYPE(result->type, COLLECTIONTYPE);
|
2004-08-25 15:28:46 +00:00
|
|
|
iptr = geom->data;
|
|
|
|
optr = result->data;
|
|
|
|
|
|
|
|
// reset size to bare serialized input
|
|
|
|
size = geom->size - 4;
|
|
|
|
|
|
|
|
// transfer bbox
|
|
|
|
if ( lwgeom_hasBBOX(geom->type) )
|
|
|
|
{
|
|
|
|
memcpy(optr, iptr, sizeof(BOX2DFLOAT4));
|
|
|
|
optr += sizeof(BOX2DFLOAT4);
|
|
|
|
iptr += sizeof(BOX2DFLOAT4);
|
|
|
|
size -= sizeof(BOX2DFLOAT4);
|
|
|
|
}
|
|
|
|
|
|
|
|
// transfer SRID
|
|
|
|
if ( lwgeom_hasSRID(geom->type) )
|
2004-08-26 16:44:01 +00:00
|
|
|
{
|
|
|
|
memcpy(optr, iptr, 4);
|
|
|
|
optr += 4;
|
|
|
|
iptr += 4;
|
|
|
|
size -= 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
// write number of geometries (1)
|
|
|
|
memcpy(optr, &nsubgeoms, 4);
|
|
|
|
optr+=4;
|
|
|
|
|
|
|
|
// write type of first geometry w/out BBOX and SRID
|
2004-10-07 20:39:30 +00:00
|
|
|
optr[0] = geom->type;
|
|
|
|
TYPE_SETHASSRID(optr[0], 0);
|
|
|
|
TYPE_SETHASBBOX(optr[0], 0);
|
2004-08-26 16:44:01 +00:00
|
|
|
optr++;
|
|
|
|
|
|
|
|
// write remaining stuff
|
|
|
|
memcpy(optr, iptr, size);
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
// transform input geometry to a multi* type
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_force_multi);
|
|
|
|
Datum LWGEOM_force_multi(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
|
|
|
PG_LWGEOM *result;
|
2004-08-26 16:44:01 +00:00
|
|
|
int oldtype, newtype;
|
|
|
|
int32 size = 0;
|
|
|
|
char *iptr, *optr;
|
|
|
|
int32 nsubgeoms = 1;
|
|
|
|
|
|
|
|
oldtype = lwgeom_getType(geom->type);
|
|
|
|
|
|
|
|
// already a multi
|
|
|
|
if ( oldtype >= 4 ) PG_RETURN_POINTER(geom);
|
|
|
|
|
|
|
|
// not a multi*, must add header and
|
|
|
|
// transfer eventual BBOX and SRID to first object
|
|
|
|
|
|
|
|
newtype = oldtype+3; // see defines
|
|
|
|
|
|
|
|
size = geom->size+5; // 4 for numgeoms, 1 for type
|
|
|
|
|
2004-09-29 15:25:21 +00:00
|
|
|
result = (PG_LWGEOM *)lwalloc(size); // 4 for numgeoms, 1 for type
|
2004-08-26 16:44:01 +00:00
|
|
|
result->size = size;
|
|
|
|
|
2004-10-07 20:39:30 +00:00
|
|
|
result->type = geom->type;
|
|
|
|
TYPE_SETTYPE(result->type, newtype);
|
2004-08-26 16:44:01 +00:00
|
|
|
iptr = geom->data;
|
|
|
|
optr = result->data;
|
|
|
|
|
|
|
|
// reset size to bare serialized input
|
|
|
|
size = geom->size - 4;
|
|
|
|
|
|
|
|
// transfer bbox
|
|
|
|
if ( lwgeom_hasBBOX(geom->type) )
|
|
|
|
{
|
|
|
|
memcpy(optr, iptr, sizeof(BOX2DFLOAT4));
|
|
|
|
optr += sizeof(BOX2DFLOAT4);
|
|
|
|
iptr += sizeof(BOX2DFLOAT4);
|
|
|
|
size -= sizeof(BOX2DFLOAT4);
|
|
|
|
}
|
|
|
|
|
|
|
|
// transfer SRID
|
|
|
|
if ( lwgeom_hasSRID(geom->type) )
|
2004-08-25 15:28:46 +00:00
|
|
|
{
|
|
|
|
memcpy(optr, iptr, 4);
|
|
|
|
optr += 4;
|
|
|
|
iptr += 4;
|
|
|
|
size -= 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
// write number of geometries (1)
|
|
|
|
memcpy(optr, &nsubgeoms, 4);
|
|
|
|
optr+=4;
|
|
|
|
|
|
|
|
// write type of first geometry w/out BBOX and SRID
|
2004-10-07 20:39:30 +00:00
|
|
|
optr[0] = geom->type;
|
|
|
|
TYPE_SETHASSRID(optr[0], 0);
|
|
|
|
TYPE_SETHASBBOX(optr[0], 0);
|
2004-08-25 15:28:46 +00:00
|
|
|
optr++;
|
|
|
|
|
|
|
|
// write remaining stuff
|
|
|
|
memcpy(optr, iptr, size);
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(result);
|
|
|
|
}
|
2004-08-26 12:55:30 +00:00
|
|
|
|
|
|
|
// Minimum 2d distance between objects in geom1 and geom2.
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_mindistance2d);
|
|
|
|
Datum LWGEOM_mindistance2d(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom1;
|
|
|
|
PG_LWGEOM *geom2;
|
2004-08-26 12:55:30 +00:00
|
|
|
double mindist;
|
|
|
|
|
2004-09-22 11:42:45 +00:00
|
|
|
#ifdef PROFILE
|
|
|
|
profstart(PROF_QRUN);
|
|
|
|
#endif
|
|
|
|
|
2004-09-29 06:31:42 +00:00
|
|
|
geom1 = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
|
|
|
geom2 = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
2004-09-22 11:42:45 +00:00
|
|
|
|
2004-08-26 12:55:30 +00:00
|
|
|
if (lwgeom_getSRID(geom1) != lwgeom_getSRID(geom2))
|
|
|
|
{
|
|
|
|
elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n");
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
|
|
|
mindist = lwgeom_mindistance2d_recursive(SERIALIZED_FORM(geom1),
|
|
|
|
SERIALIZED_FORM(geom2));
|
|
|
|
|
2004-09-22 11:42:45 +00:00
|
|
|
#ifdef PROFILE
|
|
|
|
profstop(PROF_QRUN);
|
2004-09-22 13:45:11 +00:00
|
|
|
profreport("dist",geom1, geom2, NULL);
|
2004-09-22 11:42:45 +00:00
|
|
|
#endif
|
|
|
|
|
2004-08-26 12:55:30 +00:00
|
|
|
PG_RETURN_FLOAT8(mindist);
|
|
|
|
}
|
|
|
|
|
2004-08-26 15:02:59 +00:00
|
|
|
// Maximum 2d distance between linestrings.
|
|
|
|
// Returns NULL if given geoms are not linestrings.
|
|
|
|
// This is very bogus (or I'm missing its meaning)
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_maxdistance2d_linestring);
|
|
|
|
Datum LWGEOM_maxdistance2d_linestring(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom1;
|
|
|
|
PG_LWGEOM *geom2;
|
2004-08-26 15:02:59 +00:00
|
|
|
LWLINE *line1;
|
|
|
|
LWLINE *line2;
|
|
|
|
double maxdist = 0;
|
|
|
|
int i;
|
|
|
|
|
2004-08-26 16:55:09 +00:00
|
|
|
elog(ERROR, "This function is unimplemented yet");
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
2004-09-29 06:31:42 +00:00
|
|
|
geom1 = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
2004-08-26 15:02:59 +00:00
|
|
|
line1 = lwline_deserialize(SERIALIZED_FORM(geom1));
|
|
|
|
if ( line1 == NULL ) PG_RETURN_NULL(); // not a linestring
|
|
|
|
|
2004-09-29 06:31:42 +00:00
|
|
|
geom2 = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
2004-08-26 15:02:59 +00:00
|
|
|
line2 = lwline_deserialize(SERIALIZED_FORM(geom2));
|
|
|
|
if ( line2 == NULL ) PG_RETURN_NULL(); // not a linestring
|
|
|
|
|
|
|
|
if (lwgeom_getSRID(geom1) != lwgeom_getSRID(geom2))
|
|
|
|
{
|
|
|
|
elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n");
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<line1->points->npoints; i++)
|
|
|
|
{
|
|
|
|
POINT2D *p = (POINT2D *)getPoint(line1->points, i);
|
|
|
|
double dist = distance2d_pt_ptarray(p, line2->points);
|
|
|
|
|
|
|
|
if (dist > maxdist) maxdist = dist;
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_FLOAT8(maxdist);
|
|
|
|
}
|
|
|
|
|
2004-08-27 08:13:16 +00:00
|
|
|
//translate geometry
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_translate);
|
|
|
|
Datum LWGEOM_translate(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0));
|
2004-08-27 08:13:16 +00:00
|
|
|
double xoff = PG_GETARG_FLOAT8(1);
|
|
|
|
double yoff = PG_GETARG_FLOAT8(2);
|
|
|
|
double zoff = PG_GETARG_FLOAT8(3);
|
|
|
|
|
|
|
|
lwgeom_translate_recursive(SERIALIZED_FORM(geom), xoff, yoff, zoff);
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(geom);
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_inside_circle_point);
|
|
|
|
Datum LWGEOM_inside_circle_point(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom;
|
2004-08-27 08:13:16 +00:00
|
|
|
double cx = PG_GETARG_FLOAT8(1);
|
|
|
|
double cy = PG_GETARG_FLOAT8(2);
|
|
|
|
double rr = PG_GETARG_FLOAT8(3);
|
|
|
|
LWPOINT *point;
|
|
|
|
POINT2D *pt;
|
|
|
|
|
2004-09-29 06:31:42 +00:00
|
|
|
geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
2004-08-27 08:13:16 +00:00
|
|
|
point = lwpoint_deserialize(SERIALIZED_FORM(geom));
|
|
|
|
if ( point == NULL ) PG_RETURN_NULL(); // not a point
|
|
|
|
|
|
|
|
pt = (POINT2D *)getPoint(point->point, 0);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(lwgeom_pt_inside_circle(pt, cx, cy, rr));
|
|
|
|
}
|
2004-08-27 14:35:26 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
dump_lwexploded(LWGEOM_EXPLODED *exploded)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2004-10-05 16:28:34 +00:00
|
|
|
elog(NOTICE, "SRID=%d ndims=%d", exploded->SRID,
|
|
|
|
TYPE_NDIMS(exploded->dims));
|
2004-08-27 14:35:26 +00:00
|
|
|
elog(NOTICE, "%d points, %d lines, %d polygons",
|
|
|
|
exploded->npoints, exploded->nlines, exploded->npolys);
|
|
|
|
|
|
|
|
for (i=0; i<exploded->npoints; i++)
|
|
|
|
{
|
|
|
|
elog(NOTICE, "Point%d @ %p", i, exploded->points[i]);
|
2004-08-27 15:03:11 +00:00
|
|
|
if ( (int)exploded->points[i] < 100 )
|
|
|
|
{
|
|
|
|
elog(ERROR, "dirty point pointer");
|
|
|
|
}
|
2004-08-27 14:35:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<exploded->nlines; i++)
|
|
|
|
{
|
|
|
|
elog(NOTICE, "Line%d @ %p", i, exploded->lines[i]);
|
2004-08-27 15:03:11 +00:00
|
|
|
if ( (int)exploded->lines[i] < 100 )
|
|
|
|
{
|
|
|
|
elog(ERROR, "dirty line pointer");
|
|
|
|
}
|
2004-08-27 14:35:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<exploded->npolys; i++)
|
|
|
|
{
|
|
|
|
elog(NOTICE, "Poly%d @ %p", i, exploded->polys[i]);
|
2004-08-27 15:03:11 +00:00
|
|
|
if ( (int)exploded->polys[i] < 100 )
|
|
|
|
{
|
|
|
|
elog(ERROR, "dirty poly pointer");
|
|
|
|
}
|
2004-08-27 14:35:26 +00:00
|
|
|
}
|
2004-08-27 15:03:11 +00:00
|
|
|
|
2004-08-27 14:35:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// collect( geom, geom ) returns a geometry which contains
|
|
|
|
// all the sub_objects from both of the argument geometries
|
|
|
|
// returned geometry is the simplest possible, based on the types
|
2004-09-06 16:04:13 +00:00
|
|
|
// of the collected objects
|
2004-08-27 14:35:26 +00:00
|
|
|
// ie. if all are of either X or multiX, then a multiX is returned.
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_collect);
|
|
|
|
Datum LWGEOM_collect(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-10-11 09:55:27 +00:00
|
|
|
elog(ERROR, "memcollect() is obsoleted, use collect() instead");
|
|
|
|
PG_RETURN_NULL();
|
2004-08-27 14:35:26 +00:00
|
|
|
}
|
2004-08-27 16:01:48 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* This is a geometry array constructor
|
|
|
|
* for use as aggregates sfunc.
|
|
|
|
* Will have as input an array of Geometry pointers and a Geometry.
|
|
|
|
* Will DETOAST given geometry and put a pointer to it
|
|
|
|
* in the given array. DETOASTED value is first copied
|
|
|
|
* to a safe memory context to avoid premature deletion.
|
|
|
|
*/
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_accum);
|
|
|
|
Datum LWGEOM_accum(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-09-30 16:06:05 +00:00
|
|
|
ArrayType *array = NULL;
|
2004-08-27 16:01:48 +00:00
|
|
|
int nelems, nbytes;
|
|
|
|
Datum datum;
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom;
|
2004-08-27 16:01:48 +00:00
|
|
|
ArrayType *result;
|
|
|
|
Pointer **pointers;
|
|
|
|
MemoryContext oldcontext;
|
|
|
|
|
|
|
|
//elog(NOTICE, "LWGEOM_accum called");
|
|
|
|
|
|
|
|
datum = PG_GETARG_DATUM(0);
|
|
|
|
if ( (Pointer *)datum == NULL ) {
|
|
|
|
array = NULL;
|
|
|
|
nelems = 0;
|
|
|
|
//elog(NOTICE, "geom_accum: NULL array, nelems=%d", nelems);
|
|
|
|
} else {
|
|
|
|
array = (ArrayType *) PG_DETOAST_DATUM_COPY(datum);
|
|
|
|
nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
|
|
|
|
}
|
|
|
|
|
|
|
|
datum = PG_GETARG_DATUM(1);
|
|
|
|
// Do nothing, return state array
|
|
|
|
if ( (Pointer *)datum == NULL )
|
|
|
|
{
|
|
|
|
//elog(NOTICE, "geom_accum: NULL geom, nelems=%d", nelems);
|
|
|
|
PG_RETURN_ARRAYTYPE_P(array);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Switch to * flinfo->fcinfo->fn_mcxt
|
|
|
|
* memory context to be sure both detoasted
|
|
|
|
* geometry AND array of pointers to it
|
|
|
|
* last till the call to unite_finalfunc.
|
|
|
|
*/
|
|
|
|
oldcontext = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
|
|
|
|
|
|
|
|
/* Make a DETOASTED copy of input geometry */
|
2004-09-29 06:31:42 +00:00
|
|
|
geom = (PG_LWGEOM *)PG_DETOAST_DATUM_COPY(datum);
|
2004-08-27 16:01:48 +00:00
|
|
|
|
|
|
|
//elog(NOTICE, "geom_accum: adding %p (nelems=%d)", geom, nelems);
|
|
|
|
|
|
|
|
/*
|
2004-09-29 15:25:21 +00:00
|
|
|
* Might use a more optimized version instead of lwrealloc'ing
|
2004-08-27 16:01:48 +00:00
|
|
|
* at every iteration. This is not the bottleneck anyway.
|
|
|
|
* --strk(TODO);
|
|
|
|
*/
|
|
|
|
++nelems;
|
|
|
|
nbytes = ARR_OVERHEAD(1) + sizeof(Pointer *) * nelems;
|
|
|
|
if ( ! array ) {
|
2004-09-29 15:25:21 +00:00
|
|
|
result = (ArrayType *) lwalloc(nbytes);
|
2004-08-27 16:01:48 +00:00
|
|
|
result->size = nbytes;
|
|
|
|
result->ndim = 1;
|
|
|
|
*((int *) ARR_DIMS(result)) = nelems;
|
|
|
|
} else {
|
2004-09-29 15:25:21 +00:00
|
|
|
result = (ArrayType *) lwrealloc(array, nbytes);
|
2004-08-27 16:01:48 +00:00
|
|
|
result->size = nbytes;
|
|
|
|
result->ndim = 1;
|
|
|
|
*((int *) ARR_DIMS(result)) = nelems;
|
|
|
|
}
|
|
|
|
|
|
|
|
pointers = (Pointer **)ARR_DATA_PTR(result);
|
|
|
|
pointers[nelems-1] = (Pointer *)geom;
|
|
|
|
|
|
|
|
/* Go back to previous memory context */
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
|
|
|
|
|
|
|
PG_RETURN_ARRAYTYPE_P(result);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* collect_garray ( GEOMETRY[] ) returns a geometry which contains
|
|
|
|
* all the sub_objects from all of the geometries in given array.
|
|
|
|
*
|
|
|
|
* returned geometry is the simplest possible, based on the types
|
|
|
|
* of the collected objects
|
|
|
|
* ie. if all are of either X or multiX, then a multiX is returned
|
|
|
|
* bboxonly types are treated as null geometries (no sub_objects)
|
|
|
|
*/
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_collect_garray);
|
|
|
|
Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Datum datum;
|
|
|
|
ArrayType *array;
|
2004-10-11 09:55:27 +00:00
|
|
|
int nelems;
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM **geoms;
|
2004-10-11 09:55:27 +00:00
|
|
|
PG_LWGEOM *result=NULL;
|
|
|
|
LWGEOM **lwgeoms, *outlwg;
|
|
|
|
size_t size;
|
2004-08-27 16:01:48 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
//elog(NOTICE, "LWGEOM_collect_garray called");
|
|
|
|
|
|
|
|
/* Get input datum */
|
|
|
|
datum = PG_GETARG_DATUM(0);
|
|
|
|
|
|
|
|
/* Return null on null input */
|
|
|
|
if ( (Pointer *)datum == NULL )
|
|
|
|
{
|
|
|
|
elog(NOTICE, "NULL input");
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get actual ArrayType */
|
|
|
|
array = (ArrayType *) PG_DETOAST_DATUM(datum);
|
|
|
|
|
|
|
|
/* Get number of geometries in array */
|
|
|
|
nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
|
|
|
|
|
|
|
|
/* Return null on 0-elements input array */
|
|
|
|
if ( nelems == 0 )
|
|
|
|
{
|
|
|
|
elog(NOTICE, "0 elements input array");
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get pointer to GEOMETRY pointers array */
|
2004-09-29 06:31:42 +00:00
|
|
|
geoms = (PG_LWGEOM **)ARR_DATA_PTR(array);
|
2004-08-27 16:01:48 +00:00
|
|
|
|
2004-10-11 09:55:27 +00:00
|
|
|
/*
|
|
|
|
* Deserialize all geometries in array into the lwgeoms pointers
|
|
|
|
* array
|
|
|
|
*/
|
|
|
|
lwgeoms = palloc(sizeof(LWGEOM *)*nelems);
|
2004-08-27 16:01:48 +00:00
|
|
|
for (i=0; i<nelems; i++)
|
|
|
|
{
|
2004-10-11 09:55:27 +00:00
|
|
|
lwgeoms[i] = lwgeom_deserialize(SERIALIZED_FORM(geoms[i]));
|
2004-08-27 16:01:48 +00:00
|
|
|
}
|
|
|
|
|
2004-10-11 09:55:27 +00:00
|
|
|
outlwg = (LWGEOM *)lwcollection_construct(
|
|
|
|
COLLECTIONTYPE,
|
|
|
|
lwgeom_getSRID(geoms[0]),
|
|
|
|
NULL, nelems, lwgeoms);
|
2004-08-27 16:01:48 +00:00
|
|
|
|
2004-10-11 09:55:27 +00:00
|
|
|
size = lwgeom_serialize_size(outlwg);
|
|
|
|
result = palloc(size+4);
|
|
|
|
result->size = (size+4);
|
|
|
|
lwgeom_serialize_buf(outlwg, SERIALIZED_FORM(result), &size);
|
|
|
|
if ( size != result->size-4 )
|
2004-08-27 16:01:48 +00:00
|
|
|
{
|
2004-10-11 09:55:27 +00:00
|
|
|
lwerror("lwgeom_serialize size:%d, lwgeom_serialize_size:%d",
|
|
|
|
size, result->size-4);
|
2004-08-27 16:01:48 +00:00
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
2004-09-22 16:52:13 +00:00
|
|
|
PG_RETURN_POINTER(result);
|
2004-08-27 16:01:48 +00:00
|
|
|
}
|
2004-09-06 09:13:13 +00:00
|
|
|
|
|
|
|
// makes a polygon of the expanded features bvol - 1st point = LL 3rd=UR
|
|
|
|
// 2d only. (3d might be worth adding).
|
|
|
|
// create new geometry of type polygon, 1 ring, 5 points
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_expand);
|
|
|
|
Datum LWGEOM_expand(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
2004-09-06 09:13:13 +00:00
|
|
|
double d = PG_GETARG_FLOAT8(1);
|
|
|
|
BOX2DFLOAT4 box;
|
2004-09-29 15:25:21 +00:00
|
|
|
POINT2D *pts = lwalloc(sizeof(POINT2D)*5);
|
2004-09-06 09:13:13 +00:00
|
|
|
POINTARRAY *pa[1];
|
|
|
|
LWPOLY *poly;
|
|
|
|
int SRID;
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *result;
|
2004-09-06 09:13:13 +00:00
|
|
|
char *ser;
|
|
|
|
|
2004-09-06 16:04:13 +00:00
|
|
|
// get geometry box
|
|
|
|
if ( ! getbox2d_p(SERIALIZED_FORM(geom), &box) )
|
|
|
|
{
|
|
|
|
// must be an EMPTY geometry
|
|
|
|
PG_RETURN_POINTER(geom);
|
|
|
|
}
|
|
|
|
|
|
|
|
// get geometry SRID
|
2004-09-06 09:13:13 +00:00
|
|
|
SRID = lwgeom_getsrid(SERIALIZED_FORM(geom));
|
|
|
|
|
|
|
|
// expand it
|
|
|
|
expand_box2d(&box, d);
|
|
|
|
|
|
|
|
// Assign coordinates to POINT2D array
|
|
|
|
pts[0].x = box.xmin; pts[0].y = box.ymin;
|
|
|
|
pts[1].x = box.xmin; pts[1].y = box.ymax;
|
|
|
|
pts[2].x = box.xmax; pts[2].y = box.ymax;
|
|
|
|
pts[3].x = box.xmax; pts[3].y = box.ymin;
|
|
|
|
pts[4].x = box.xmin; pts[4].y = box.ymin;
|
|
|
|
|
|
|
|
// Construct point array
|
2004-09-29 15:25:21 +00:00
|
|
|
pa[0] = lwalloc(sizeof(POINTARRAY));
|
2004-09-06 09:13:13 +00:00
|
|
|
pa[0]->serialized_pointlist = (char *)pts;
|
2004-10-05 16:28:34 +00:00
|
|
|
TYPE_SETZM(pa[0]->dims, 0, 0);
|
2004-09-06 09:13:13 +00:00
|
|
|
pa[0]->npoints = 5;
|
|
|
|
|
2004-10-07 10:03:23 +00:00
|
|
|
// Construct polygon
|
2004-10-08 13:20:55 +00:00
|
|
|
poly = lwpoly_construct(SRID, box2d_clone(&box), 1, pa);
|
2004-09-06 09:13:13 +00:00
|
|
|
|
|
|
|
// Serialize polygon
|
|
|
|
ser = lwpoly_serialize(poly);
|
|
|
|
|
2004-09-29 06:31:42 +00:00
|
|
|
// Construct PG_LWGEOM
|
2004-10-08 13:20:55 +00:00
|
|
|
result = PG_LWGEOM_construct(ser, SRID, 1);
|
2004-09-06 09:13:13 +00:00
|
|
|
|
|
|
|
PG_RETURN_POINTER(result);
|
|
|
|
}
|
2004-09-06 10:37:09 +00:00
|
|
|
|
|
|
|
// Convert geometry to BOX (internal postgres type)
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_to_BOX);
|
|
|
|
Datum LWGEOM_to_BOX(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *lwgeom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
2004-09-06 10:37:09 +00:00
|
|
|
BOX2DFLOAT4 box2d;
|
2004-09-29 15:25:21 +00:00
|
|
|
BOX *result = (BOX *)lwalloc(sizeof(BOX));
|
2004-09-06 10:37:09 +00:00
|
|
|
|
2004-09-06 16:04:13 +00:00
|
|
|
if ( ! getbox2d_p(SERIALIZED_FORM(lwgeom), &box2d) )
|
|
|
|
{
|
|
|
|
PG_RETURN_NULL(); // must be the empty geometry
|
|
|
|
}
|
2004-09-06 10:37:09 +00:00
|
|
|
box2df_to_box_p(&box2d, result);
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
// makes a polygon of the features bvol - 1st point = LL 3rd=UR
|
|
|
|
// 2d only. (3d might be worth adding).
|
|
|
|
// create new geometry of type polygon, 1 ring, 5 points
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_envelope);
|
|
|
|
Datum LWGEOM_envelope(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
2004-09-06 10:37:09 +00:00
|
|
|
BOX2DFLOAT4 box;
|
2004-09-29 15:25:21 +00:00
|
|
|
POINT2D *pts = lwalloc(sizeof(POINT2D)*5);
|
2004-09-06 10:37:09 +00:00
|
|
|
POINTARRAY *pa[1];
|
|
|
|
LWPOLY *poly;
|
|
|
|
int SRID;
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *result;
|
2004-09-06 10:37:09 +00:00
|
|
|
char *ser;
|
|
|
|
|
2004-09-06 16:04:13 +00:00
|
|
|
// get bounding box
|
|
|
|
if ( ! getbox2d_p(SERIALIZED_FORM(geom), &box) )
|
|
|
|
{
|
|
|
|
// must be the EMPTY geometry
|
|
|
|
PG_RETURN_POINTER(geom);
|
|
|
|
}
|
|
|
|
|
|
|
|
// get geometry SRID
|
2004-09-06 10:37:09 +00:00
|
|
|
SRID = lwgeom_getsrid(SERIALIZED_FORM(geom));
|
|
|
|
|
|
|
|
// Assign coordinates to POINT2D array
|
|
|
|
pts[0].x = box.xmin; pts[0].y = box.ymin;
|
|
|
|
pts[1].x = box.xmin; pts[1].y = box.ymax;
|
|
|
|
pts[2].x = box.xmax; pts[2].y = box.ymax;
|
|
|
|
pts[3].x = box.xmax; pts[3].y = box.ymin;
|
|
|
|
pts[4].x = box.xmin; pts[4].y = box.ymin;
|
|
|
|
|
|
|
|
// Construct point array
|
2004-09-29 15:25:21 +00:00
|
|
|
pa[0] = lwalloc(sizeof(POINTARRAY));
|
2004-09-06 10:37:09 +00:00
|
|
|
pa[0]->serialized_pointlist = (char *)pts;
|
2004-10-05 16:28:34 +00:00
|
|
|
TYPE_SETZM(pa[0]->dims, 0, 0);
|
2004-09-06 10:37:09 +00:00
|
|
|
pa[0]->npoints = 5;
|
|
|
|
|
2004-10-07 10:03:23 +00:00
|
|
|
// Construct polygon
|
2004-10-08 13:20:55 +00:00
|
|
|
poly = lwpoly_construct(SRID, box2d_clone(&box), 1, pa);
|
2004-09-06 10:37:09 +00:00
|
|
|
|
|
|
|
// Serialize polygon
|
|
|
|
ser = lwpoly_serialize(poly);
|
|
|
|
|
2004-09-29 06:31:42 +00:00
|
|
|
// Construct PG_LWGEOM
|
2004-10-08 13:20:55 +00:00
|
|
|
result = PG_LWGEOM_construct(ser, SRID, 1);
|
2004-09-06 10:37:09 +00:00
|
|
|
|
|
|
|
PG_RETURN_POINTER(result);
|
|
|
|
}
|
2004-09-06 12:24:17 +00:00
|
|
|
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_isempty);
|
|
|
|
Datum LWGEOM_isempty(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom = (PG_LWGEOM *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
2004-09-06 12:24:17 +00:00
|
|
|
|
|
|
|
if ( lwgeom_getnumgeometries(SERIALIZED_FORM(geom)) == 0 )
|
|
|
|
PG_RETURN_BOOL(TRUE);
|
|
|
|
PG_RETURN_BOOL(FALSE);
|
|
|
|
}
|
2004-09-08 10:25:26 +00:00
|
|
|
|
|
|
|
|
|
|
|
#if ! USE_GEOS
|
2004-09-20 09:21:29 +00:00
|
|
|
Datum centroid(PG_FUNCTION_ARGS);
|
2004-09-08 10:25:26 +00:00
|
|
|
PG_FUNCTION_INFO_V1(centroid);
|
|
|
|
Datum centroid(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
2004-09-08 10:25:26 +00:00
|
|
|
int type = lwgeom_getType(geom->type);
|
|
|
|
int SRID = lwgeom_getSRID(geom);
|
|
|
|
LWGEOM_EXPLODED *exp = lwgeom_explode(SERIALIZED_FORM(geom));
|
2004-10-05 21:53:11 +00:00
|
|
|
LWPOLY *poly=NULL;
|
2004-09-08 10:25:26 +00:00
|
|
|
LWPOINT *point;
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *result;
|
2004-09-20 09:21:29 +00:00
|
|
|
POINTARRAY *ring, *pa;
|
2004-10-05 16:28:34 +00:00
|
|
|
POINT3DZ *p, cent;
|
2004-09-08 10:25:26 +00:00
|
|
|
int i,j,k;
|
|
|
|
uint32 num_points_tot = 0;
|
|
|
|
char *srl;
|
|
|
|
char wantbbox = 0;
|
2004-09-20 09:21:29 +00:00
|
|
|
double tot_x=0, tot_y=0, tot_z=0;
|
2004-09-08 10:25:26 +00:00
|
|
|
|
|
|
|
if (type != POLYGONTYPE && type != MULTIPOLYGONTYPE)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
//find the centroid
|
|
|
|
for (i=0; i<exp->npolys; i++)
|
|
|
|
{
|
|
|
|
poly = lwpoly_deserialize(exp->polys[i]);
|
|
|
|
for (j=0; j<poly->nrings; j++)
|
|
|
|
{
|
|
|
|
ring = poly->rings[j];
|
|
|
|
for (k=0; k<ring->npoints-1; k++)
|
|
|
|
{
|
2004-10-05 16:28:34 +00:00
|
|
|
p = (POINT3DZ *)getPoint(ring, k);
|
2004-09-20 09:21:29 +00:00
|
|
|
tot_x += p->x;
|
|
|
|
tot_y += p->y;
|
2004-10-05 16:28:34 +00:00
|
|
|
if ( TYPE_HASZ(ring->dims) ) tot_z += p->z;
|
2004-09-08 10:25:26 +00:00
|
|
|
}
|
|
|
|
num_points_tot += ring->npoints-1;
|
|
|
|
}
|
|
|
|
pfree_polygon(poly);
|
|
|
|
}
|
|
|
|
pfree_exploded(exp);
|
|
|
|
|
|
|
|
// Setup point
|
|
|
|
cent.x = tot_x/num_points_tot;
|
|
|
|
cent.y = tot_y/num_points_tot;
|
|
|
|
cent.z = tot_z/num_points_tot;
|
|
|
|
|
|
|
|
// Construct POINTARRAY (paranoia?)
|
2004-10-05 21:53:11 +00:00
|
|
|
pa = pointArray_construct((char *)¢, 1, 0, 1);
|
2004-09-08 10:25:26 +00:00
|
|
|
|
|
|
|
// Construct LWPOINT
|
2004-10-08 13:20:55 +00:00
|
|
|
point = lwpoint_construct(SRID, NULL, pa);
|
2004-09-08 10:25:26 +00:00
|
|
|
|
|
|
|
// Serialize LWPOINT
|
|
|
|
srl = lwpoint_serialize(point);
|
|
|
|
|
|
|
|
pfree_point(point);
|
|
|
|
pfree_POINTARRAY(pa);
|
|
|
|
|
2004-09-29 06:31:42 +00:00
|
|
|
// Construct output PG_LWGEOM
|
2004-10-05 21:53:11 +00:00
|
|
|
result = PG_LWGEOM_construct(srl, SRID, wantbbox);
|
2004-09-08 10:25:26 +00:00
|
|
|
|
|
|
|
PG_RETURN_POINTER(result);
|
|
|
|
}
|
|
|
|
#endif // ! USE_GEOS
|
2004-09-08 14:19:25 +00:00
|
|
|
|
|
|
|
// Returns a modified [multi]polygon so that no ring segment is
|
|
|
|
// longer then the given distance (computed using 2d).
|
|
|
|
// Every input point is kept.
|
|
|
|
// Z and M values for added points (if needed) are set to 0.
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_segmentize2d);
|
|
|
|
Datum LWGEOM_segmentize2d(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-10-10 20:31:23 +00:00
|
|
|
PG_LWGEOM *outgeom, *ingeom;
|
|
|
|
double dist;
|
|
|
|
LWGEOM *inlwgeom, *outlwgeom;
|
|
|
|
size_t size, retsize;
|
2004-09-08 14:19:25 +00:00
|
|
|
|
2004-10-10 20:31:23 +00:00
|
|
|
ingeom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
|
|
|
dist = PG_GETARG_FLOAT8(1);
|
2004-09-08 14:19:25 +00:00
|
|
|
|
2004-10-10 20:31:23 +00:00
|
|
|
// Avoid deserialize/serialize steps
|
|
|
|
if ( (TYPE_GETTYPE(ingeom->type) == POINTTYPE) ||
|
|
|
|
(TYPE_GETTYPE(ingeom->type) == MULTIPOINTTYPE) )
|
|
|
|
PG_RETURN_POINTER(ingeom);
|
2004-09-08 14:19:25 +00:00
|
|
|
|
2004-10-10 20:31:23 +00:00
|
|
|
inlwgeom = lwgeom_deserialize(SERIALIZED_FORM(ingeom));
|
|
|
|
outlwgeom = lwgeom_segmentize2d(inlwgeom, dist);
|
2004-09-08 14:19:25 +00:00
|
|
|
|
2004-10-10 20:31:23 +00:00
|
|
|
size = lwgeom_serialize_size(outlwgeom);
|
|
|
|
outgeom = palloc(size+4);
|
|
|
|
outgeom->size = size+4;
|
|
|
|
lwgeom_serialize_buf(outlwgeom, SERIALIZED_FORM(outgeom), &retsize);
|
2004-09-08 14:19:25 +00:00
|
|
|
|
2004-10-10 20:31:23 +00:00
|
|
|
if ( size != retsize )
|
|
|
|
{
|
|
|
|
lwerror ("lwgeom_serialize_buf returned size(%d) != lwgeom_serialize_size (%d)", retsize, size);
|
|
|
|
}
|
2004-09-08 14:19:25 +00:00
|
|
|
|
2004-10-10 20:31:23 +00:00
|
|
|
PG_RETURN_POINTER(outgeom);
|
2004-09-08 14:19:25 +00:00
|
|
|
}
|
2004-09-28 08:22:20 +00:00
|
|
|
|
|
|
|
// Reverse vertex order of geometry
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_reverse);
|
|
|
|
Datum LWGEOM_reverse(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom;
|
2004-09-30 08:18:06 +00:00
|
|
|
LWGEOM *lwgeom;
|
2004-09-28 08:22:20 +00:00
|
|
|
|
2004-09-30 08:18:06 +00:00
|
|
|
geom = (PG_LWGEOM *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0));
|
2004-09-28 08:22:20 +00:00
|
|
|
|
2004-09-30 08:18:06 +00:00
|
|
|
lwgeom = lwgeom_deserialize(SERIALIZED_FORM(geom));
|
|
|
|
lwgeom_reverse(lwgeom);
|
2004-09-28 08:22:20 +00:00
|
|
|
|
2004-09-30 08:18:06 +00:00
|
|
|
PG_RETURN_POINTER(geom);
|
2004-09-28 08:22:20 +00:00
|
|
|
}
|
2004-09-28 09:01:17 +00:00
|
|
|
|
|
|
|
// Force polygons of the collection to obey Right-Hand-Rule
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_forceRHR_poly);
|
|
|
|
Datum LWGEOM_forceRHR_poly(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2004-09-29 06:31:42 +00:00
|
|
|
PG_LWGEOM *geom;
|
2004-09-30 08:18:06 +00:00
|
|
|
LWGEOM *lwgeom;
|
2004-09-28 09:01:17 +00:00
|
|
|
|
2004-09-30 08:18:06 +00:00
|
|
|
geom = (PG_LWGEOM *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0));
|
2004-09-28 09:01:17 +00:00
|
|
|
|
2004-09-30 08:18:06 +00:00
|
|
|
lwgeom = lwgeom_deserialize(SERIALIZED_FORM(geom));
|
|
|
|
lwgeom_forceRHR(lwgeom);
|
2004-09-28 09:01:17 +00:00
|
|
|
|
2004-09-30 08:18:06 +00:00
|
|
|
PG_RETURN_POINTER(geom);
|
2004-09-28 09:01:17 +00:00
|
|
|
}
|
2004-10-03 15:52:23 +00:00
|
|
|
|
|
|
|
// Test deserialize/serialize operations
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_noop);
|
|
|
|
Datum LWGEOM_noop(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
PG_LWGEOM *in, *out;
|
|
|
|
LWGEOM *lwgeom;
|
|
|
|
size_t size, retsize;
|
|
|
|
|
|
|
|
in = (PG_LWGEOM *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0));
|
|
|
|
|
|
|
|
lwgeom = lwgeom_deserialize(SERIALIZED_FORM(in));
|
|
|
|
|
|
|
|
lwnotice("Deserialized: %s", lwgeom_summary(lwgeom, 0));
|
|
|
|
|
|
|
|
size = lwgeom_serialize_size(lwgeom);
|
|
|
|
out = palloc(size+4);
|
|
|
|
out->size = size+4;
|
|
|
|
lwgeom_serialize_buf(lwgeom, SERIALIZED_FORM(out), &retsize);
|
|
|
|
|
|
|
|
if ( size != retsize )
|
|
|
|
{
|
|
|
|
lwerror ("lwgeom_serialize_buf returned size(%d) != lwgeom_serialize_size (%d)", retsize, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(out);
|
|
|
|
}
|
2004-10-06 08:53:24 +00:00
|
|
|
|
|
|
|
// Return:
|
|
|
|
// 0==2d
|
|
|
|
// 1==3dm
|
|
|
|
// 2==3dz
|
|
|
|
// 3==4d
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_zmflag);
|
|
|
|
Datum LWGEOM_zmflag(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
PG_LWGEOM *in;
|
|
|
|
unsigned char type;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
in = (PG_LWGEOM *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0));
|
|
|
|
type = in->type;
|
|
|
|
if ( TYPE_HASZ(type) ) ret += 2;
|
|
|
|
if ( TYPE_HASM(type) ) ret += 1;
|
|
|
|
PG_RETURN_INT16(ret);
|
|
|
|
}
|
2004-10-08 13:20:55 +00:00
|
|
|
|
|
|
|
// lwgeom_same(lwgeom1, lwgeom2)
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_same);
|
|
|
|
Datum LWGEOM_same(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
PG_LWGEOM *g1 = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
|
|
|
PG_LWGEOM *g2 = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
|
|
|
LWGEOM *lwg1, *lwg2;
|
|
|
|
bool result;
|
|
|
|
|
|
|
|
if ( TYPE_GETTYPE(g1->type) != TYPE_GETTYPE(g2->type) )
|
|
|
|
PG_RETURN_BOOL(FALSE); // different types
|
|
|
|
|
|
|
|
if ( TYPE_GETZM(g1->type) != TYPE_GETZM(g2->type) )
|
|
|
|
PG_RETURN_BOOL(FALSE); // different dimensions
|
|
|
|
|
|
|
|
// ok, deserialize.
|
|
|
|
lwg1 = lwgeom_deserialize(SERIALIZED_FORM(g1));
|
|
|
|
lwg2 = lwgeom_deserialize(SERIALIZED_FORM(g2));
|
|
|
|
|
|
|
|
// invoke appropriate function
|
|
|
|
result = lwgeom_same(lwg1, lwg2);
|
|
|
|
|
|
|
|
// Relase memory
|
|
|
|
lwgeom_release(lwg1);
|
|
|
|
lwgeom_release(lwg2);
|
|
|
|
PG_FREE_IF_COPY(g1, 0);
|
|
|
|
PG_FREE_IF_COPY(g2, 1);
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(result);
|
|
|
|
}
|
|
|
|
|