/* ** The suite initialization function. ** Create any re-used objects. */ static int init_cg_suite(void) { pa21 = ptarray_construct(0, 0, 2); pa22 = ptarray_construct(0, 0, 2); l21 = lwline_construct(SRID_UNKNOWN, NULL, pa21); l22 = lwline_construct(SRID_UNKNOWN, NULL, pa22); return 0; }
/* * Construct a LWLINE from a LWMPOINT */ LWLINE * lwline_from_lwmpoint(int SRID, LWMPOINT *mpoint) { unsigned int i; POINTARRAY *pa; char zmflag = TYPE_GETZM(mpoint->type); size_t ptsize, size; uchar *newpoints, *ptr; if ( zmflag == 0 ) ptsize=2*sizeof(double); else if ( zmflag == 3 ) ptsize=4*sizeof(double); else ptsize=3*sizeof(double); /* Allocate space for output points */ size = ptsize*mpoint->ngeoms; newpoints = lwalloc(size); memset(newpoints, 0, size); ptr=newpoints; for (i=0; i<mpoint->ngeoms; i++) { memcpy(ptr, getPoint_internal(mpoint->geoms[i]->point, 0), ptsize); ptr+=ptsize; } pa = pointArray_construct(newpoints, zmflag&2, zmflag&1, mpoint->ngeoms); LWDEBUGF(3, "lwline_from_lwmpoint: constructed pointarray for %d points, %d zmflag", mpoint->ngeoms, zmflag); return lwline_construct(SRID, NULL, pa); }
/** * LINESTRING */ static LWLINE* lwline_from_twkb_state(twkb_parse_state *s) { uint32_t npoints; POINTARRAY *pa; LWDEBUG(2,"Entering lwline_from_twkb_state"); if ( s->is_empty ) return lwline_construct_empty(SRID_UNKNOWN, s->has_z, s->has_m); /* Read number of points */ npoints = twkb_parse_state_uvarint(s); if ( npoints == 0 ) return lwline_construct_empty(SRID_UNKNOWN, s->has_z, s->has_m); /* Read coordinates */ pa = ptarray_from_twkb_state(s, npoints); if( pa == NULL ) return lwline_construct_empty(SRID_UNKNOWN, s->has_z, s->has_m); if( s->check & LW_PARSER_CHECK_MINPOINTS && pa->npoints < 2 ) { lwerror("%s must have at least two points", lwtype_name(s->lwtype)); return NULL; } return lwline_construct(SRID_UNKNOWN, NULL, pa); }
/** * Create a new linestring. Null point array implies empty. Null dimensionality * implies no specified dimensionality in the WKT. Check for numpoints >= 2 if * requested. */ LWGEOM* wkt_parser_linestring_new(POINTARRAY *pa, char *dimensionality) { uint8_t flags = wkt_dimensionality(dimensionality); LWDEBUG(4,"entered"); /* No pointarray means it is empty */ if( ! pa ) return lwline_as_lwgeom(lwline_construct_empty(SRID_UNKNOWN, FLAGS_GET_Z(flags), FLAGS_GET_M(flags))); /* If the number of dimensions is not consistent, we have a problem. */ if( wkt_pointarray_dimensionality(pa, flags) == LW_FALSE ) { ptarray_free(pa); SET_PARSER_ERROR(PARSER_ERROR_MIXDIMS); return NULL; } /* Apply check for not enough points, if requested. */ if( (global_parser_result.parser_check_flags & LW_PARSER_CHECK_MINPOINTS) && (pa->npoints < 2) ) { ptarray_free(pa); SET_PARSER_ERROR(PARSER_ERROR_MOREPOINTS); return NULL; } return lwline_as_lwgeom(lwline_construct(SRID_UNKNOWN, NULL, pa)); }
static void test_lwline_clip_big(void) { POINTARRAY *pa = ptarray_construct(1, 0, 3); LWLINE *line = lwline_construct(SRID_UNKNOWN, NULL, pa); LWCOLLECTION *c; char *ewkt; POINT4D p; p.x = 0.0; p.y = 0.0; p.z = 0.0; ptarray_set_point4d(pa, 0, &p); p.x = 1.0; p.y = 1.0; p.z = 1.0; ptarray_set_point4d(pa, 1, &p); p.x = 2.0; p.y = 2.0; p.z = 2.0; ptarray_set_point4d(pa, 2, &p); c = lwline_clip_to_ordinate_range(line, 'Z', 0.5, 1.5); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((0.5 0.5 0.5,1 1 1,1.5 1.5 1.5))" ); lwfree(ewkt); lwcollection_free(c); lwline_free(line); }
static LWGEOM* parse_geojson_linestring(json_object *geojson, bool *hasz, int *root_srid) { LWGEOM *geom; POINTARRAY *pa; json_object* points = NULL; int i = 0; POSTGIS_DEBUG(2, "parse_geojson_linestring called."); points = findMemberByName( geojson, "coordinates" ); if ( ! points ) geojson_lwerror("Unable to find 'coordinates' in GeoJSON string", 4); pa = ptarray_construct_empty(1, 0, 1); if( json_type_array == json_object_get_type( points ) ) { const int nPoints = json_object_array_length( points ); for(i = 0; i < nPoints; ++i) { json_object* coords = NULL; coords = json_object_array_get_idx( points, i ); parse_geojson_coord(coords, hasz, pa); } } geom = (LWGEOM *) lwline_construct(*root_srid, NULL, pa); POSTGIS_DEBUG(2, "parse_geojson_linestring finished."); return geom; }
LWMLINE * lwmcurve_segmentize(LWMCURVE *mcurve, uint32_t perQuad) { LWMLINE *ogeom; LWGEOM *tmp; LWGEOM **lines; int i; LWDEBUGF(2, "lwmcurve_segmentize called, geoms=%d, dim=%d.", mcurve->ngeoms, FLAGS_NDIMS(mcurve->flags)); lines = lwalloc(sizeof(LWGEOM *)*mcurve->ngeoms); for (i = 0; i < mcurve->ngeoms; i++) { tmp = mcurve->geoms[i]; if (tmp->type == CIRCSTRINGTYPE) { lines[i] = (LWGEOM *)lwcircstring_segmentize((LWCIRCSTRING *)tmp, perQuad); } else if (tmp->type == LINETYPE) { lines[i] = (LWGEOM *)lwline_construct(mcurve->srid, NULL, ptarray_clone_deep(((LWLINE *)tmp)->points)); } else { lwerror("Unsupported geometry found in MultiCurve."); return NULL; } } ogeom = (LWMLINE *)lwcollection_construct(MULTILINETYPE, mcurve->srid, NULL, mcurve->ngeoms, lines); return ogeom; }
/** * Re-write the measure ordinate (or add one, if it isn't already there) interpolating * the measure between the supplied start and end values. */ LWLINE* lwline_measured_from_lwline(const LWLINE *lwline, double m_start, double m_end) { int i = 0; int hasm = 0, hasz = 0; int npoints = 0; double length = 0.0; double length_so_far = 0.0; double m_range = m_end - m_start; double m; POINTARRAY *pa = NULL; POINT3DZ p1, p2; if ( TYPE_GETTYPE(lwline->type) != LINETYPE ) { lwerror("lwline_construct_from_lwline: only line types supported"); return NULL; } hasz = TYPE_HASZ(lwline->type); hasm = 1; /* Null points or npoints == 0 will result in empty return geometry */ if ( lwline->points ) { npoints = lwline->points->npoints; length = lwgeom_pointarray_length2d(lwline->points); getPoint3dz_p(lwline->points, 0, &p1); } pa = ptarray_construct(hasz, hasm, npoints); for ( i = 0; i < npoints; i++ ) { POINT4D q; POINT2D a, b; getPoint3dz_p(lwline->points, i, &p2); a.x = p1.x; a.y = p1.y; b.x = p2.x; b.y = p2.y; length_so_far += distance2d_pt_pt(&a, &b); if ( length > 0.0 ) m = m_start + m_range * length_so_far / length; else m = 0.0; q.x = p2.x; q.y = p2.y; q.z = p2.z; q.m = m; setPoint4d(pa, i, &q); p1 = p2; } return lwline_construct(lwline->SRID, NULL, pa); }
/** * Parse KML lineString */ static LWGEOM* parse_kml_line(xmlNodePtr xnode, bool *hasz) { POINTARRAY *pa; if (xnode->children == NULL) lwerror("invalid KML representation"); pa = parse_kml_coordinates(xnode->children, hasz); if (pa->npoints < 2) lwerror("invalid KML representation"); return (LWGEOM *) lwline_construct(4326, NULL, pa); }
LWLINE * lwline_removepoint(LWLINE *line, unsigned int index) { POINTARRAY *newpa; LWLINE *ret; newpa = ptarray_removePoint(line->points, index); ret = lwline_construct(line->SRID, ptarray_compute_box2d(newpa), newpa); return ret; }
Datum LWGEOM_exteriorring_polygon(PG_FUNCTION_ARGS) { PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); LWPOLY *poly = NULL; LWCURVEPOLY *curvepoly = NULL; POINTARRAY *extring; LWGEOM *ring; LWLINE *line; PG_LWGEOM *result; BOX2DFLOAT4 *bbox=NULL; POSTGIS_DEBUG(2, "LWGEOM_exteriorring_polygon called."); if ( TYPE_GETTYPE(geom->type) != POLYGONTYPE && TYPE_GETTYPE(geom->type) != CURVEPOLYTYPE) { elog(ERROR, "ExteriorRing: geom is not a polygon"); PG_RETURN_NULL(); } if (lwgeom_getType((uchar)SERIALIZED_FORM(geom)[0]) == POLYGONTYPE) { poly = lwpoly_deserialize(SERIALIZED_FORM(geom)); /* Ok, now we have a polygon. Here is its exterior ring. */ extring = poly->rings[0]; /* * This is a LWLINE constructed by exterior ring POINTARRAY * If the input geom has a bbox, use it for * the output geom, as exterior ring makes it up ! */ if ( poly->bbox ) bbox=box2d_clone(poly->bbox); line = lwline_construct(poly->SRID, bbox, extring); result = pglwgeom_serialize((LWGEOM *)line); lwgeom_release((LWGEOM *)line); lwgeom_release((LWGEOM *)poly); } else { curvepoly = lwcurvepoly_deserialize(SERIALIZED_FORM(geom)); ring = curvepoly->rings[0]; result = pglwgeom_serialize(ring); lwgeom_release(ring); } PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(result); }
LWLINE * lwcircstring_segmentize(const LWCIRCSTRING *icurve, uint32_t perQuad) { LWLINE *oline; POINTARRAY *ptarray; POINTARRAY *tmp; uint32_t i, j; POINT4D p1, p2, p3, p4; LWDEBUGF(2, "lwcircstring_segmentize called., dim = %d", icurve->points->flags); ptarray = ptarray_construct_empty(FLAGS_GET_Z(icurve->points->flags), FLAGS_GET_M(icurve->points->flags), 64); for (i = 2; i < icurve->points->npoints; i+=2) { LWDEBUGF(3, "lwcircstring_segmentize: arc ending at point %d", i); getPoint4d_p(icurve->points, i - 2, &p1); getPoint4d_p(icurve->points, i - 1, &p2); getPoint4d_p(icurve->points, i, &p3); tmp = lwcircle_segmentize(&p1, &p2, &p3, perQuad); if (tmp) { LWDEBUGF(3, "lwcircstring_segmentize: generated %d points", tmp->npoints); for (j = 0; j < tmp->npoints; j++) { getPoint4d_p(tmp, j, &p4); ptarray_append_point(ptarray, &p4, LW_TRUE); } ptarray_free(tmp); } else { LWDEBUG(3, "lwcircstring_segmentize: points are colinear, returning curve points as line"); for (j = i - 1 ; j <= i ; j++) { getPoint4d_p(icurve->points, j, &p4); ptarray_append_point(ptarray, &p4, LW_TRUE); } } } getPoint4d_p(icurve->points, icurve->points->npoints-1, &p1); ptarray_append_point(ptarray, &p1, LW_TRUE); oline = lwline_construct(icurve->srid, NULL, ptarray); return oline; }
/* * @param icurve input curve * @param tol tolerance, semantic driven by tolerance_type * @param tolerance_type see LW_LINEARIZE_TOLERANCE_TYPE * @param flags see flags in lwarc_linearize * * @return a newly allocated LWLINE */ static LWLINE * lwcircstring_linearize(const LWCIRCSTRING *icurve, double tol, LW_LINEARIZE_TOLERANCE_TYPE tolerance_type, int flags) { LWLINE *oline; POINTARRAY *ptarray; uint32_t i, j; POINT4D p1, p2, p3, p4; int ret; LWDEBUGF(2, "lwcircstring_linearize called., dim = %d", icurve->points->flags); ptarray = ptarray_construct_empty(FLAGS_GET_Z(icurve->points->flags), FLAGS_GET_M(icurve->points->flags), 64); for (i = 2; i < icurve->points->npoints; i+=2) { LWDEBUGF(3, "lwcircstring_linearize: arc ending at point %d", i); getPoint4d_p(icurve->points, i - 2, &p1); getPoint4d_p(icurve->points, i - 1, &p2); getPoint4d_p(icurve->points, i, &p3); ret = lwarc_linearize(ptarray, &p1, &p2, &p3, tol, tolerance_type, flags); if ( ret > 0 ) { LWDEBUGF(3, "lwcircstring_linearize: generated %d points", ptarray->npoints); } else if ( ret == 0 ) { LWDEBUG(3, "lwcircstring_linearize: points are colinear, returning curve points as line"); for (j = i - 2 ; j < i ; j++) { getPoint4d_p(icurve->points, j, &p4); ptarray_append_point(ptarray, &p4, LW_TRUE); } } else { /* An error occurred, lwerror should have been called by now */ ptarray_free(ptarray); return NULL; } } getPoint4d_p(icurve->points, icurve->points->npoints-1, &p1); ptarray_append_point(ptarray, &p1, LW_TRUE); oline = lwline_construct(icurve->srid, NULL, ptarray); return oline; }
static LWGEOM* parse_geojson_multilinestring(json_object *geojson, int *hasz, int root_srid) { LWGEOM *geom = NULL; int i, j; json_object* poObjLines = NULL; if (!root_srid) { geom = (LWGEOM *)lwcollection_construct_empty(MULTILINETYPE, root_srid, 1, 0); } else { geom = (LWGEOM *)lwcollection_construct_empty(MULTILINETYPE, -1, 1, 0); } poObjLines = findMemberByName( geojson, "coordinates" ); if ( ! poObjLines ) { geojson_lwerror("Unable to find 'coordinates' in GeoJSON string", 4); return NULL; } if( json_type_array == json_object_get_type( poObjLines ) ) { const int nLines = json_object_array_length( poObjLines ); for( i = 0; i < nLines; ++i) { POINTARRAY *pa = NULL; json_object* poObjLine = NULL; poObjLine = json_object_array_get_idx( poObjLines, i ); pa = ptarray_construct_empty(1, 0, 1); if( json_type_array == json_object_get_type( poObjLine ) ) { const int nPoints = json_object_array_length( poObjLine ); for(j = 0; j < nPoints; ++j) { json_object* coords = NULL; coords = json_object_array_get_idx( poObjLine, j ); parse_geojson_coord(coords, hasz, pa); } geom = (LWGEOM*)lwmline_add_lwline((LWMLINE*)geom, (LWLINE*)lwline_construct(root_srid, NULL, pa)); } } } return geom; }
static LWGEOM* linestring_from_pa(const POINTARRAY *pa, int srid, int start, int end) { int i = 0, j = 0; POINT4D p; POINTARRAY *pao = ptarray_construct(ptarray_has_z(pa), ptarray_has_m(pa), end-start+2); LWDEBUGF(4, "srid=%d, start=%d, end=%d", srid, start, end); for( i = start; i < end + 2; i++ ) { getPoint4d_p(pa, i, &p); ptarray_set_point4d(pao, j++, &p); } return lwline_as_lwgeom(lwline_construct(srid, NULL, pao)); }
LWLINE * lwline_addpoint(LWLINE *line, LWPOINT *point, unsigned int where) { POINTARRAY *newpa; LWLINE *ret; newpa = ptarray_addPoint(line->points, getPoint_internal(point->point, 0), TYPE_NDIMS(point->type), where); ret = lwline_construct(line->SRID, ptarray_compute_box2d(newpa), newpa); return ret; }
/** * LINESTRING * Read a WKB linestring, starting just after the endian byte, * type number and optional srid number. Advance the parse state * forward appropriately. * There is only one pointarray in a linestring. Optionally * check for minimal following of rules (two point minimum). */ static LWLINE* lwline_from_wkb_state(wkb_parse_state *s) { POINTARRAY *pa = ptarray_from_wkb_state(s); if( pa == NULL || pa->npoints == 0 ) return lwline_construct_empty(s->srid, s->has_z, s->has_m); if( s->check & LW_PARSER_CHECK_MINPOINTS && pa->npoints < 2 ) { lwerror("%s must have at least two points", lwtype_name(s->lwtype)); return NULL; } return lwline_construct(s->srid, NULL, pa); }
/* * @param icompound input compound curve * @param tol tolerance, semantic driven by tolerance_type * @param tolerance_type see LW_LINEARIZE_TOLERANCE_TYPE * @param flags see flags in lwarc_linearize * * @return a newly allocated LWLINE */ static LWLINE * lwcompound_linearize(const LWCOMPOUND *icompound, double tol, LW_LINEARIZE_TOLERANCE_TYPE tolerance_type, int flags) { LWGEOM *geom; POINTARRAY *ptarray = NULL, *ptarray_out = NULL; LWLINE *tmp = NULL; uint32_t i, j; POINT4D p; LWDEBUG(2, "lwcompound_stroke called."); ptarray = ptarray_construct_empty(FLAGS_GET_Z(icompound->flags), FLAGS_GET_M(icompound->flags), 64); for (i = 0; i < icompound->ngeoms; i++) { geom = icompound->geoms[i]; if (geom->type == CIRCSTRINGTYPE) { tmp = lwcircstring_linearize((LWCIRCSTRING *)geom, tol, tolerance_type, flags); for (j = 0; j < tmp->points->npoints; j++) { getPoint4d_p(tmp->points, j, &p); ptarray_append_point(ptarray, &p, LW_TRUE); } lwline_free(tmp); } else if (geom->type == LINETYPE) { tmp = (LWLINE *)geom; for (j = 0; j < tmp->points->npoints; j++) { getPoint4d_p(tmp->points, j, &p); ptarray_append_point(ptarray, &p, LW_TRUE); } } else { lwerror("Unsupported geometry type %d found.", geom->type, lwtype_name(geom->type)); return NULL; } } ptarray_out = ptarray_remove_repeated_points(ptarray, 0.0); ptarray_free(ptarray); return lwline_construct(icompound->srid, NULL, ptarray_out); }
/* * Construct a LWLINE from an array of LWPOINTs * LWLINE dimensions are large enough to host all input dimensions. */ LWLINE * lwline_from_lwpointarray(int SRID, unsigned int npoints, LWPOINT **points) { int zmflag=0; unsigned int i; POINTARRAY *pa; uchar *newpoints, *ptr; size_t ptsize, size; /* * Find output dimensions, check integrity */ for (i=0; i<npoints; i++) { if ( TYPE_GETTYPE(points[i]->type) != POINTTYPE ) { lwerror("lwline_from_lwpointarray: invalid input type: %s", lwgeom_typename(TYPE_GETTYPE(points[i]->type))); return NULL; } if ( TYPE_HASZ(points[i]->type) ) zmflag |= 2; if ( TYPE_HASM(points[i]->type) ) zmflag |= 1; if ( zmflag == 3 ) break; } if ( zmflag == 0 ) ptsize=2*sizeof(double); else if ( zmflag == 3 ) ptsize=4*sizeof(double); else ptsize=3*sizeof(double); /* * Allocate output points array */ size = ptsize*npoints; newpoints = lwalloc(size); memset(newpoints, 0, size); ptr=newpoints; for (i=0; i<npoints; i++) { size=pointArray_ptsize(points[i]->point); memcpy(ptr, getPoint_internal(points[i]->point, 0), size); ptr+=ptsize; } pa = pointArray_construct(newpoints, zmflag&2, zmflag&1, npoints); return lwline_construct(SRID, NULL, pa); }
LWLINE * lwline_grid(LWLINE *line, gridspec *grid) { LWLINE *oline; POINTARRAY *opa; opa = ptarray_grid(line->points, grid); /* Skip line3d with less then 2 points */ if ( opa->npoints < 2 ) return NULL; /* TODO: grid bounding box... */ oline = lwline_construct(line->srid, NULL, opa); return oline; }
static LWLINE* lwline_set_effective_area(const LWLINE *iline,int set_area, double trshld) { LWDEBUG(2, "Entered lwline_set_effective_area"); int set_m; if(set_area) set_m=1; else set_m=FLAGS_GET_M(iline->flags); LWLINE *oline = lwline_construct_empty(iline->srid, FLAGS_GET_Z(iline->flags), set_m); /* Skip empty case */ if( lwline_is_empty(iline) ) return lwline_clone(iline); oline = lwline_construct(iline->srid, NULL, ptarray_set_effective_area(iline->points,2,set_area,trshld)); oline->type = iline->type; return oline; }
/** * @param mcurve input compound curve * @param tol tolerance, semantic driven by tolerance_type * @param tolerance_type see LW_LINEARIZE_TOLERANCE_TYPE * @param flags see flags in lwarc_linearize * * @return a newly allocated LWMLINE */ static LWMLINE * lwmcurve_linearize(const LWMCURVE *mcurve, double tol, LW_LINEARIZE_TOLERANCE_TYPE type, int flags) { LWMLINE *ogeom; LWGEOM **lines; int i; LWDEBUGF(2, "lwmcurve_linearize called, geoms=%d, dim=%d.", mcurve->ngeoms, FLAGS_NDIMS(mcurve->flags)); lines = lwalloc(sizeof(LWGEOM *)*mcurve->ngeoms); for (i = 0; i < mcurve->ngeoms; i++) { const LWGEOM *tmp = mcurve->geoms[i]; if (tmp->type == CIRCSTRINGTYPE) { lines[i] = (LWGEOM *)lwcircstring_linearize((LWCIRCSTRING *)tmp, tol, type, flags); } else if (tmp->type == LINETYPE) { lines[i] = (LWGEOM *)lwline_construct(mcurve->srid, NULL, ptarray_clone_deep(((LWLINE *)tmp)->points)); } else if (tmp->type == COMPOUNDTYPE) { lines[i] = (LWGEOM *)lwcompound_linearize((LWCOMPOUND *)tmp, tol, type, flags); } else { lwerror("Unsupported geometry found in MultiCurve."); return NULL; } } ogeom = (LWMLINE *)lwcollection_construct(MULTILINETYPE, mcurve->srid, NULL, mcurve->ngeoms, lines); return ogeom; }
Datum LWGEOM_interiorringn_polygon(PG_FUNCTION_ARGS) { PG_LWGEOM *geom; int32 wanted_index; LWCURVEPOLY *curvepoly = NULL; LWPOLY *poly = NULL; POINTARRAY *ring; LWLINE *line; PG_LWGEOM *result; BOX2DFLOAT4 *bbox = NULL; POSTGIS_DEBUG(2, "LWGEOM_interierringn_polygon called."); wanted_index = PG_GETARG_INT32(1); if ( wanted_index < 1 ) { /* elog(ERROR, "InteriorRingN: ring number is 1-based"); */ PG_RETURN_NULL(); /* index out of range */ } geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); if ( TYPE_GETTYPE(geom->type) != POLYGONTYPE && TYPE_GETTYPE(geom->type) != CURVEPOLYTYPE ) { PG_FREE_IF_COPY(geom, 0); elog(ERROR, "InteriorRingN: geom is not a polygon"); PG_RETURN_NULL(); } if ( TYPE_GETTYPE(geom->type) == POLYGONTYPE) { poly = lwpoly_deserialize(SERIALIZED_FORM(geom)); /* Ok, now we have a polygon. Let's see if it has enough holes */ if ( wanted_index >= poly->nrings ) { PG_FREE_IF_COPY(geom, 0); lwgeom_release((LWGEOM *)poly); PG_RETURN_NULL(); } ring = poly->rings[wanted_index]; /* COMPUTE_BBOX==TAINTING */ if ( poly->bbox ) bbox = ptarray_compute_box2d(ring); /* This is a LWLINE constructed by interior ring POINTARRAY */ line = lwline_construct(poly->SRID, bbox, ring); /* Copy SRID from polygon */ line->SRID = poly->SRID; result = pglwgeom_serialize((LWGEOM *)line); lwgeom_release((LWGEOM *)line); lwgeom_release((LWGEOM *)poly); } else { curvepoly = lwcurvepoly_deserialize(SERIALIZED_FORM(geom)); if (wanted_index >= curvepoly->nrings) { PG_FREE_IF_COPY(geom, 0); lwgeom_release((LWGEOM *)curvepoly); PG_RETURN_NULL(); } result = pglwgeom_serialize(curvepoly->rings[wanted_index]); lwgeom_release((LWGEOM *)curvepoly); } PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(result); }
/* * Line is assumed to have an M value. * * Return NULL if no parts of the line are in the given range (inclusive) * * Return an LWCOLLECTION with LWLINES and LWPOINT being consecutive * and isolated points on the line falling in the range. * * X,Y and Z (if present) ordinates are interpolated. * */ static LWGEOM * lwline_locate_between_m(LWLINE *lwline_in, double m0, double m1) { POINTARRAY *ipa=lwline_in->points; int i; LWGEOM **geoms; int ngeoms; int outtype; int typeflag=0; /* see flags below */ const int pointflag=0x01; const int lineflag=0x10; POINTARRAYSET paset=ptarray_locate_between_m(ipa, m0, m1); POSTGIS_DEBUGF(2, "lwline_locate_between called for lwline %p", lwline_in); POSTGIS_DEBUGF(3, " ptarray_locate... returned %d pointarrays", paset.nptarrays); if ( paset.nptarrays == 0 ) { return NULL; } ngeoms=paset.nptarrays; /* TODO: rework this to reduce used memory */ geoms=lwalloc(sizeof(LWGEOM *)*ngeoms); for (i=0; i<ngeoms; i++) { LWPOINT *lwpoint; LWLINE *lwline; POINTARRAY *pa=paset.ptarrays[i]; /* This is a point */ if ( pa->npoints == 1 ) { lwpoint = lwpoint_construct(lwline_in->srid, NULL, pa); geoms[i]=(LWGEOM *)lwpoint; typeflag|=pointflag; } /* This is a line */ else if ( pa->npoints > 1 ) { lwline = lwline_construct(lwline_in->srid, NULL, pa); geoms[i]=(LWGEOM *)lwline; typeflag|=lineflag; } /* This is a bug */ else { lwpgerror("ptarray_locate_between_m returned a POINARRAY set containing POINTARRAY with 0 points"); } } if ( ngeoms == 1 ) { return geoms[0]; } else { /* Choose best type */ if ( typeflag == 1 ) outtype=MULTIPOINTTYPE; else if ( typeflag == 2 ) outtype=MULTILINETYPE; else outtype = COLLECTIONTYPE; return (LWGEOM *)lwcollection_construct(outtype, lwline_in->srid, NULL, ngeoms, geoms); } }
int main() { /* * An example to show how to call the WKT/WKB unparsers in liblwgeom */ LWGEOM_UNPARSER_RESULT lwg_unparser_result; int result; LWGEOM *lwgeom; uchar *serialized_lwgeom; DYNPTARRAY *dpa; POINT4D point4d; POINTARRAY **rings; LWPOINT *testpoint; LWLINE *testline; LWPOLY *testpoly; /* * Construct a geometry equivalent to POINT(0 51) */ dpa = dynptarray_create(10, 2); point4d.x = 0; point4d.y = 51; dynptarray_addPoint4d(dpa, &point4d, 0); testpoint = lwpoint_construct(-1, NULL, dpa->pa); /* Generate the LWGEOM from LWPOINT, then serialize it ready for the parser */ lwgeom = lwpoint_as_lwgeom(testpoint); serialized_lwgeom = lwgeom_serialize(lwgeom); /* Output the geometry in WKT and WKB */ result = serialized_lwgeom_to_ewkt(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_ALL); printf("WKT format : %s\n", lwg_unparser_result.wkoutput); result = serialized_lwgeom_to_hexwkb(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_ALL, NDR); printf("HEXWKB format : %s\n\n", lwg_unparser_result.wkoutput); /* Free all of the allocated items */ lwfree(lwg_unparser_result.wkoutput); lwfree(serialized_lwgeom); lwpoint_free(testpoint); lwfree(dpa); /* * Construct a geometry equivalent to LINESTRING(0 0, 2 2, 4 1) */ dpa = dynptarray_create(10, 2); point4d.x = 0; point4d.y = 0; dynptarray_addPoint4d(dpa, &point4d, 0); point4d.x = 2; point4d.y = 2; dynptarray_addPoint4d(dpa, &point4d, 0); point4d.x = 4; point4d.y = 1; dynptarray_addPoint4d(dpa, &point4d, 0); testline = lwline_construct(-1, NULL, dpa->pa); /* Generate the LWGEOM from LWLINE, then serialize it ready for the parser */ lwgeom = lwline_as_lwgeom(testline); serialized_lwgeom = lwgeom_serialize(lwgeom); /* Output the geometry in WKT and WKB */ result = serialized_lwgeom_to_ewkt(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_ALL); printf("WKT format : %s\n", lwg_unparser_result.wkoutput); result = serialized_lwgeom_to_hexwkb(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_ALL, NDR); printf("HEXWKB format : %s\n\n", lwg_unparser_result.wkoutput); /* Free all of the allocated items */ lwfree(lwg_unparser_result.wkoutput); lwfree(serialized_lwgeom); lwline_free(testline); lwfree(dpa); /* * Construct a geometry equivalent to POLYGON((0 0, 0 10, 10 10, 10 0, 0 0)(3 3, 3 6, 6 6, 6 3, 3 3)) */ /* Allocate memory for the rings */ rings = lwalloc(sizeof(POINTARRAY) * 2); /* Construct the first ring */ dpa = dynptarray_create(10, 2); point4d.x = 0; point4d.y = 0; dynptarray_addPoint4d(dpa, &point4d, 0); point4d.x = 0; point4d.y = 10; dynptarray_addPoint4d(dpa, &point4d, 0); point4d.x = 10; point4d.y = 10; dynptarray_addPoint4d(dpa, &point4d, 0); point4d.x = 10; point4d.y = 0; dynptarray_addPoint4d(dpa, &point4d, 0); point4d.x = 0; point4d.y = 0; dynptarray_addPoint4d(dpa, &point4d, 0); rings[0] = dpa->pa; lwfree(dpa); /* Construct the second ring */ dpa = dynptarray_create(10, 2); point4d.x = 3; point4d.y = 3; dynptarray_addPoint4d(dpa, &point4d, 0); point4d.x = 3; point4d.y = 6; dynptarray_addPoint4d(dpa, &point4d, 0); point4d.x = 6; point4d.y = 6; dynptarray_addPoint4d(dpa, &point4d, 0); point4d.x = 6; point4d.y = 3; dynptarray_addPoint4d(dpa, &point4d, 0); point4d.x = 3; point4d.y = 3; dynptarray_addPoint4d(dpa, &point4d, 0); rings[1] = dpa->pa; lwfree(dpa); testpoly = lwpoly_construct(-1, NULL, 2, rings); /* Generate the LWGEOM from LWPOLY, then serialize it ready for the parser */ lwgeom = lwpoly_as_lwgeom(testpoly); serialized_lwgeom = lwgeom_serialize(lwgeom); /* Output the geometry in WKT and WKB */ result = serialized_lwgeom_to_ewkt(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_NONE); printf("WKT format : %s\n", lwg_unparser_result.wkoutput); result = serialized_lwgeom_to_hexwkb(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_NONE, NDR); printf("HEXWKB format : %s\n\n", lwg_unparser_result.wkoutput); /* Free all of the allocated items */ lwfree(lwg_unparser_result.wkoutput); lwfree(serialized_lwgeom); lwpoly_free(testpoly); }
Datum BOX2D_to_LWGEOM(PG_FUNCTION_ARGS) { GBOX *box = (GBOX *)PG_GETARG_POINTER(0); POINTARRAY *pa = ptarray_construct_empty(0, 0, 5); POINT4D pt; GSERIALIZED *result; /* * Alter BOX2D cast so that a valid geometry is always * returned depending upon the size of the BOX2D. The * code makes the following assumptions: * - If the BOX2D is a single point then return a * POINT geometry * - If the BOX2D represents either a horizontal or * vertical line, return a LINESTRING geometry * - Otherwise return a POLYGON */ if ( (box->xmin == box->xmax) && (box->ymin == box->ymax) ) { /* Construct and serialize point */ LWPOINT *point = lwpoint_make2d(SRID_UNKNOWN, box->xmin, box->ymin); result = geometry_serialize(lwpoint_as_lwgeom(point)); lwpoint_free(point); } else if ( (box->xmin == box->xmax) || (box->ymin == box->ymax) ) { LWLINE *line; /* Assign coordinates to point array */ pt.x = box->xmin; pt.y = box->ymin; ptarray_append_point(pa, &pt, LW_TRUE); pt.x = box->xmax; pt.y = box->ymax; ptarray_append_point(pa, &pt, LW_TRUE); /* Construct and serialize linestring */ line = lwline_construct(SRID_UNKNOWN, NULL, pa); result = geometry_serialize(lwline_as_lwgeom(line)); lwline_free(line); } else { LWPOLY *poly; POINTARRAY **ppa = lwalloc(sizeof(POINTARRAY*)); /* Assign coordinates to point array */ pt.x = box->xmin; pt.y = box->ymin; ptarray_append_point(pa, &pt, LW_TRUE); pt.x = box->xmin; pt.y = box->ymax; ptarray_append_point(pa, &pt, LW_TRUE); pt.x = box->xmax; pt.y = box->ymax; ptarray_append_point(pa, &pt, LW_TRUE); pt.x = box->xmax; pt.y = box->ymin; ptarray_append_point(pa, &pt, LW_TRUE); pt.x = box->xmin; pt.y = box->ymin; ptarray_append_point(pa, &pt, LW_TRUE); /* Construct polygon */ ppa[0] = pa; poly = lwpoly_construct(SRID_UNKNOWN, NULL, 1, ppa); result = geometry_serialize(lwpoly_as_lwgeom(poly)); lwpoly_free(poly); } PG_RETURN_POINTER(result); }
/* Return an LWGEOM from a Geometry */ LWGEOM * GEOS2LWGEOM(const GEOSGeometry *geom, char want3d) { int type = GEOSGeomTypeId(geom) ; int hasZ; int SRID = GEOSGetSRID(geom); /* GEOS's 0 is equivalent to our unknown as for SRID values */ if ( SRID == 0 ) SRID = SRID_UNKNOWN; if ( want3d ) { hasZ = GEOSHasZ(geom); if ( ! hasZ ) { LWDEBUG(3, "Geometry has no Z, won't provide one"); want3d = 0; } } /* if ( GEOSisEmpty(geom) ) { return (LWGEOM*)lwcollection_construct_empty(COLLECTIONTYPE, SRID, want3d, 0); } */ switch (type) { const GEOSCoordSequence *cs; POINTARRAY *pa, **ppaa; const GEOSGeometry *g; LWGEOM **geoms; uint32_t i, ngeoms; case GEOS_POINT: LWDEBUG(4, "lwgeom_from_geometry: it's a Point"); cs = GEOSGeom_getCoordSeq(geom); if ( GEOSisEmpty(geom) ) return (LWGEOM*)lwpoint_construct_empty(SRID, want3d, 0); pa = ptarray_from_GEOSCoordSeq(cs, want3d); return (LWGEOM *)lwpoint_construct(SRID, NULL, pa); case GEOS_LINESTRING: case GEOS_LINEARRING: LWDEBUG(4, "lwgeom_from_geometry: it's a LineString or LinearRing"); if ( GEOSisEmpty(geom) ) return (LWGEOM*)lwline_construct_empty(SRID, want3d, 0); cs = GEOSGeom_getCoordSeq(geom); pa = ptarray_from_GEOSCoordSeq(cs, want3d); return (LWGEOM *)lwline_construct(SRID, NULL, pa); case GEOS_POLYGON: LWDEBUG(4, "lwgeom_from_geometry: it's a Polygon"); if ( GEOSisEmpty(geom) ) return (LWGEOM*)lwpoly_construct_empty(SRID, want3d, 0); ngeoms = GEOSGetNumInteriorRings(geom); ppaa = lwalloc(sizeof(POINTARRAY *)*(ngeoms+1)); g = GEOSGetExteriorRing(geom); cs = GEOSGeom_getCoordSeq(g); ppaa[0] = ptarray_from_GEOSCoordSeq(cs, want3d); for (i=0; i<ngeoms; i++) { g = GEOSGetInteriorRingN(geom, i); cs = GEOSGeom_getCoordSeq(g); ppaa[i+1] = ptarray_from_GEOSCoordSeq(cs, want3d); } return (LWGEOM *)lwpoly_construct(SRID, NULL, ngeoms+1, ppaa); case GEOS_MULTIPOINT: case GEOS_MULTILINESTRING: case GEOS_MULTIPOLYGON: case GEOS_GEOMETRYCOLLECTION: LWDEBUG(4, "lwgeom_from_geometry: it's a Collection or Multi"); ngeoms = GEOSGetNumGeometries(geom); geoms = NULL; if ( ngeoms ) { geoms = lwalloc(sizeof(LWGEOM *)*ngeoms); for (i=0; i<ngeoms; i++) { g = GEOSGetGeometryN(geom, i); geoms[i] = GEOS2LWGEOM(g, want3d); } } return (LWGEOM *)lwcollection_construct(type, SRID, NULL, ngeoms, geoms); default: lwerror("GEOS2LWGEOM: unknown geometry type: %d", type); return NULL; } }
int lwline_split_by_point_to(const LWLINE* lwline_in, const LWPOINT* blade_in, LWMLINE* v) { double loc, dist; POINT4D pt, pt_projected; POINTARRAY* pa1; POINTARRAY* pa2; double vstol; /* vertex snap tolerance */ /* Possible outcomes: * * 1. The point is not on the line or on the boundary * -> Leave collection untouched, return 0 * 2. The point is on the boundary * -> Push 1 element on the collection: * o the original line * -> Return 1 * 3. The point is in the line * -> Push 2 elements on the collection: * o start_point - cut_point * o cut_point - last_point * -> Return 2 */ getPoint4d_p(blade_in->point, 0, &pt); loc = ptarray_locate_point(lwline_in->points, &pt, &dist, &pt_projected); /* lwnotice("Location: %g -- Distance: %g", loc, dist); */ if ( dist > 0 ) /* TODO: accept a tolerance ? */ { /* No intersection */ return 0; } if ( loc == 0 || loc == 1 ) { /* Intersection is on the boundary */ return 1; } /* There is a real intersection, let's get two substrings */ /* Compute vertex snap tolerance based on line length * TODO: take as parameter ? */ vstol = ptarray_length_2d(lwline_in->points) / 1e14; pa1 = ptarray_substring(lwline_in->points, 0, loc, vstol); pa2 = ptarray_substring(lwline_in->points, loc, 1, vstol); /* NOTE: I've seen empty pointarrays with loc != 0 and loc != 1 */ if ( pa1->npoints == 0 || pa2->npoints == 0 ) { ptarray_free(pa1); ptarray_free(pa2); /* Intersection is on the boundary */ return 1; } lwmline_add_lwline(v, lwline_construct(SRID_UNKNOWN, NULL, pa1)); lwmline_add_lwline(v, lwline_construct(SRID_UNKNOWN, NULL, pa2)); return 2; }
int lwline_split_by_point_to(const LWLINE* lwline_in, const LWPOINT* blade_in, LWMLINE* v) { double mindist = -1; POINT4D pt, pt_projected; POINT4D p1, p2; POINTARRAY *ipa = lwline_in->points; POINTARRAY* pa1; POINTARRAY* pa2; int i, nsegs, seg = -1; /* Possible outcomes: * * 1. The point is not on the line or on the boundary * -> Leave collection untouched, return 0 * 2. The point is on the boundary * -> Leave collection untouched, return 1 * 3. The point is in the line * -> Push 2 elements on the collection: * o start_point - cut_point * o cut_point - last_point * -> Return 2 */ getPoint4d_p(blade_in->point, 0, &pt); /* Find closest segment */ getPoint4d_p(ipa, 0, &p1); nsegs = ipa->npoints - 1; for ( i = 0; i < nsegs; i++ ) { getPoint4d_p(ipa, i+1, &p2); double dist; dist = distance2d_pt_seg((POINT2D*)&pt, (POINT2D*)&p1, (POINT2D*)&p2); LWDEBUGF(4, " Distance of point %g %g to segment %g %g, %g %g: %g", pt.x, pt.y, p1.x, p1.y, p2.x, p2.y, dist); if (i==0 || dist < mindist ) { mindist = dist; seg=i; if ( mindist == 0.0 ) break; /* can't be closer than ON line */ } p1 = p2; } LWDEBUGF(3, "Closest segment: %d", seg); LWDEBUGF(3, "mindist: %g", mindist); /* No intersection */ if ( mindist > 0 ) return 0; /* empty or single-point line, intersection on boundary */ if ( seg < 0 ) return 1; /* * We need to project the * point on the closest segment, * to interpolate Z and M if needed */ getPoint4d_p(ipa, seg, &p1); getPoint4d_p(ipa, seg+1, &p2); closest_point_on_segment(&pt, &p1, &p2, &pt_projected); /* But X and Y we want the ones of the input point, * as on some architectures the interpolation math moves the * coordinates (see #3422) */ pt_projected.x = pt.x; pt_projected.y = pt.y; LWDEBUGF(3, "Projected point:(%g %g), seg:%d, p1:(%g %g), p2:(%g %g)", pt_projected.x, pt_projected.y, seg, p1.x, p1.y, p2.x, p2.y); /* When closest point == an endpoint, this is a boundary intersection */ if ( ( (seg == nsegs-1) && p4d_same(&pt_projected, &p2) ) || ( (seg == 0) && p4d_same(&pt_projected, &p1) ) ) { return 1; } /* This is an internal intersection, let's build the two new pointarrays */ pa1 = ptarray_construct_empty(FLAGS_GET_Z(ipa->flags), FLAGS_GET_M(ipa->flags), seg+2); /* TODO: replace with a memcpy ? */ for (i=0; i<=seg; ++i) { getPoint4d_p(ipa, i, &p1); ptarray_append_point(pa1, &p1, LW_FALSE); } ptarray_append_point(pa1, &pt_projected, LW_FALSE); pa2 = ptarray_construct_empty(FLAGS_GET_Z(ipa->flags), FLAGS_GET_M(ipa->flags), ipa->npoints-seg); ptarray_append_point(pa2, &pt_projected, LW_FALSE); /* TODO: replace with a memcpy (if so need to check for duplicated point) ? */ for (i=seg+1; i<ipa->npoints; ++i) { getPoint4d_p(ipa, i, &p1); ptarray_append_point(pa2, &p1, LW_FALSE); } /* NOTE: I've seen empty pointarrays with loc != 0 and loc != 1 */ if ( pa1->npoints == 0 || pa2->npoints == 0 ) { ptarray_free(pa1); ptarray_free(pa2); /* Intersection is on the boundary */ return 1; } lwmline_add_lwline(v, lwline_construct(SRID_UNKNOWN, NULL, pa1)); lwmline_add_lwline(v, lwline_construct(SRID_UNKNOWN, NULL, pa2)); return 2; }
Datum LWGEOM_line_substring(PG_FUNCTION_ARGS) { GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); double from = PG_GETARG_FLOAT8(1); double to = PG_GETARG_FLOAT8(2); LWGEOM *olwgeom; POINTARRAY *ipa, *opa; GSERIALIZED *ret; int type = gserialized_get_type(geom); if ( from < 0 || from > 1 ) { elog(ERROR,"line_interpolate_point: 2nd arg isnt within [0,1]"); PG_RETURN_NULL(); } if ( to < 0 || to > 1 ) { elog(ERROR,"line_interpolate_point: 3rd arg isnt within [0,1]"); PG_RETURN_NULL(); } if ( from > to ) { elog(ERROR, "2nd arg must be smaller then 3rd arg"); PG_RETURN_NULL(); } if ( type == LINETYPE ) { LWLINE *iline = lwgeom_as_lwline(lwgeom_from_gserialized(geom)); if ( lwgeom_is_empty((LWGEOM*)iline) ) { /* TODO return empty line */ lwline_release(iline); PG_FREE_IF_COPY(geom, 0); PG_RETURN_NULL(); } ipa = iline->points; opa = ptarray_substring(ipa, from, to, 0); if ( opa->npoints == 1 ) /* Point returned */ olwgeom = (LWGEOM *)lwpoint_construct(iline->srid, NULL, opa); else olwgeom = (LWGEOM *)lwline_construct(iline->srid, NULL, opa); } else if ( type == MULTILINETYPE ) { LWMLINE *iline; int i = 0, g = 0; int homogeneous = LW_TRUE; LWGEOM **geoms = NULL; double length = 0.0, sublength = 0.0, minprop = 0.0, maxprop = 0.0; iline = lwgeom_as_lwmline(lwgeom_from_gserialized(geom)); if ( lwgeom_is_empty((LWGEOM*)iline) ) { /* TODO return empty collection */ lwmline_release(iline); PG_FREE_IF_COPY(geom, 0); PG_RETURN_NULL(); } /* Calculate the total length of the mline */ for ( i = 0; i < iline->ngeoms; i++ ) { LWLINE *subline = (LWLINE*)iline->geoms[i]; if ( subline->points && subline->points->npoints > 1 ) length += ptarray_length_2d(subline->points); } geoms = lwalloc(sizeof(LWGEOM*) * iline->ngeoms); /* Slice each sub-geometry of the multiline */ for ( i = 0; i < iline->ngeoms; i++ ) { LWLINE *subline = (LWLINE*)iline->geoms[i]; double subfrom = 0.0, subto = 0.0; if ( subline->points && subline->points->npoints > 1 ) sublength += ptarray_length_2d(subline->points); /* Calculate proportions for this subline */ minprop = maxprop; maxprop = sublength / length; /* This subline doesn't reach the lowest proportion requested or is beyond the highest proporton */ if ( from > maxprop || to < minprop ) continue; if ( from <= minprop ) subfrom = 0.0; if ( to >= maxprop ) subto = 1.0; if ( from > minprop && from <= maxprop ) subfrom = (from - minprop) / (maxprop - minprop); if ( to < maxprop && to >= minprop ) subto = (to - minprop) / (maxprop - minprop); opa = ptarray_substring(subline->points, subfrom, subto, 0); if ( opa && opa->npoints > 0 ) { if ( opa->npoints == 1 ) /* Point returned */ { geoms[g] = (LWGEOM *)lwpoint_construct(iline->srid, NULL, opa); homogeneous = LW_FALSE; } else { geoms[g] = (LWGEOM *)lwline_construct(iline->srid, NULL, opa); } g++; } } /* If we got any points, we need to return a GEOMETRYCOLLECTION */ if ( ! homogeneous ) type = COLLECTIONTYPE; olwgeom = (LWGEOM*)lwcollection_construct(type, iline->srid, NULL, g, geoms); } else { elog(ERROR,"line_interpolate_point: 1st arg isnt a line"); PG_RETURN_NULL(); } ret = geometry_serialize(olwgeom); lwgeom_free(olwgeom); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(ret); }