30 #include "../postgis_config.h" 99 LWDEBUGF(5,
"pa = %p; p = %p; where = %d", pa, p, where);
104 lwerror(
"ptarray_insert_point: called on read-only point array");
109 if ( where > pa->
npoints || where < 0)
111 lwerror(
"ptarray_insert_point: offset out of range (%d)", where);
138 if( where < pa->npoints )
140 size_t copy_size = point_size * (pa->
npoints - where);
142 LWDEBUGF(5,
"copying %d bytes to start vertex %d from start vertex %d", copy_size, where+1, where);
150 LWDEBUGF(5,
"copying new point to start vertex %d", point_size, where);
162 lwerror(
"ptarray_append_point: null input");
171 LWDEBUGF(4,
"checking for duplicate end point (pt = POINT(%g %g) pa->npoints-q = POINT(%g %g))",pt->
x,pt->
y,tmp.
x,tmp.
y);
174 if ( (pt->
x == tmp.
x) && (pt->
y == tmp.
y) &&
189 unsigned int poff = 0;
190 unsigned int npoints;
197 lwerror(
"ptarray_append_ptarray: null input");
207 lwerror(
"ptarray_append_ptarray: target pointarray is read-only");
213 lwerror(
"ptarray_append_ptarray: appending mixed dimensionality is not allowed");
231 else if ( gap_tolerance == 0 || ( gap_tolerance > 0 &&
234 lwerror(
"Second line start point too far from first line end point");
268 lwerror(
"ptarray_remove_point: null input");
273 if ( where >= pa->
npoints || where < 0)
275 lwerror(
"ptarray_remove_point: offset out of range (%d)", where);
280 if( where < pa->npoints - 1 )
298 LWDEBUGF(5,
"hasz = %d, hasm = %d, npoints = %d, ptlist = %p", hasz, hasm, npoints, ptlist);
337 LWDEBUG(5,
"Freeing a PointArray");
352 for (i=0; i<mid; i++)
357 memcpy((
uint8_t *)&pbuf, to, ptsize);
358 memcpy(to, from, ptsize);
359 memcpy(from, (
uint8_t *)&pbuf, ptsize);
375 for (i=0 ; i < pa->
npoints ; i++)
391 double d, *dp1, *dp2;
394 dp1 = ((
double*)&p)+(unsigned)o1;
395 dp2 = ((
double*)&p)+(unsigned)o2;
396 for (i=0 ; i < pa->
npoints ; i++)
425 pbuf.
x = pbuf.
y = pbuf.
z = pbuf.
m = 0;
436 while (ipoff<ipa->npoints)
448 POINT4D *p1ptr=&p1, *p2ptr=&p2;
456 pbuf.
x = p1.
x + (p2.
x-p1.
x)/segdist * dist;
457 pbuf.
y = p1.
y + (p2.
y-p1.
y)/segdist * dist;
459 pbuf.
z = p1.
z + (p2.
z-p1.
z)/segdist * dist;
461 pbuf.
m = p1.
m + (p2.
m-p1.
m)/segdist * dist;
485 LWDEBUG(5,
"dimensions are the same");
488 LWDEBUG(5,
"npoints are the same");
497 LWDEBUGF(5,
"point #%d is the same",i);
510 LWDEBUGF(3,
"pa %x p %x size %d where %d",
511 pa, p, pdims, where);
513 if ( pdims < 2 || pdims > 4 )
515 lwerror(
"ptarray_addPoint: point dimension out of range (%d)",
522 lwerror(
"ptarray_addPoint: offset out of range (%d)",
527 LWDEBUG(3,
"called with a %dD point");
529 pbuf.
x = pbuf.
y = pbuf.
z = pbuf.
m = 0.0;
530 memcpy((
uint8_t *)&pbuf, p, pdims*
sizeof(
double));
532 LWDEBUG(3,
"initialized point buffer");
537 if ( where == -1 ) where = pa->
npoints;
562 LWDEBUGF(3,
"pa %x which %d", pa, which);
564 #if PARANOIA_LEVEL > 0 567 lwerror(
"%s [%d] offset (%d) out of range (%d..%d)", __FILE__, __LINE__,
574 lwerror(
"%s [%d] can't remove a point from a 2-vertex POINTARRAY", __FILE__, __LINE__);
589 if ( which < pa->npoints-1 )
605 lwerror(
"ptarray_cat: Mixed dimension");
634 LWDEBUG(3,
"ptarray_clone_deep called.");
665 LWDEBUG(3,
"ptarray_clone_deep called.");
687 lwerror(
"ptarray_is_closed: called with null point array");
701 lwerror(
"ptarray_is_closed_2d: called with null point array");
714 lwerror(
"ptarray_is_closed_3d: called with null point array");
753 if ( check_closed && !
p2d_same(seg1, seg2) )
754 lwerror(
"ptarray_contains_point called on unclosed ring");
756 for ( i=1; i < pa->
npoints; i++ )
761 if ( seg1->
x == seg2->
x && seg1->
y == seg2->
y )
771 if ( pt->
y > ymax || pt->
y < ymin )
793 if ( (side < 0) && (seg1->
y <= pt->
y) && (pt->
y < seg2->
y) )
803 else if ( (side > 0) && (seg2->
y <= pt->
y) && (pt->
y < seg1->
y) )
812 if ( winding_number )
813 *winding_number = wn;
853 lwerror(
"ptarrayarc_contains_point called with even number of points");
860 lwerror(
"ptarrayarc_contains_point called too-short pointarray");
867 if ( check_closed && !
p2d_same(seg1, seg3) )
869 lwerror(
"ptarrayarc_contains_point called on unclosed ring");
888 else if ( d < radius )
900 for ( i=1; i < pa->
npoints; i += 2 )
925 if ( (pt->
x > gbox.
xmax || pt->
x < gbox.
xmin) &&
935 if ( (side == 0) &&
lw_pt_in_arc(pt, seg1, seg2, seg3) )
941 if ( side < 0 && (seg1->
y <= pt->
y) && (pt->
y < seg3->
y) )
947 if ( side > 0 && (seg2->
y <= pt->
y) && (pt->
y < seg1->
y) )
953 if ( pt->
x <= gbox.
xmax && pt->
x >= gbox.
xmin )
979 if ( winding_number )
980 *winding_number = wn;
1004 double x0,
x, y1, y2;
1013 for ( i = 2; i < pa->
npoints; i++ )
1047 for( i = 0; i < pa->
npoints; i++ )
1050 if( hasz && ! in_hasz )
1052 if( hasm && ! in_hasm )
1069 double length, slength, tlength;
1082 LWDEBUGF(3,
"Total length: %g", length);
1090 LWDEBUGF(3,
"From/To: %g/%g", from, to);
1096 for ( i = 0; i < nsegs; i++ )
1103 LWDEBUGF(3 ,
"Segment %d: (%g,%g,%g,%g)-(%g,%g,%g,%g)",
1104 i, p1.
x, p1.
y, p1.
z, p1.
m, p2.
x, p2.
y, p2.
z, p2.
m);
1118 if ( fabs ( from - ( tlength + slength ) ) <= tolerance )
1121 LWDEBUG(3,
" Second point is our start");
1131 else if ( fabs(from - tlength) <= tolerance )
1134 LWDEBUG(3,
" First point is our start");
1152 else if ( from > tlength + slength )
goto END;
1157 LWDEBUG(3,
" Seg contains first point");
1163 dseg = (from - tlength) / slength;
1185 if ( fabs(to - ( tlength + slength ) ) <= tolerance )
1188 LWDEBUG(3,
" Second point is our end");
1198 else if ( fabs(to - tlength) <= tolerance )
1201 LWDEBUG(3,
" First point is our end");
1212 else if ( to > tlength + slength )
1222 else if ( to < tlength + slength )
1225 LWDEBUG(3,
" Seg contains our end");
1227 dseg = (to - tlength) / slength;
1245 memcpy(&p1, &p2,
sizeof(
POINT4D));
1282 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) );
1295 ret->
x = A->
x + ( (B->
x - A->
x) * r );
1296 ret->
y = A->
y + ( (B->
y - A->
y) * r );
1297 ret->
z = A->
z + ( (B->
z - A->
z) * r );
1298 ret->
m = A->
m + ( (B->
m - A->
m) * r );
1311 POINT4D start4d, end4d, projtmp;
1313 const POINT2D *start = NULL, *end = NULL;
1319 if ( ! proj4d ) proj4d = &projtmp;
1340 if (t==1 || dist < mindist )
1348 LWDEBUG(3,
"Breaking on mindist=0");
1355 if ( mindistout ) *mindistout = mindist;
1357 LWDEBUGF(3,
"Closest segment: %d", seg);
1358 LWDEBUGF(3,
"mindist: %g", mindist);
1380 LWDEBUGF(3,
"Closest point on segment: %g,%g", proj.
x, proj.
y);
1388 if ( tlen == 0 )
return 0;
1392 for (t=0; t<seg; t++, start=end)
1397 LWDEBUGF(4,
"Segment %d made plen %g", t, plen);
1402 LWDEBUGF(3,
"plen %g, tlen %g", plen, tlen);
1425 if ( x < 0 ) x+= 360;
1426 else if ( x > 180 ) x -= 360;
1460 lwerror(
"%s: unsupported number of dimensions - %d", __func__, ndims);
1471 double tolsq = tolerance * tolerance;
1478 double dsq = FLT_MAX;
1481 if ( n_points <= min_points )
return;
1484 for (i = 1; i < n_points; i++)
1486 int last_point = (i == n_points-1);
1492 if (n_points + n_points_out > min_points + i)
1494 if (tolerance > 0.0)
1499 if (!last_point && dsq <= tolsq)
1507 if (memcmp((
char*)pt, (
char*)last, pt_size) == 0)
1515 if (last_point && n_points_out > 1 && tolerance > 0.0 && dsq <= tolsq)
1558 LWDEBUG(4,
"function called");
1569 LWDEBUGF(4,
"P%d(%f,%f) to P%d(%f,%f)",
1570 p1, pa->
x, pa->
y, p2, pb->
x, pb->
y);
1572 for (k=p1+1; k<p2; k++)
1586 LWDEBUGF(4,
"P%d is farthest (%g)", k, d);
1594 LWDEBUG(3,
"segment too short, no split/no dist");
1610 double eps_sqr = epsilon * epsilon;
1616 stack[++sp] = inpts->
npoints-1;
1626 LWDEBUG(3,
"Added P0 to simplified point array (size 1)");
1633 LWDEBUGF(3,
"Farthest point from P%d-P%d is P%d (dist. %g)", p1, stack[sp], split, dist);
1635 if (dist > eps_sqr || ( outpts->
npoints+sp+1 < minpts && dist >= 0 ) )
1637 LWDEBUGF(4,
"Added P%d to stack (outpts:%d)", split, sp);
1638 stack[++sp] = split;
1646 LWDEBUGF(4,
"Added P%d to simplified point array (size: %d)", stack[sp], outpts->
npoints);
1651 LWDEBUGF(4,
"stack pointer = %d", sp);
1674 lwerror(
"arc point array with even number of points");
1678 for ( i=2; i < pts->
npoints; i += 2 )
1699 if ( pts->
npoints < 2 )
return 0.0;
1703 for ( i=1; i < pts->
npoints; i++ )
1707 dist += sqrt( ((frm->
x - to->
x)*(frm->
x - to->
x)) +
1708 ((frm->
y - to->
y)*(frm->
y - to->
y)) );
1727 if ( pts->
npoints < 2 )
return 0.0;
1733 for ( i=1; i < pts->
npoints; i++ )
1736 dist += sqrt( ((frm.
x - to.
x)*(frm.
x - to.
x)) +
1737 ((frm.
y - to.
y)*(frm.
y - to.
y)) +
1738 ((frm.
z - to.
z)*(frm.
z - to.
z)) );
1758 #if PARANOIA_LEVEL > 0 1761 lwerror(
"%s [%d] got NULL pointarray", __FILE__, __LINE__);
1771 lwerror(
"%s [%d] called outside of ptarray range (n=%d, pa.npoints=%d, pa.maxpoints=%d)", __FILE__, __LINE__, n, pa->
npoints, pa->
maxpoints);
1781 LWDEBUGF(5,
"point = %g %g", *((
double*)(ptr)), *((
double*)(ptr+8)));
1785 LWDEBUGF(5,
"point = %g %g %g", *((
double*)(ptr)), *((
double*)(ptr+8)), *((
double*)(ptr+16)));
1789 LWDEBUGF(5,
"point = %g %g %g %g", *((
double*)(ptr)), *((
double*)(ptr+8)), *((
double*)(ptr+16)), *((
double*)(ptr+24)));
1806 LWDEBUG(2,
"lwgeom_affine_ptarray start");
1823 LWDEBUGF(3,
" POINT %g %g %g => %g %g %g", x, y, z, p4d.
x, p4d.
y, p4d.
z);
1828 LWDEBUG(3,
" doesn't have z");
1839 LWDEBUGF(3,
" POINT %g %g => %g %g", x, y, p4d.
x, p4d.
y);
1843 LWDEBUG(3,
"lwgeom_affine_ptarray end");
1856 LWDEBUG(3,
"ptarray_scale start");
1868 LWDEBUG(3,
"ptarray_scale end");
1896 LWDEBUGF(2,
"ptarray_grid called on %p", pa);
1900 for (ipn=0; ipn<pa->
npoints; ++ipn)
1906 pt.
x = rint((pt.
x - grid->
ipx)/grid->
xsize) *
1910 pt.
y = rint((pt.
y - grid->
ipy)/grid->
ysize) *
1914 pt.
z = rint((pt.
z - grid->
ipz)/grid->
zsize) *
1918 pt.
m = rint((pt.
m - grid->
ipm)/grid->
msize) *
1934 for ( i = 0; i < pa->
npoints; i++ )
void ptarray_set_point4d(POINTARRAY *pa, int n, const POINT4D *p4d)
double lw_arc_center(const POINT2D *p1, const POINT2D *p2, const POINT2D *p3, POINT2D *result)
Determines the center of the circle defined by the three given points.
POINTARRAY * ptarray_remove_repeated_points_minpoints(const POINTARRAY *in, double tolerance, int minpoints)
int ptarrayarc_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number)
POINTARRAY * ptarray_substring(POINTARRAY *ipa, double from, double to, double tolerance)
start location (distance from start / total distance) end location (distance from start / total dist...
int lw_arc_is_pt(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3)
Returns true if arc A is actually a point (all vertices are the same) .
uint8_t * serialized_pointlist
int ptarray_point_size(const POINTARRAY *pa)
POINTARRAY * ptarray_merge(POINTARRAY *pa1, POINTARRAY *pa2)
Merge two given POINTARRAY and returns a pointer on the new aggregate one.
#define FLAGS_GET_READONLY(flags)
int lw_arc_calculate_gbox_cartesian_2d(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, GBOX *gbox)
double ptarray_length(const POINTARRAY *pts)
Find the 3d/2d length of the given POINTARRAY (depending on its dimensionality)
POINTARRAY * ptarray_clone_deep(const POINTARRAY *in)
Deep clone a pointarray (also clones serialized pointlist)
POINTARRAY * ptarray_simplify(POINTARRAY *inpts, double epsilon, unsigned int minpts)
Datum area(PG_FUNCTION_ARGS)
double ptarray_locate_point(const POINTARRAY *pa, const POINT4D *p4d, double *mindistout, POINT4D *proj4d)
POINTARRAY * ptarray_flip_coordinates(POINTARRAY *pa)
Reverse X and Y axis on a given POINTARRAY.
void ptarray_reverse(POINTARRAY *pa)
POINTARRAY * ptarray_construct_reference_data(char hasz, char hasm, uint32_t npoints, uint8_t *ptlist)
Build a new POINTARRAY, but on top of someone else's ordinate array.
#define FLAGS_GET_ZM(flags)
#define LWDEBUG(level, msg)
void ptarray_scale(POINTARRAY *pa, const POINT4D *fact)
Scale a pointarray.
int ptarray_is_closed_2d(const POINTARRAY *in)
#define LW_ON_INTERRUPT(x)
int ptarray_append_point(POINTARRAY *pa, const POINT4D *pt, int repeated_points)
Append a point to the end of an existing POINTARRAY If allow_duplicate is LW_FALSE, then a duplicate point will not be added.
void ptarray_swap_ordinates(POINTARRAY *pa, LWORD o1, LWORD o2)
Swap ordinate values o1 and o2 on a given POINTARRAY.
int ptarray_isccw(const POINTARRAY *pa)
POINTARRAY * ptarray_removePoint(POINTARRAY *pa, uint32_t which)
Remove a point from a pointarray.
double distance2d_pt_pt(const POINT2D *p1, const POINT2D *p2)
The old function nessecary for ptarray_segmentize2d in ptarray.c.
int ptarray_npoints_in_rect(const POINTARRAY *pa, const GBOX *gbox)
POINTARRAY * ptarray_construct_copy_data(char hasz, char hasm, uint32_t npoints, const uint8_t *ptlist)
Construct a new POINTARRAY, copying in the data from ptlist.
double distance2d_pt_seg(const POINT2D *p, const POINT2D *A, const POINT2D *B)
The old function nessecary for ptarray_segmentize2d in ptarray.c.
void ptarray_longitude_shift(POINTARRAY *pa)
Longitude shift for a pointarray.
void interpolate_point4d(POINT4D *A, POINT4D *B, POINT4D *I, double F)
Find interpolation point I between point A and point B so that the len(AI) == len(AB)*F and I falls o...
POINTARRAY * ptarray_clone(const POINTARRAY *in)
Clone a POINTARRAY object.
int ptarray_startpoint(const POINTARRAY *pa, POINT4D *pt)
int p2d_same(const POINT2D *p1, const POINT2D *p2)
POINTARRAY * ptarray_grid(const POINTARRAY *pa, const gridspec *grid)
double lw_arc_length(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3)
Returns the length of a circular arc segment.
int getPoint3dz_p(const POINTARRAY *pa, int n, POINT3DZ *point)
int ptarray_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number)
const POINT2D * getPoint2d_cp(const POINTARRAY *pa, int n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from...
POINTARRAY * ptarray_addPoint(const POINTARRAY *pa, uint8_t *p, size_t pdims, uint32_t where)
Add a point in a pointarray.
#define LW_TRUE
Return types for functions with status returns.
void closest_point_on_segment(const POINT4D *p, const POINT4D *A, const POINT4D *B, POINT4D *ret)
int ptarray_insert_point(POINTARRAY *pa, const POINT4D *p, int where)
Insert a point into an existing POINTARRAY.
int ptarray_is_closed_z(const POINTARRAY *in)
static void ptarray_copy_point(POINTARRAY *pa, uint32_t from, uint32_t to)
int ptarray_has_z(const POINTARRAY *pa)
#define LW_INSIDE
Constants for point-in-polygon return values.
int ptarray_has_m(const POINTARRAY *pa)
enum LWORD_T LWORD
Ordinate names.
POINTARRAY * ptarray_construct(char hasz, char hasm, uint32_t npoints)
Construct an empty pointarray, allocating storage and setting the npoints, but not filling in any inf...
int getPoint2d_p(const POINTARRAY *pa, int n, POINT2D *point)
#define FLAGS_GET_Z(flags)
Macros for manipulating the 'flags' byte.
int ptarray_is_closed_3d(const POINTARRAY *in)
double ptarray_length_2d(const POINTARRAY *pts)
Find the 2d length of the given POINTARRAY (even if it's 3d)
static void ptarray_remove_repeated_points_in_place(POINTARRAY *pa, double tolerance, uint32_t min_points)
uint8_t gflags(int hasz, int hasm, int geodetic)
Construct a new flags char.
double ptarray_signed_area(const POINTARRAY *pa)
Returns the area in cartesian units.
double ptarray_arc_length_2d(const POINTARRAY *pts)
Find the 2d length of the given POINTARRAY, using circular arc interpolation between each coordinate ...
int ptarray_remove_point(POINTARRAY *pa, int where)
Remove a point from an existing POINTARRAY.
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
int lw_arc_side(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, const POINT2D *Q)
int lw_pt_in_arc(const POINT2D *P, const POINT2D *A1, const POINT2D *A2, const POINT2D *A3)
Returns true if P is on the same side of the plane partition defined by A1/A3 as A2 is...
void * lwrealloc(void *mem, size_t size)
#define FLAGS_GET_M(flags)
int lw_pt_in_seg(const POINT2D *P, const POINT2D *A1, const POINT2D *A2)
Returns true if P is between A1/A2.
double distance2d_sqr_pt_pt(const POINT2D *p1, const POINT2D *p2)
void * lwalloc(size_t size)
int lw_segment_side(const POINT2D *p1, const POINT2D *p2, const POINT2D *q)
lw_segment_side()
void ptarray_free(POINTARRAY *pa)
POINTARRAY * ptarray_segmentize2d(const POINTARRAY *ipa, double dist)
Returns a modified POINTARRAY so that no segment is longer than the given distance (computed using 2d...
int ptarrayarc_contains_point(const POINTARRAY *pa, const POINT2D *pt)
For POINTARRAYs representing CIRCULARSTRINGS.
double distance2d_sqr_pt_seg(const POINT2D *p, const POINT2D *A, const POINT2D *B)
char ptarray_same(const POINTARRAY *pa1, const POINTARRAY *pa2)
#define LWDEBUGF(level, msg,...)
#define FLAGS_NDIMS(flags)
void ptarray_affine(POINTARRAY *pa, const AFFINE *a)
Affine transform a pointarray.
POINTARRAY * ptarray_force_dims(const POINTARRAY *pa, int hasz, int hasm)
uint8_t * getPoint_internal(const POINTARRAY *pa, int n)
int ptarray_is_closed(const POINTARRAY *in)
Check for ring closure using whatever dimensionality is declared on the pointarray.
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
int gbox_contains_point2d(const GBOX *g, const POINT2D *p)
int getPoint4d_p(const POINTARRAY *pa, int n, POINT4D *point)
int ptarray_append_ptarray(POINTARRAY *pa1, POINTARRAY *pa2, double gap_tolerance)
Append a POINTARRAY, pa2 to the end of an existing POINTARRAY, pa1.
#define FLAGS_SET_READONLY(flags, value)
POINTARRAY * ptarray_remove_repeated_points(const POINTARRAY *in, double tolerance)
static void ptarray_dp_findsplit(POINTARRAY *pts, int p1, int p2, int *split, double *dist)
int ptarray_contains_point(const POINTARRAY *pa, const POINT2D *pt)
Return 1 if the point is inside the POINTARRAY, -1 if it is outside, and 0 if it is on the boundary...