Datum BOX2DFLOAT4_construct(PG_FUNCTION_ARGS) { PG_LWGEOM *min = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); PG_LWGEOM *max = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); BOX2DFLOAT4 *result = palloc(sizeof(BOX2DFLOAT4)); LWGEOM *minpoint, *maxpoint; POINT2D minp, maxp; minpoint = lwgeom_deserialize(SERIALIZED_FORM(min)); maxpoint = lwgeom_deserialize(SERIALIZED_FORM(max)); if ( TYPE_GETTYPE(minpoint->type) != POINTTYPE || TYPE_GETTYPE(maxpoint->type) != POINTTYPE ) { elog(ERROR, "BOX2DFLOAT4_construct: args must be points"); PG_RETURN_NULL(); } errorIfSRIDMismatch(minpoint->SRID, maxpoint->SRID); getPoint2d_p(((LWPOINT *)minpoint)->point, 0, &minp); getPoint2d_p(((LWPOINT *)maxpoint)->point, 0, &maxp); result->xmax = maxp.x; result->ymax = maxp.y; result->xmin = minp.x; result->ymin = minp.y; PG_RETURN_POINTER(result); }
static size_t pointArray_svg_rel(POINTARRAY *pa, char *output, int close_ring, int precision) { int i, end; char *ptr; char x[OUT_MAX_DIGS_DOUBLE+OUT_MAX_DOUBLE_PRECISION+1]; char y[OUT_MAX_DIGS_DOUBLE+OUT_MAX_DOUBLE_PRECISION+1]; POINT2D pt, lpt; ptr = output; if (close_ring) end = pa->npoints; else end = pa->npoints - 1; /* Starting point */ getPoint2d_p(pa, 0, &pt); if (fabs(pt.x) < OUT_MAX_DOUBLE) sprintf(x, "%.*f", precision, pt.x); else sprintf(x, "%g", pt.x); trim_trailing_zeros(x); if (fabs(pt.y) < OUT_MAX_DOUBLE) sprintf(y, "%.*f", precision, fabs(pt.y) ? pt.y * -1 : pt.y); else sprintf(y, "%g", fabs(pt.y) ? pt.y * -1 : pt.y); trim_trailing_zeros(y); ptr += sprintf(ptr,"%s %s l", x, y); /* All the following ones */ for (i=1 ; i < end ; i++) { lpt = pt; getPoint2d_p(pa, i, &pt); if (fabs(pt.x -lpt.x) < OUT_MAX_DOUBLE) sprintf(x, "%.*f", precision, pt.x -lpt.x); else sprintf(x, "%g", pt.x -lpt.x); trim_trailing_zeros(x); /* SVG Y axis is reversed, an no need to transform 0 into -0 */ if (fabs(pt.y -lpt.y) < OUT_MAX_DOUBLE) sprintf(y, "%.*f", precision, fabs(pt.y -lpt.y) ? (pt.y - lpt.y) * -1: (pt.y - lpt.y)); else sprintf(y, "%g", fabs(pt.y -lpt.y) ? (pt.y - lpt.y) * -1: (pt.y - lpt.y)); trim_trailing_zeros(y); ptr += sprintf(ptr," %s %s", x, y); } return (ptr-output); }
/** * 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(const POINT2D *p, const POINTARRAY *ring) { int cn = 0; /* the crossing number counter */ int i; POINT2D v1, v2; POINT2D first, last; getPoint2d_p(ring, 0, &first); getPoint2d_p(ring, ring->npoints-1, &last); if ( memcmp(&first, &last, sizeof(POINT2D)) ) { lwerror("pt_in_ring_2d: V[n] != V[0] (%g %g != %g %g)", first.x, first.y, last.x, last.y); return LW_FALSE; } LWDEBUGF(2, "pt_in_ring_2d called with point: %g %g", p->x, p->y); /* printPA(ring); */ /* loop through all edges of the polygon */ getPoint2d_p(ring, 0, &v1); for (i=0; i<ring->npoints-1; i++) { double vt; getPoint2d_p(ring, i+1, &v2); /* 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; } LWDEBUGF(3, "pt_in_ring_2d returning %d", cn&1); return (cn&1); /* 0 if even (out), and 1 if odd (in) */ }
/** point to point calculation */ int lw_dist2d_point_point(LWPOINT *point1, LWPOINT *point2, DISTPTS *dl) { POINT2D p1; POINT2D p2; getPoint2d_p(point1->point, 0, &p1); getPoint2d_p(point2->point, 0, &p2); return lw_dist2d_pt_pt(&p1, &p2,dl); }
static size_t assvg_point_buf(const LWPOINT *point, char * output, int circle, int precision) { char *ptr=output; char x[OUT_MAX_DIGS_DOUBLE+OUT_MAX_DOUBLE_PRECISION+1]; char y[OUT_MAX_DIGS_DOUBLE+OUT_MAX_DOUBLE_PRECISION+1]; POINT2D pt; getPoint2d_p(point->point, 0, &pt); if (fabs(pt.x) < OUT_MAX_DOUBLE) sprintf(x, "%.*f", precision, pt.x); else sprintf(x, "%g", pt.x); trim_trailing_zeros(x); /* SVG Y axis is reversed, an no need to transform 0 into -0 */ if (fabs(pt.y) < OUT_MAX_DOUBLE) sprintf(y, "%.*f", precision, fabs(pt.y) ? pt.y * -1 : pt.y); else sprintf(y, "%g", fabs(pt.y) ? pt.y * -1 : pt.y); trim_trailing_zeros(y); if (circle) ptr += sprintf(ptr, "x=\"%s\" y=\"%s\"", x, y); else ptr += sprintf(ptr, "cx=\"%s\" cy=\"%s\"", x, y); return (ptr-output); }
/* * return 0 iff point outside polygon or on boundary * return 1 iff point inside polygon */ int point_in_polygon_rtree(RTREE_NODE **root, int ringCount, LWPOINT *point) { int i; POINT2D pt; POSTGIS_DEBUGF(2, "point_in_polygon called for %p %d %p.", root, ringCount, point); getPoint2d_p(point->point, 0, &pt); /* assume bbox short-circuit has already been attempted */ if (point_in_ring_rtree(root[0], &pt) != 1) { POSTGIS_DEBUG(3, "point_in_polygon_rtree: outside exterior ring."); return 0; } for (i=1; i<ringCount; i++) { if (point_in_ring_rtree(root[i], &pt) != -1) { POSTGIS_DEBUGF(3, "point_in_polygon_rtree: within hole %d.", i); return 0; } } return 1; }
/** * Serializes a LWPOINT to a char*. This is a helper function that partially * writes the appropriate draw and fill commands used to generate an SVG image * using ImageMagick's "convert" command. * @param output a char reference to write the LWPOINT to * @param lwp a reference to a LWPOINT * @return the numbers of character written to *output */ static size_t drawPoint(char *output, LWPOINT *lwp, LAYERSTYLE *styles) { char x[MAX_DIGS_DOUBLE+MAX_DOUBLE_PRECISION+1]; char y1[MAX_DIGS_DOUBLE+MAX_DOUBLE_PRECISION+1]; char y2[MAX_DIGS_DOUBLE+MAX_DOUBLE_PRECISION+1]; char *ptr = output; POINTARRAY *pa = lwp->point; POINT2D p; getPoint2d_p(pa, 0, &p); LWDEBUGF(4, "%s", "drawPoint called"); LWDEBUGF( 4, "point = %s", lwgeom_to_ewkt((LWGEOM*)lwp,0) ); sprintf(x, "%f", p.x); trim_trailing_zeros(x); sprintf(y1, "%f", p.y); trim_trailing_zeros(y1); sprintf(y2, "%f", p.y + styles->pointSize); trim_trailing_zeros(y2); ptr += sprintf(ptr, "-fill %s -strokewidth 0 ", styles->pointColor); ptr += sprintf(ptr, "-draw \"circle %s,%s %s,%s", x, y1, x, y2); ptr += sprintf(ptr, "'\" "); return (ptr - output); }
/* * return -1 if point outside polygon * return 0 if point on boundary * return 1 if point inside polygon * * Expected **root order is each exterior ring followed by its holes, eg. EIIEIIEI */ int point_in_multipolygon_rtree(RTREE_NODE **root, int polyCount, int *ringCounts, LWPOINT *point) { int i, p, r, in_ring; POINT2D pt; int result = -1; POSTGIS_DEBUGF(2, "point_in_multipolygon_rtree called for %p %d %p.", root, polyCount, point); getPoint2d_p(point->point, 0, &pt); /* assume bbox short-circuit has already been attempted */ i = 0; /* the current index into the root array */ /* is the point inside any of the sub-polygons? */ for ( p = 0; p < polyCount; p++ ) { in_ring = point_in_ring_rtree(root[i], &pt); POSTGIS_DEBUGF(4, "point_in_multipolygon_rtree: exterior ring (%d), point_in_ring returned %d", p, in_ring); if ( in_ring == -1 ) /* outside the exterior ring */ { POSTGIS_DEBUG(3, "point_in_multipolygon_rtree: outside exterior ring."); } else if ( in_ring == 0 ) /* on the boundary */ { POSTGIS_DEBUGF(3, "point_in_multipolygon_rtree: on edge of exterior ring %d", p); return 0; } else { result = in_ring; for(r=1; r<ringCounts[p]; r++) { in_ring = point_in_ring_rtree(root[i+r], &pt); POSTGIS_DEBUGF(4, "point_in_multipolygon_rtree: interior ring (%d), point_in_ring returned %d", r, in_ring); if (in_ring == 1) /* inside a hole => outside the polygon */ { POSTGIS_DEBUGF(3, "point_in_multipolygon_rtree: within hole %d of exterior ring %d", r, p); result = -1; break; } if (in_ring == 0) /* on the edge of a hole */ { POSTGIS_DEBUGF(3, "point_in_multipolygon_rtree: on edge of hole %d of exterior ring %d", r, p); return 0; } } /* if we have a positive result, we can short-circuit and return it */ if ( result != -1) { return result; } } /* increment the index by the total number of rings in the sub-poly */ /* we do this here in case we short-cutted out of the poly before looking at all the rings */ i += ringCounts[p]; } return result; /* -1 = outside, 0 = boundary, 1 = inside */ }
static void ptarray_dp_findsplit(POINTARRAY *pts, int p1, int p2, int *split, double *dist) { int k; POINT2D pa, pb, pk; double tmp; LWDEBUG(4, "function called"); *dist = -1; *split = p1; if (p1 + 1 < p2) { getPoint2d_p(pts, p1, &pa); getPoint2d_p(pts, p2, &pb); LWDEBUGF(4, "P%d(%f,%f) to P%d(%f,%f)", p1, pa.x, pa.y, p2, pb.x, pb.y); for (k=p1+1; k<p2; k++) { getPoint2d_p(pts, k, &pk); LWDEBUGF(4, "P%d(%f,%f)", k, pk.x, pk.y); /* distance computation */ tmp = distance2d_pt_seg(&pk, &pa, &pb); if (tmp > *dist) { *dist = tmp; /* record the maximum */ *split = k; LWDEBUGF(4, "P%d is farthest (%g)", k, *dist); } } } /* length---should be redone if can == 0 */ else { LWDEBUG(3, "segment too short, no split/no dist"); } }
/** * Find the 2d length of the given #POINTARRAY (even if it's 3d) */ double ptarray_length_2d(const POINTARRAY *pts) { double dist = 0.0; int i; POINT2D frm; POINT2D to; if ( pts->npoints < 2 ) return 0.0; for (i=0; i<pts->npoints-1; i++) { getPoint2d_p(pts, i, &frm); getPoint2d_p(pts, i+1, &to); dist += sqrt( ( (frm.x - to.x)*(frm.x - to.x) ) + ((frm.y - to.y)*(frm.y - to.y) ) ); } return dist; }
/** point to line calculation */ int lw_dist2d_point_line(LWPOINT *point, LWLINE *line, DISTPTS *dl) { POINT2D p; POINTARRAY *pa = line->points; LWDEBUG(2, "lw_dist2d_point_line is called"); getPoint2d_p(point->point, 0, &p); return lw_dist2d_pt_ptarray(&p, pa, dl); }
/* * return -1 iff point outside multipolygon * return 0 iff point on multipolygon boundary * return 1 iff point inside multipolygon */ int point_in_multipolygon(LWMPOLY *mpolygon, LWPOINT *point) { int i, j, result, in_ring; POINT2D pt; POSTGIS_DEBUG(2, "point_in_polygon called."); getPoint2d_p(point->point, 0, &pt); /* assume bbox short-circuit has already been attempted */ result = -1; for (j = 0; j < mpolygon->ngeoms; j++ ) { LWPOLY *polygon = mpolygon->geoms[j]; /* everything is outside of an empty polygon */ if ( polygon->nrings == 0 ) continue; in_ring = point_in_ring(polygon->rings[0], &pt); if ( in_ring == -1) /* outside the exterior ring */ { POSTGIS_DEBUG(3, "point_in_polygon: outside exterior ring."); continue; } if ( in_ring == 0 ) { return 0; } result = in_ring; for (i=1; i<polygon->nrings; i++) { in_ring = point_in_ring(polygon->rings[i], &pt); if (in_ring == 1) /* inside a hole => outside the polygon */ { POSTGIS_DEBUGF(3, "point_in_polygon: within hole %d.", i); result = -1; break; } if (in_ring == 0) /* on the edge of a hole */ { POSTGIS_DEBUGF(3, "point_in_polygon: on edge of hole %d.", i); return 0; } } if ( result != -1) { return result; } } return result; }
/** * Find the area of the outer ring */ double lwtriangle_area(const LWTRIANGLE *triangle) { double area=0.0; int i; POINT2D p1; POINT2D p2; if (! triangle->points->npoints) return area; /* empty triangle */ for (i=0; i < triangle->points->npoints-1; i++) { getPoint2d_p(triangle->points, i, &p1); getPoint2d_p(triangle->points, i+1, &p2); area += ( p1.x * p2.y ) - ( p1.y * p2.x ); } area /= 2.0; return fabs(area); }
/** * search all the segments of pointarray to see which one is closest to p1 * Returns minimum distance between point and pointarray */ int lw_dist2d_pt_ptarray(POINT2D *p, POINTARRAY *pa,DISTPTS *dl) { int t; POINT2D start, end; int twist = dl->twisted; LWDEBUG(2, "lw_dist2d_pt_ptarray is called"); getPoint2d_p(pa, 0, &start); for (t=1; t<pa->npoints; t++) { dl->twisted=twist; getPoint2d_p(pa, t, &end); if (!lw_dist2d_pt_seg(p, &start, &end,dl)) return LW_FALSE; if (dl->distance<=dl->tolerance && dl->mode == DIST_MIN) return LW_TRUE; /*just a check if the answer is already given*/ start = end; } return LW_TRUE; }
/** * 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) */ int lw_dist2d_point_poly(LWPOINT *point, LWPOLY *poly, DISTPTS *dl) { POINT2D p; int i; LWDEBUG(2, "lw_dist2d_point_poly called"); getPoint2d_p(point->point, 0, &p); if (dl->mode == DIST_MAX) { LWDEBUG(3, "looking for maxdistance"); return lw_dist2d_pt_ptarray(&p, poly->rings[0], dl); } /* Return distance to outer ring if not inside it */ if ( ! pt_in_ring_2d(&p, poly->rings[0]) ) { LWDEBUG(3, "first point not inside outer-ring"); return lw_dist2d_pt_ptarray(&p, poly->rings[0], dl); } /* * 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]) ) { LWDEBUG(3, " inside an hole"); return lw_dist2d_pt_ptarray(&p, poly->rings[i], dl); } } LWDEBUG(3, " inside the polygon"); if (dl->mode == DIST_MIN) { dl->distance=0.0; dl->p1.x=p.x; dl->p1.y=p.y; dl->p2.x=p.x; dl->p2.y=p.y; } return LW_TRUE; /* Is inside the polygon */ }
Datum LWGEOM_y_point(PG_FUNCTION_ARGS) { PG_LWGEOM *geom; LWPOINT *point = NULL; POINT2D p; geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); if ( TYPE_GETTYPE(geom->type) != POINTTYPE ) lwerror("Argument to Y() must be a point"); point = lwgeom_getpoint(SERIALIZED_FORM(geom), 0); getPoint2d_p(point->point, 0, &p); PG_FREE_IF_COPY(geom, 0); PG_RETURN_FLOAT8(p.y); }
/** test each segment of l1 against each segment of l2. */ int lw_dist2d_ptarray_ptarray(POINTARRAY *l1, POINTARRAY *l2,DISTPTS *dl) { int t,u; POINT2D start, end; POINT2D start2, end2; int twist = dl->twisted; LWDEBUGF(2, "lw_dist2d_ptarray_ptarray called (points: %d-%d)",l1->npoints, l2->npoints); if (dl->mode == DIST_MAX)/*If we are searching for maxdistance we go straight to point-point calculation since the maxdistance have to be between two vertexes*/ { for (t=0; t<l1->npoints; t++) /*for each segment in L1 */ { getPoint2d_p(l1, t, &start); for (u=0; u<l2->npoints; u++) /*for each segment in L2 */ { getPoint2d_p(l2, u, &start2); lw_dist2d_pt_pt(&start,&start2,dl); LWDEBUGF(4, "maxdist_ptarray_ptarray; seg %i * seg %i, dist = %g\n",t,u,dl->distance); LWDEBUGF(3, " seg%d-seg%d dist: %f, mindist: %f", t, u, dl->distance, dl->tolerance); } } } else { getPoint2d_p(l1, 0, &start); for (t=1; t<l1->npoints; t++) /*for each segment in L1 */ { getPoint2d_p(l1, t, &end); getPoint2d_p(l2, 0, &start2); for (u=1; u<l2->npoints; u++) /*for each segment in L2 */ { getPoint2d_p(l2, u, &end2); dl->twisted=twist; lw_dist2d_seg_seg(&start, &end, &start2, &end2,dl); LWDEBUGF(4, "mindist_ptarray_ptarray; seg %i * seg %i, dist = %g\n",t,u,dl->distance); LWDEBUGF(3, " seg%d-seg%d dist: %f, mindist: %f", t, u, dl->distance, dl->tolerance); if (dl->distance<=dl->tolerance && dl->mode == DIST_MIN) return LW_TRUE; /*just a check if the answer is already given*/ start2 = end2; } start = end; } } return LW_TRUE; }
/** * Writes the coordinates of a POINTARRAY to a char* where ordinates are * separated by a comma and coordinates by a space so that the coordinate * pairs can be interpreted by ImageMagick's SVG draw command. * * @param output a reference to write the POINTARRAY to * @param pa a reference to a POINTARRAY * @return the numbers of character written to *output */ static size_t pointarrayToString(char *output, POINTARRAY *pa) { char x[MAX_DIGS_DOUBLE+MAX_DOUBLE_PRECISION+1]; char y[MAX_DIGS_DOUBLE+MAX_DOUBLE_PRECISION+1]; int i; char *ptr = output; for ( i=0; i < pa->npoints; i++ ) { POINT2D pt; getPoint2d_p(pa, i, &pt); sprintf(x, "%f", pt.x); trim_trailing_zeros(x); sprintf(y, "%f", pt.y); trim_trailing_zeros(y); if ( i ) ptr += sprintf(ptr, " "); ptr += sprintf(ptr, "%s,%s", x, y); } return (ptr - output); }
/** * Returns maximum size of rendered pointarray in bytes. */ static size_t pointArray_svg_abs(POINTARRAY *pa, char *output, int close_ring, int precision) { int i, end; char *ptr; char x[OUT_MAX_DIGS_DOUBLE+OUT_MAX_DOUBLE_PRECISION+1]; char y[OUT_MAX_DIGS_DOUBLE+OUT_MAX_DOUBLE_PRECISION+1]; POINT2D pt; ptr = output; if (close_ring) end = pa->npoints; else end = pa->npoints - 1; for (i=0 ; i < end ; i++) { getPoint2d_p(pa, i, &pt); if (fabs(pt.x) < OUT_MAX_DOUBLE) sprintf(x, "%.*f", precision, pt.x); else sprintf(x, "%g", pt.x); trim_trailing_zeros(x); /* SVG Y axis is reversed, an no need to transform 0 into -0 */ if (fabs(pt.y) < OUT_MAX_DOUBLE) sprintf(y, "%.*f", precision, fabs(pt.y) ? pt.y * -1:pt.y); else sprintf(y, "%g", fabs(pt.y) ? pt.y * -1:pt.y); trim_trailing_zeros(y); if (i == 1) ptr += sprintf(ptr, " L "); else if (i) ptr += sprintf(ptr, " "); ptr += sprintf(ptr,"%s %s", x, y); } return (ptr-output); }
Datum LWGEOM_x_point(PG_FUNCTION_ARGS) { GSERIALIZED *geom; LWGEOM *lwgeom; LWPOINT *point = NULL; POINT2D p; geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); if ( gserialized_get_type(geom) != POINTTYPE ) lwerror("Argument to X() must be a point"); lwgeom = lwgeom_from_gserialized(geom); point = lwgeom_as_lwpoint(lwgeom); if ( lwgeom_is_empty(lwgeom) ) PG_RETURN_NULL(); getPoint2d_p(point->point, 0, &p); PG_FREE_IF_COPY(geom, 0); PG_RETURN_FLOAT8(p.x); }
/* * return -1 iff point outside polygon * return 0 iff point on boundary * return 1 iff point inside polygon */ int point_in_polygon(LWPOLY *polygon, LWPOINT *point) { int i, result, in_ring; POINTARRAY *ring; POINT2D pt; POSTGIS_DEBUG(2, "point_in_polygon called."); getPoint2d_p(point->point, 0, &pt); /* assume bbox short-circuit has already been attempted */ ring = polygon->rings[0]; in_ring = point_in_ring(polygon->rings[0], &pt); if ( in_ring == -1) /* outside the exterior ring */ { POSTGIS_DEBUG(3, "point_in_polygon: outside exterior ring."); return -1; } result = in_ring; for (i=1; i<polygon->nrings; i++) { ring = polygon->rings[i]; in_ring = point_in_ring(polygon->rings[i], &pt); if (in_ring == 1) /* inside a hole => outside the polygon */ { POSTGIS_DEBUGF(3, "point_in_polygon: within hole %d.", i); return -1; } if (in_ring == 0) /* on the edge of a hole */ { POSTGIS_DEBUGF(3, "point_in_polygon: on edge of hole %d.", i); return 0; } } return result; /* -1 = outside, 0 = boundary, 1 = inside */ }
/** In X3D3, coordinates are separated by a space separator */ static size_t pointArray_toX3D3(POINTARRAY *pa, char *output, int precision, int opts, int is_closed) { int i; char *ptr; char x[OUT_MAX_DIGS_DOUBLE+OUT_MAX_DOUBLE_PRECISION+1]; char y[OUT_MAX_DIGS_DOUBLE+OUT_MAX_DOUBLE_PRECISION+1]; char z[OUT_MAX_DIGS_DOUBLE+OUT_MAX_DOUBLE_PRECISION+1]; ptr = output; if ( ! FLAGS_GET_Z(pa->flags) ) { for (i=0; i<pa->npoints; i++) { /** Only output the point if it is not the last point of a closed object or it is a non-closed type **/ if ( !is_closed || i < (pa->npoints - 1) ) { POINT2D pt; getPoint2d_p(pa, i, &pt); if (fabs(pt.x) < OUT_MAX_DOUBLE) sprintf(x, "%.*f", precision, pt.x); else sprintf(x, "%g", pt.x); trim_trailing_zeros(x); if (fabs(pt.y) < OUT_MAX_DOUBLE) sprintf(y, "%.*f", precision, pt.y); else sprintf(y, "%g", pt.y); trim_trailing_zeros(y); if ( i ) ptr += sprintf(ptr, " "); ptr += sprintf(ptr, "%s %s", x, y); } } } else { for (i=0; i<pa->npoints; i++) { /** Only output the point if it is not the last point of a closed object or it is a non-closed type **/ if ( !is_closed || i < (pa->npoints - 1) ) { POINT4D pt; getPoint4d_p(pa, i, &pt); if (fabs(pt.x) < OUT_MAX_DOUBLE) sprintf(x, "%.*f", precision, pt.x); else sprintf(x, "%g", pt.x); trim_trailing_zeros(x); if (fabs(pt.y) < OUT_MAX_DOUBLE) sprintf(y, "%.*f", precision, pt.y); else sprintf(y, "%g", pt.y); trim_trailing_zeros(y); if (fabs(pt.z) < OUT_MAX_DOUBLE) sprintf(z, "%.*f", precision, pt.z); else sprintf(z, "%g", pt.z); trim_trailing_zeros(z); if ( i ) ptr += sprintf(ptr, " "); ptr += sprintf(ptr, "%s %s %s", x, y, z); } } } return ptr-output; }
/* * return -1 iff point is outside ring pts * return 1 iff point is inside ring pts * return 0 iff point is on ring pts */ int point_in_ring_rtree(RTREE_NODE *root, POINT2D *point) { int wn = 0; int i; double side; POINT2D seg1; POINT2D seg2; LWMLINE *lines; POSTGIS_DEBUG(2, "point_in_ring called."); lines = findLineSegments(root, point->y); if (!lines) return -1; for (i=0; i<lines->ngeoms; i++) { getPoint2d_p(lines->geoms[i]->points, 0, &seg1); getPoint2d_p(lines->geoms[i]->points, 1, &seg2); side = determineSide(&seg1, &seg2, point); POSTGIS_DEBUGF(3, "segment: (%.8f, %.8f),(%.8f, %.8f)", seg1.x, seg1.y, seg2.x, seg2.y); POSTGIS_DEBUGF(3, "side result: %.8f", side); POSTGIS_DEBUGF(3, "counterclockwise wrap %d, clockwise wrap %d", FP_CONTAINS_BOTTOM(seg1.y,point->y,seg2.y), FP_CONTAINS_BOTTOM(seg2.y,point->y,seg1.y)); /* zero length segments are ignored. */ if (((seg2.x-seg1.x)*(seg2.x-seg1.x)+(seg2.y-seg1.y)*(seg2.y-seg1.y)) < 1e-12*1e-12) { POSTGIS_DEBUG(3, "segment is zero length... ignoring."); continue; } /* a point on the boundary of a ring is not contained. */ if (fabs(side) < 1e-12) { if (isOnSegment(&seg1, &seg2, point) == 1) { POSTGIS_DEBUGF(3, "point on ring boundary between points %d, %d", i, i+1); return 0; } } /* * If the point is to the left of the line, and it's rising, * then the line is to the right of the point and * circling counter-clockwise, so incremement. */ if (FP_CONTAINS_BOTTOM(seg1.y,point->y,seg2.y) && side>0) { POSTGIS_DEBUG(3, "incrementing winding number."); ++wn; } /* * If the point is to the right of the line, and it's falling, * then the line is to the right of the point and circling * clockwise, so decrement. */ else if (FP_CONTAINS_BOTTOM(seg2.y,point->y,seg1.y) && side<0) { POSTGIS_DEBUG(3, "decrementing winding number."); --wn; } } POSTGIS_DEBUGF(3, "winding number %d", wn); if (wn == 0) return -1; return 1; }
LWPOLY * lwpoly_grid(LWPOLY *poly, gridspec *grid) { LWPOLY *opoly; int ri; POINTARRAY **newrings = NULL; int nrings = 0; double minvisiblearea; /* * TODO: control this assertion * it is assumed that, since the grid size will be a pixel, * a visible ring should show at least a white pixel inside, * thus, for a square, that would be grid_xsize*grid_ysize */ minvisiblearea = grid->xsize * grid->ysize; nrings = 0; POSTGIS_DEBUGF(3, "grid_polygon3d: applying grid to polygon with %d rings", poly->nrings); for (ri=0; ri<poly->nrings; ri++) { POINTARRAY *ring = poly->rings[ri]; POINTARRAY *newring; #if POSTGIS_DEBUG_LEVEL >= 4 POINT2D p1, p2; getPoint2d_p(ring, 0, &p1); getPoint2d_p(ring, ring->npoints-1, &p2); if ( ! SAMEPOINT(&p1, &p2) ) POSTGIS_DEBUG(4, "Before gridding: first point != last point"); #endif newring = ptarray_grid(ring, grid); /* Skip ring if not composed by at least 4 pts (3 segments) */ if ( newring->npoints < 4 ) { pfree(newring); POSTGIS_DEBUGF(3, "grid_polygon3d: ring%d skipped ( <4 pts )", ri); if ( ri ) continue; else break; /* this is the external ring, no need to work on holes */ } #if POSTGIS_DEBUG_LEVEL >= 4 getPoint2d_p(newring, 0, &p1); getPoint2d_p(newring, newring->npoints-1, &p2); if ( ! SAMEPOINT(&p1, &p2) ) POSTGIS_DEBUG(4, "After gridding: first point != last point"); #endif POSTGIS_DEBUGF(3, "grid_polygon3d: ring%d simplified from %d to %d points", ri, ring->npoints, newring->npoints); /* * Add ring to simplified ring array * (TODO: dinamic allocation of pts_per_ring) */ if ( ! nrings ) { newrings = palloc(sizeof(POINTARRAY *)); } else { newrings = repalloc(newrings, sizeof(POINTARRAY *)*(nrings+1)); } if ( ! newrings ) { elog(ERROR, "Out of virtual memory"); return NULL; } newrings[nrings++] = newring; } POSTGIS_DEBUGF(3, "grid_polygon3d: simplified polygon with %d rings", nrings); if ( ! nrings ) return NULL; opoly = lwpoly_construct(poly->srid, NULL, nrings, newrings); return opoly; }
/* * Given a point, returns the location of closest point on pointarray * and, optionally, it's actual distance from the point array. */ double ptarray_locate_point(const POINTARRAY *pa, const POINT4D *p4d, double *mindistout, POINT4D *proj4d) { double mindist=-1; double tlen, plen; int t, seg=-1; POINT4D start4d, end4d, projtmp; POINT2D start, end, proj, p; /* Initialize our 2D copy of the input parameter */ p.x = p4d->x; p.y = p4d->y; if ( ! proj4d ) proj4d = &projtmp; getPoint2d_p(pa, 0, &start); for (t=1; t<pa->npoints; t++) { double dist; getPoint2d_p(pa, t, &end); dist = distance2d_pt_seg(&p, &start, &end); if (t==1 || dist < mindist ) { mindist = dist; seg=t-1; } if ( mindist == 0 ) { LWDEBUG(3, "Breaking on mindist=0"); break; } start = end; } if ( mindistout ) *mindistout = mindist; LWDEBUGF(3, "Closest segment: %d", seg); LWDEBUGF(3, "mindist: %g", mindist); /* * We need to project the * point on the closest segment. */ getPoint4d_p(pa, seg, &start4d); getPoint4d_p(pa, seg+1, &end4d); closest_point_on_segment(p4d, &start4d, &end4d, proj4d); /* Copy 4D values into 2D holder */ proj.x = proj4d->x; proj.y = proj4d->y; LWDEBUGF(3, "Closest segment:%d, npoints:%d", seg, pa->npoints); /* For robustness, force 1 when closest point == endpoint */ if ( (seg >= (pa->npoints-2)) && p2d_same(&proj, &end) ) { return 1.0; } LWDEBUGF(3, "Closest point on segment: %g,%g", proj.x, proj.y); tlen = ptarray_length_2d(pa); LWDEBUGF(3, "tlen %g", tlen); /* Location of any point on a zero-length line is 0 */ /* See http://trac.osgeo.org/postgis/ticket/1772#comment:2 */ if ( tlen == 0 ) return 0; plen=0; getPoint2d_p(pa, 0, &start); for (t=0; t<seg; t++, start=end) { getPoint2d_p(pa, t+1, &end); plen += distance2d_pt_pt(&start, &end); LWDEBUGF(4, "Segment %d made plen %g", t, plen); } plen+=distance2d_pt_pt(&proj, &start); LWDEBUGF(3, "plen %g, tlen %g", plen, tlen); return plen/tlen; }
int ptarray_append_ptarray(POINTARRAY *pa1, POINTARRAY *pa2, double gap_tolerance) { unsigned int poff = 0; unsigned int npoints; unsigned int ncap; unsigned int ptsize; /* Check for pathology */ if( ! pa1 || ! pa2 ) { lwerror("ptarray_append_ptarray: null input"); return LW_FAILURE; } npoints = pa2->npoints; if ( ! npoints ) return LW_SUCCESS; /* nothing more to do */ if( FLAGS_GET_READONLY(pa1->flags) ) { lwerror("ptarray_append_ptarray: target pointarray is read-only"); return LW_FAILURE; } if( FLAGS_GET_ZM(pa1->flags) != FLAGS_GET_ZM(pa2->flags) ) { lwerror("ptarray_append_ptarray: appending mixed dimensionality is not allowed"); return LW_FAILURE; } ptsize = ptarray_point_size(pa1); /* Check for duplicate end point */ if ( pa1->npoints ) { POINT2D tmp1, tmp2; getPoint2d_p(pa1, pa1->npoints-1, &tmp1); getPoint2d_p(pa2, 0, &tmp2); /* If the end point and start point are the same, then don't copy start point */ if (p2d_same(&tmp1, &tmp2)) { poff = 1; --npoints; } else if ( gap_tolerance == 0 || ( gap_tolerance > 0 && distance2d_pt_pt(&tmp1, &tmp2) > gap_tolerance ) ) { lwerror("Second line start point too far from first line end point"); return LW_FAILURE; } } /* Check if we need extra space */ ncap = pa1->npoints + npoints; if ( pa1->maxpoints < ncap ) { pa1->maxpoints = ncap > pa1->maxpoints*2 ? ncap : pa1->maxpoints*2; pa1->serialized_pointlist = (uint8_t *)lwrealloc(pa1->serialized_pointlist, ptsize * pa1->maxpoints); } memcpy(getPoint_internal(pa1, pa1->npoints), getPoint_internal(pa2, poff), ptsize * npoints); pa1->npoints = ncap; return LW_SUCCESS; }
static size_t pointArray_to_geojson(POINTARRAY *pa, char *output, int precision) { int i; char *ptr; char x[OUT_MAX_DIGS_DOUBLE+OUT_MAX_DOUBLE_PRECISION+1]; char y[OUT_MAX_DIGS_DOUBLE+OUT_MAX_DOUBLE_PRECISION+1]; char z[OUT_MAX_DIGS_DOUBLE+OUT_MAX_DOUBLE_PRECISION+1]; ptr = output; if (!FLAGS_GET_Z(pa->flags)) { for (i=0; i<pa->npoints; i++) { POINT2D pt; getPoint2d_p(pa, i, &pt); if (fabs(pt.x) < OUT_MAX_DOUBLE) sprintf(x, "%.*f", precision, pt.x); else sprintf(x, "%g", pt.x); trim_trailing_zeros(x); if (fabs(pt.y) < OUT_MAX_DOUBLE) sprintf(y, "%.*f", precision, pt.y); else sprintf(y, "%g", pt.y); trim_trailing_zeros(y); if ( i ) ptr += sprintf(ptr, ","); ptr += sprintf(ptr, "[%s,%s]", x, y); } } else { for (i=0; i<pa->npoints; i++) { POINT4D pt; getPoint4d_p(pa, i, &pt); if (fabs(pt.x) < OUT_MAX_DOUBLE) sprintf(x, "%.*f", precision, pt.x); else sprintf(x, "%g", pt.x); trim_trailing_zeros(x); if (fabs(pt.y) < OUT_MAX_DOUBLE) sprintf(y, "%.*f", precision, pt.y); else sprintf(y, "%g", pt.y); trim_trailing_zeros(y); if (fabs(pt.z) < OUT_MAX_DOUBLE) sprintf(z, "%.*f", precision, pt.z); else sprintf(z, "%g", pt.z); trim_trailing_zeros(z); if ( i ) ptr += sprintf(ptr, ","); ptr += sprintf(ptr, "[%s,%s,%s]", x, y, z); } } return (ptr-output); }
/* * Convenience functions to hide the POINTARRAY * TODO: obsolete this */ int lwpoint_getPoint2d_p(const LWPOINT *point, POINT2D *out) { return getPoint2d_p(point->point, 0, out); }
static double ptarray_area_spheroid(const POINTARRAY *pa, const SPHEROID *spheroid) { GEOGRAPHIC_POINT a, b; POINT2D p; int i; double area = 0.0; GBOX gbox2d; int in_south = LW_FALSE; double delta_lon_tolerance; double latitude_min; gbox2d.flags = gflags(0, 0, 0); /* Return zero on non-sensical inputs */ if ( ! pa || pa->npoints < 4 ) return 0.0; /* Get the raw min/max values for the latitudes */ ptarray_calculate_gbox(pa, &gbox2d); if ( signum(gbox2d.ymin) != signum(gbox2d.ymax) ) lwerror("ptarray_area_spheroid: cannot handle ptarray that crosses equator"); /* Geodetic bbox < 0.0 implies geometry is entirely in southern hemisphere */ if ( gbox2d.ymax < 0.0 ) in_south = LW_TRUE; LWDEBUGF(4, "gbox2d.ymax %.12g", gbox2d.ymax); /* Tolerance for strip area calculation */ if ( in_south ) { delta_lon_tolerance = (90.0 / (fabs(gbox2d.ymin) / 8.0) - 2.0) / 10000.0; latitude_min = deg2rad(fabs(gbox2d.ymax)); } else { delta_lon_tolerance = (90.0 / (fabs(gbox2d.ymax) / 8.0) - 2.0) / 10000.0; latitude_min = deg2rad(gbox2d.ymin); } /* Initialize first point */ getPoint2d_p(pa, 0, &p); geographic_point_init(p.x, p.y, &a); for ( i = 1; i < pa->npoints; i++ ) { GEOGRAPHIC_POINT a1, b1; double strip_area = 0.0; double delta_lon = 0.0; LWDEBUGF(4, "edge #%d", i); getPoint2d_p(pa, i, &p); geographic_point_init(p.x, p.y, &b); a1 = a; b1 = b; /* Flip into north if in south */ if ( in_south ) { a1.lat = -1.0 * a1.lat; b1.lat = -1.0 * b1.lat; } LWDEBUGF(4, "in_south %d", in_south); LWDEBUGF(4, "crosses_dateline(a, b) %d", crosses_dateline(&a, &b) ); if ( crosses_dateline(&a, &b) ) { double shift; if ( a1.lon > 0.0 ) shift = (M_PI - a1.lon) + 0.088; /* About 5deg more */ else shift = (M_PI - b1.lon) + 0.088; /* About 5deg more */ LWDEBUGF(4, "shift: %.8g", shift); LWDEBUGF(4, "before shift a1(%.8g %.8g) b1(%.8g %.8g)", a1.lat, a1.lon, b1.lat, b1.lon); point_shift(&a1, shift); point_shift(&b1, shift); LWDEBUGF(4, "after shift a1(%.8g %.8g) b1(%.8g %.8g)", a1.lat, a1.lon, b1.lat, b1.lon); } delta_lon = fabs(b1.lon - a1.lon); LWDEBUGF(4, "a1(%.18g %.18g) b1(%.18g %.18g)", a1.lat, a1.lon, b1.lat, b1.lon); LWDEBUGF(4, "delta_lon %.18g", delta_lon); LWDEBUGF(4, "delta_lon_tolerance %.18g", delta_lon_tolerance); if ( delta_lon > 0.0 ) { if ( delta_lon < delta_lon_tolerance ) { strip_area = spheroid_striparea(&a1, &b1, latitude_min, spheroid); LWDEBUGF(4, "strip_area %.12g", strip_area); area += strip_area; } else { GEOGRAPHIC_POINT p, q; double step = floor(delta_lon / delta_lon_tolerance); double distance = spheroid_distance(&a1, &b1, spheroid); double pDistance = 0.0; int j = 0; LWDEBUGF(4, "step %.18g", step); LWDEBUGF(4, "distance %.18g", distance); step = distance / step; LWDEBUGF(4, "step %.18g", step); p = a1; while (pDistance < (distance - step * 1.01)) { double azimuth = spheroid_direction(&p, &b1, spheroid); j++; LWDEBUGF(4, " iteration %d", j); LWDEBUGF(4, " azimuth %.12g", azimuth); pDistance = pDistance + step; LWDEBUGF(4, " pDistance %.12g", pDistance); spheroid_project(&p, spheroid, step, azimuth, &q); strip_area = spheroid_striparea(&p, &q, latitude_min, spheroid); LWDEBUGF(4, " strip_area %.12g", strip_area); area += strip_area; LWDEBUGF(4, " area %.12g", area); p.lat = q.lat; p.lon = q.lon; } strip_area = spheroid_striparea(&p, &b1, latitude_min, spheroid); area += strip_area; } } /* B gets incremented in the next loop, so we save the value here */ a = b; } return fabs(area); }
/** ** @brief lwline_crossing_direction: returns the kind of #CG_LINE_CROSS_TYPE behavior of 2 linestrings ** @param l1 first line string ** @param l2 second line string ** @return a #CG_LINE_CROSS_TYPE ** LINE_NO_CROSS = 0 ** LINE_CROSS_LEFT = -1 ** LINE_CROSS_RIGHT = 1 ** LINE_MULTICROSS_END_LEFT = -2 ** LINE_MULTICROSS_END_RIGHT = 2 ** LINE_MULTICROSS_END_SAME_FIRST_LEFT = -3 ** LINE_MULTICROSS_END_SAME_FIRST_RIGHT = 3 ** */ int lwline_crossing_direction(const LWLINE *l1, const LWLINE *l2) { int i = 0, j = 0, rv = 0; POINT2D p1, p2, q1, q2; POINTARRAY *pa1 = NULL, *pa2 = NULL; int cross_left = 0; int cross_right = 0; int first_cross = 0; int this_cross = 0; pa1 = (POINTARRAY*)l1->points; pa2 = (POINTARRAY*)l2->points; /* One-point lines can't intersect (and shouldn't exist). */ if ( pa1->npoints < 2 || pa2->npoints < 2 ) return LINE_NO_CROSS; LWDEBUGF(4, "l1 = %s", lwgeom_to_ewkt((LWGEOM*)l1)); LWDEBUGF(4, "l2 = %s", lwgeom_to_ewkt((LWGEOM*)l2)); /* Initialize first point of q */ rv = getPoint2d_p(pa2, 0, &q1); for ( i = 1; i < pa2->npoints; i++ ) { /* Update second point of q to next value */ rv = getPoint2d_p(pa2, i, &q2); /* Initialize first point of p */ rv = getPoint2d_p(pa1, 0, &p1); for ( j = 1; j < pa1->npoints; j++ ) { /* Update second point of p to next value */ rv = getPoint2d_p(pa1, j, &p2); this_cross = lw_segment_intersects(&p1, &p2, &q1, &q2); LWDEBUGF(4, "i=%d, j=%d (%.8g %.8g, %.8g %.8g)", this_cross, i, j, p1.x, p1.y, p2.x, p2.y); if ( this_cross == SEG_CROSS_LEFT ) { LWDEBUG(4,"this_cross == SEG_CROSS_LEFT"); cross_left++; if ( ! first_cross ) first_cross = SEG_CROSS_LEFT; } if ( this_cross == SEG_CROSS_RIGHT ) { LWDEBUG(4,"this_cross == SEG_CROSS_RIGHT"); cross_right++; if ( ! first_cross ) first_cross = SEG_CROSS_LEFT; } /* ** Crossing at a co-linearity can be turned handled by extending ** segment to next vertext and seeing if the end points straddle ** the co-linear segment. */ if ( this_cross == SEG_COLINEAR ) { LWDEBUG(4,"this_cross == SEG_COLINEAR"); /* TODO: Add logic here and in segment_intersects() continue; */ } LWDEBUG(4,"this_cross == SEG_NO_INTERSECTION"); /* Turn second point of p into first point */ p1 = p2; } /* Turn second point of q into first point */ q1 = q2; } LWDEBUGF(4, "first_cross=%d, cross_left=%d, cross_right=%d", first_cross, cross_left, cross_right); if ( !cross_left && !cross_right ) return LINE_NO_CROSS; if ( !cross_left && cross_right == 1 ) return LINE_CROSS_RIGHT; if ( !cross_right && cross_left == 1 ) return LINE_CROSS_LEFT; if ( cross_left - cross_right == 1 ) return LINE_MULTICROSS_END_LEFT; if ( cross_left - cross_right == -1 ) return LINE_MULTICROSS_END_RIGHT; if ( cross_left - cross_right == 0 && first_cross == SEG_CROSS_LEFT ) return LINE_MULTICROSS_END_SAME_FIRST_LEFT; if ( cross_left - cross_right == 0 && first_cross == SEG_CROSS_RIGHT ) return LINE_MULTICROSS_END_SAME_FIRST_RIGHT; return LINE_NO_CROSS; }