/** * Create a new point. Null point array implies empty. Null dimensionality * implies no specified dimensionality in the WKT. */ LWGEOM* wkt_parser_point_new(POINTARRAY *pa, char *dimensionality) { uint8_t flags = wkt_dimensionality(dimensionality); LWDEBUG(4,"entered"); /* No pointarray means it is empty */ if( ! pa ) return lwpoint_as_lwgeom(lwpoint_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; } /* Only one point allowed in our point array! */ if( pa->npoints != 1 ) { ptarray_free(pa); SET_PARSER_ERROR(PARSER_ERROR_LESSPOINTS); return NULL; } return lwpoint_as_lwgeom(lwpoint_construct(SRID_UNKNOWN, NULL, pa)); }
LWGEOM * lwgeom_construct_empty(uint8_t type, int srid, char hasz, char hasm) { switch(type) { case POINTTYPE: return lwpoint_as_lwgeom(lwpoint_construct_empty(srid, hasz, hasm)); case LINETYPE: return lwline_as_lwgeom(lwline_construct_empty(srid, hasz, hasm)); case POLYGONTYPE: return lwpoly_as_lwgeom(lwpoly_construct_empty(srid, hasz, hasm)); case CURVEPOLYTYPE: return lwcurvepoly_as_lwgeom(lwcurvepoly_construct_empty(srid, hasz, hasm)); case CIRCSTRINGTYPE: return lwcircstring_as_lwgeom(lwcircstring_construct_empty(srid, hasz, hasm)); case TRIANGLETYPE: return lwtriangle_as_lwgeom(lwtriangle_construct_empty(srid, hasz, hasm)); case COMPOUNDTYPE: case MULTIPOINTTYPE: case MULTILINETYPE: case MULTIPOLYGONTYPE: case COLLECTIONTYPE: return lwcollection_as_lwgeom(lwcollection_construct_empty(type, srid, hasz, hasm)); default: lwerror("lwgeom_construct_empty: unsupported geometry type: %s", lwtype_name(type)); return NULL; } }
/** * MULTIPOINT */ static LWCOLLECTION* lwmultipoint_from_twkb_state(twkb_parse_state *s) { int ngeoms, i; LWGEOM *geom = NULL; LWCOLLECTION *col = lwcollection_construct_empty(s->lwtype, SRID_UNKNOWN, s->has_z, s->has_m); LWDEBUG(2,"Entering lwmultipoint_from_twkb_state"); if ( s->is_empty ) return col; /* Read number of geometries */ ngeoms = twkb_parse_state_uvarint(s); LWDEBUGF(4,"Number of geometries %d", ngeoms); /* It has an idlist, we need to skip that */ if ( s->has_idlist ) { for ( i = 0; i < ngeoms; i++ ) twkb_parse_state_varint_skip(s); } for ( i = 0; i < ngeoms; i++ ) { geom = lwpoint_as_lwgeom(lwpoint_from_twkb_state(s)); if ( lwcollection_add_lwgeom(col, geom) == NULL ) { lwerror("Unable to add geometry (%p) to collection (%p)", geom, col); return NULL; } } return col; }
LWGEOM* lwgeom_force_dims(const LWGEOM *geom, int hasz, int hasm) { switch(geom->type) { case POINTTYPE: return lwpoint_as_lwgeom(lwpoint_force_dims((LWPOINT*)geom, hasz, hasm)); case CIRCSTRINGTYPE: case LINETYPE: case TRIANGLETYPE: return lwline_as_lwgeom(lwline_force_dims((LWLINE*)geom, hasz, hasm)); case POLYGONTYPE: return lwpoly_as_lwgeom(lwpoly_force_dims((LWPOLY*)geom, hasz, hasm)); case COMPOUNDTYPE: case CURVEPOLYTYPE: case MULTICURVETYPE: case MULTISURFACETYPE: case MULTIPOINTTYPE: case MULTILINETYPE: case MULTIPOLYGONTYPE: case POLYHEDRALSURFACETYPE: case TINTYPE: case COLLECTIONTYPE: return lwcollection_as_lwgeom(lwcollection_force_dims((LWCOLLECTION*)geom, hasz, hasm)); default: lwerror("lwgeom_force_2d: unsupported geom type: %s", lwtype_name(geom->type)); return NULL; } }
Datum LWGEOM_pointn_linestring(PG_FUNCTION_ARGS) { GSERIALIZED *geom = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); int where = PG_GETARG_INT32(1); LWGEOM *lwgeom = lwgeom_from_gserialized(geom); LWPOINT *lwpoint = NULL; int type = lwgeom->type; /* Can't handle crazy index! */ if ( where < 1 ) PG_RETURN_NULL(); if ( type == LINETYPE || type == CIRCSTRINGTYPE ) { /* OGC index starts at one, so we substract first. */ lwpoint = lwline_get_lwpoint((LWLINE*)lwgeom, where - 1); } lwgeom_free(lwgeom); PG_FREE_IF_COPY(geom, 0); if ( ! lwpoint ) PG_RETURN_NULL(); PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(lwpoint))); }
Datum LWGEOM_endpoint_linestring(PG_FUNCTION_ARGS) { GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0); LWGEOM *lwgeom = lwgeom_from_gserialized(geom); LWPOINT *lwpoint = NULL; int type = lwgeom->type; if ( type == LINETYPE || type == CIRCSTRINGTYPE ) { LWLINE *line = (LWLINE*)lwgeom; if ( line->points ) lwpoint = lwline_get_lwpoint((LWLINE*)lwgeom, line->points->npoints - 1); } else if ( type == COMPOUNDTYPE ) { lwpoint = lwcompound_get_endpoint((LWCOMPOUND*)lwgeom); } lwgeom_free(lwgeom); PG_FREE_IF_COPY(geom, 0); if ( ! lwpoint ) PG_RETURN_NULL(); PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(lwpoint))); }
/** * Clip an input POINT between two values, on any ordinate input. */ LWCOLLECTION* lwpoint_clip_to_ordinate_range(const LWPOINT *point, char ordinate, double from, double to) { LWCOLLECTION *lwgeom_out = NULL; char hasz, hasm; POINT4D p4d; double ordinate_value; /* Nothing to do with NULL */ if ( ! point ) lwerror("Null input geometry."); /* Ensure 'from' is less than 'to'. */ if ( to < from ) { double t = from; from = to; to = t; } /* Read Z/M info */ hasz = lwgeom_has_z(lwpoint_as_lwgeom(point)); hasm = lwgeom_has_m(lwpoint_as_lwgeom(point)); /* Prepare return object */ lwgeom_out = lwcollection_construct_empty(MULTIPOINTTYPE, point->srid, hasz, hasm); /* Test if ordinate is in range */ lwpoint_getPoint4d_p(point, &p4d); ordinate_value = lwpoint_get_ordinate(&p4d, ordinate); if ( from <= ordinate_value && to >= ordinate_value ) { LWPOINT *lwp = lwpoint_clone(point); lwcollection_add_lwgeom(lwgeom_out, lwpoint_as_lwgeom(lwp)); } /* Set the bbox */ lwgeom_drop_bbox((LWGEOM*)lwgeom_out); lwgeom_add_bbox((LWGEOM*)lwgeom_out); return lwgeom_out; }
static LWMPOINT* lwpoint_locate_along(const LWPOINT *lwpoint, double m, double offset) { double point_m = lwpoint_get_m(lwpoint); LWGEOM *lwg = lwpoint_as_lwgeom(lwpoint); LWMPOINT *r = lwmpoint_construct_empty(lwgeom_get_srid(lwg), lwgeom_has_z(lwg), lwgeom_has_m(lwg)); if ( FP_EQUALS(m, point_m) ) { lwmpoint_add_lwpoint(r, lwpoint_clone(lwpoint)); } return r; }
/** * Clip an input MULTIPOINT between two values, on any ordinate input. */ LWCOLLECTION* lwmpoint_clip_to_ordinate_range(const LWMPOINT *mpoint, char ordinate, double from, double to) { LWCOLLECTION *lwgeom_out = NULL; char hasz, hasm; int i; /* Nothing to do with NULL */ if ( ! mpoint ) lwerror("Null input geometry."); /* Ensure 'from' is less than 'to'. */ if ( to < from ) { double t = from; from = to; to = t; } /* Read Z/M info */ hasz = lwgeom_has_z(lwmpoint_as_lwgeom(mpoint)); hasm = lwgeom_has_m(lwmpoint_as_lwgeom(mpoint)); /* Prepare return object */ lwgeom_out = lwcollection_construct_empty(MULTIPOINTTYPE, mpoint->srid, hasz, hasm); /* For each point, is its ordinate value between from and to? */ for ( i = 0; i < mpoint->ngeoms; i ++ ) { POINT4D p4d; double ordinate_value; lwpoint_getPoint4d_p(mpoint->geoms[i], &p4d); ordinate_value = lwpoint_get_ordinate(&p4d, ordinate); if ( from <= ordinate_value && to >= ordinate_value ) { LWPOINT *lwp = lwpoint_clone(mpoint->geoms[i]); lwcollection_add_lwgeom(lwgeom_out, lwpoint_as_lwgeom(lwp)); } } /* Set the bbox */ lwgeom_drop_bbox((LWGEOM*)lwgeom_out); lwgeom_add_bbox((LWGEOM*)lwgeom_out); return lwgeom_out; }
Datum LWGEOM_startpoint_linestring(PG_FUNCTION_ARGS) { GSERIALIZED *geom = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); LWGEOM *lwgeom = lwgeom_from_gserialized(geom); LWPOINT *lwpoint = NULL; int type = lwgeom->type; if ( type == LINETYPE || type == CIRCSTRINGTYPE ) { lwpoint = lwline_get_lwpoint((LWLINE*)lwgeom, 0); } lwgeom_free(lwgeom); PG_FREE_IF_COPY(geom, 0); if ( ! lwpoint ) PG_RETURN_NULL(); PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(lwpoint))); }
/** * @brief Generate an allocated geometry string for shapefile object obj using the state parameters */ int GeneratePointGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry) { LWCOLLECTION *lwcollection; LWGEOM **lwmultipoints; uchar *serialized_lwgeom; LWGEOM_UNPARSER_RESULT lwg_unparser_result; DYNPTARRAY **dpas; POINT4D point4d; int dims = 0, hasz = 0, hasm = 0; int result; int u; char *mem; /* Determine the correct dimensions: note that in hwgeom-compatible mode we cannot use the M coordinate */ if (state->wkbtype & WKBZOFFSET) hasz = 1; if (!state->config->hwgeom) if (state->wkbtype & WKBMOFFSET) hasm = 1; TYPE_SETZM(dims, hasz, hasm); /* Allocate memory for our array of LWPOINTs and our dynptarrays */ lwmultipoints = malloc(sizeof(LWPOINT *) * obj->nVertices); dpas = malloc(sizeof(DYNPTARRAY *) * obj->nVertices); /* We need an array of pointers to each of our sub-geometries */ for (u = 0; u < obj->nVertices; u++) { /* Generate the point */ point4d.x = obj->padfX[u]; point4d.y = obj->padfY[u]; if (state->wkbtype & WKBZOFFSET) point4d.z = obj->padfZ[u]; if (state->wkbtype & WKBMOFFSET) point4d.m = obj->padfM[u]; /* Create a dynptarray containing a single point */ dpas[u] = dynptarray_create(1, dims); dynptarray_addPoint4d(dpas[u], &point4d, 0); /* Generate the LWPOINT */ lwmultipoints[u] = lwpoint_as_lwgeom(lwpoint_construct(state->config->sr_id, NULL, dpas[u]->pa)); } /* If we have more than 1 vertex then we are working on a MULTIPOINT and so generate a MULTIPOINT rather than a POINT */ if (obj->nVertices > 1) { lwcollection = lwcollection_construct(MULTIPOINTTYPE, state->config->sr_id, NULL, obj->nVertices, lwmultipoints); serialized_lwgeom = lwgeom_serialize(lwcollection_as_lwgeom(lwcollection)); } else { serialized_lwgeom = lwgeom_serialize(lwmultipoints[0]); } if (!state->config->hwgeom) result = serialized_lwgeom_to_hexwkb(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_NONE, -1); else result = serialized_lwgeom_to_ewkt(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_NONE); if (result) { snprintf(state->message, SHPLOADERMSGLEN, "%s", lwg_unparser_result.message); return SHPLOADERERR; } /* Allocate a string containing the resulting geometry */ mem = malloc(strlen(lwg_unparser_result.wkoutput) + 1); strcpy(mem, lwg_unparser_result.wkoutput); /* Free all of the allocated items */ lwfree(lwg_unparser_result.wkoutput); lwfree(serialized_lwgeom); for (u = 0; u < obj->nVertices; u++) { if (dpas[u]->pa->serialized_pointlist) lwfree(dpas[u]->pa->serialized_pointlist); lwpoint_free(lwgeom_as_lwpoint(lwmultipoints[u])); lwfree(dpas[u]); } lwfree(dpas); lwfree(lwmultipoints); /* Return the string - everything ok */ *geometry = mem; return SHPLOADEROK; }
void lwpoint_release(LWPOINT *lwpoint) { lwgeom_release(lwpoint_as_lwgeom(lwpoint)); }
/** * Check the consistency of the metadata we want to enforce in the typmod: * srid, type and dimensionality. If things are inconsistent, shut down the query. */ GSERIALIZED* postgis_valid_typmod(GSERIALIZED *gser, int32_t typmod) { int32 geom_srid = gserialized_get_srid(gser); int32 geom_type = gserialized_get_type(gser); int32 geom_z = gserialized_has_z(gser); int32 geom_m = gserialized_has_m(gser); int32 typmod_srid = TYPMOD_GET_SRID(typmod); int32 typmod_type = TYPMOD_GET_TYPE(typmod); int32 typmod_z = TYPMOD_GET_Z(typmod); int32 typmod_m = TYPMOD_GET_M(typmod); POSTGIS_DEBUG(2, "Entered function"); /* No typmod (-1) => no preferences */ if (typmod < 0) return gser; POSTGIS_DEBUGF(3, "Got geom(type = %d, srid = %d, hasz = %d, hasm = %d)", geom_type, geom_srid, geom_z, geom_m); POSTGIS_DEBUGF(3, "Got typmod(type = %d, srid = %d, hasz = %d, hasm = %d)", typmod_type, typmod_srid, typmod_z, typmod_m); /* * #3031: If a user is handing us a MULTIPOINT EMPTY but trying to fit it into * a POINT geometry column, there's a strong chance the reason she has * a MULTIPOINT EMPTY because we gave it to her during data dump, * converting the internal POINT EMPTY into a EWKB MULTIPOINT EMPTY * (because EWKB doesn't have a clean way to represent POINT EMPTY). * In such a case, it makes sense to turn the MULTIPOINT EMPTY back into a * point EMPTY, rather than throwing an error. */ if ( typmod_type == POINTTYPE && geom_type == MULTIPOINTTYPE && gserialized_is_empty(gser) ) { LWPOINT *empty_point = lwpoint_construct_empty(geom_srid, geom_z, geom_m); geom_type = POINTTYPE; pfree(gser); if ( gserialized_is_geodetic(gser) ) gser = geography_serialize(lwpoint_as_lwgeom(empty_point)); else gser = geometry_serialize(lwpoint_as_lwgeom(empty_point)); } /* Typmod has a preference for SRID? Geometry SRID had better match. */ if ( typmod_srid > 0 && typmod_srid != geom_srid ) { ereport(ERROR, ( errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Geometry SRID (%d) does not match column SRID (%d)", geom_srid, typmod_srid) )); } /* Typmod has a preference for geometry type. */ if ( typmod_type > 0 && /* GEOMETRYCOLLECTION column can hold any kind of collection */ ((typmod_type == COLLECTIONTYPE && ! (geom_type == COLLECTIONTYPE || geom_type == MULTIPOLYGONTYPE || geom_type == MULTIPOINTTYPE || geom_type == MULTILINETYPE )) || /* Other types must be strictly equal. */ (typmod_type != geom_type)) ) { ereport(ERROR, ( errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Geometry type (%s) does not match column type (%s)", lwtype_name(geom_type), lwtype_name(typmod_type)) )); } /* Mismatched Z dimensionality. */ if ( typmod_z && ! geom_z ) { ereport(ERROR, ( errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Column has Z dimension but geometry does not" ))); } /* Mismatched Z dimensionality (other way). */ if ( geom_z && ! typmod_z ) { ereport(ERROR, ( errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Geometry has Z dimension but column does not" ))); } /* Mismatched M dimensionality. */ if ( typmod_m && ! geom_m ) { ereport(ERROR, ( errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Column has M dimension but geometry does not" ))); } /* Mismatched M dimensionality (other way). */ if ( geom_m && ! typmod_m ) { ereport(ERROR, ( errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Geometry has M dimension but column does not" ))); } return gser; }
/** * @brief Generate an allocated geometry string for shapefile object obj using the state parameters * if "force_multi" is true, single points will instead be created as multipoints with a single vertice. */ int GeneratePointGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry, int force_multi) { LWGEOM **lwmultipoints; LWGEOM *lwgeom = NULL; POINT4D point4d; int dims = 0; int u; char *mem; size_t mem_length; FLAGS_SET_Z(dims, state->has_z); FLAGS_SET_M(dims, state->has_m); /* Allocate memory for our array of LWPOINTs and our dynptarrays */ lwmultipoints = malloc(sizeof(LWPOINT *) * obj->nVertices); /* We need an array of pointers to each of our sub-geometries */ for (u = 0; u < obj->nVertices; u++) { /* Create a ptarray containing a single point */ POINTARRAY *pa = ptarray_construct_empty(state->has_z, state->has_m, 1); /* Generate the point */ point4d.x = obj->padfX[u]; point4d.y = obj->padfY[u]; if (state->has_z) point4d.z = obj->padfZ[u]; if (state->has_m) point4d.m = obj->padfM[u]; /* Add in the point! */ ptarray_append_point(pa, &point4d, LW_TRUE); /* Generate the LWPOINT */ lwmultipoints[u] = lwpoint_as_lwgeom(lwpoint_construct(state->from_srid, NULL, pa)); } /* If we have more than 1 vertex then we are working on a MULTIPOINT and so generate a MULTIPOINT rather than a POINT */ if ((obj->nVertices > 1) || force_multi) { lwgeom = lwcollection_as_lwgeom(lwcollection_construct(MULTIPOINTTYPE, state->from_srid, NULL, obj->nVertices, lwmultipoints)); } else { lwgeom = lwmultipoints[0]; lwfree(lwmultipoints); } if (state->config->use_wkt) { mem = lwgeom_to_wkt(lwgeom, WKT_EXTENDED, WKT_PRECISION, &mem_length); } else { mem = lwgeom_to_hexwkb(lwgeom, WKB_EXTENDED, &mem_length); } if ( !mem ) { snprintf(state->message, SHPLOADERMSGLEN, "unable to write geometry"); return SHPLOADERERR; } /* Free all of the allocated items */ lwgeom_free(lwgeom); /* Return the string - everything ok */ *geometry = mem; return SHPLOADEROK; }
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); }
Datum LWGEOM_line_interpolate_point(PG_FUNCTION_ARGS) { GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); double distance = PG_GETARG_FLOAT8(1); LWLINE *line; LWPOINT *point; POINTARRAY *ipa, *opa; POINT4D pt; int nsegs, i; double length, slength, tlength; if ( distance < 0 || distance > 1 ) { elog(ERROR,"line_interpolate_point: 2nd arg isnt within [0,1]"); PG_RETURN_NULL(); } if ( gserialized_get_type(geom) != LINETYPE ) { elog(ERROR,"line_interpolate_point: 1st arg isnt a line"); PG_RETURN_NULL(); } line = lwgeom_as_lwline(lwgeom_from_gserialized(geom)); ipa = line->points; /* If distance is one of the two extremes, return the point on that * end rather than doing any expensive computations */ if ( distance == 0.0 || distance == 1.0 ) { if ( distance == 0.0 ) getPoint4d_p(ipa, 0, &pt); else getPoint4d_p(ipa, ipa->npoints-1, &pt); opa = ptarray_construct_reference_data(FLAGS_GET_Z(line->flags), FLAGS_GET_M(line->flags), 1, (uint8_t*)&pt); point = lwpoint_construct(line->srid, NULL, opa); PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(point))); } /* Interpolate a point on the line */ nsegs = ipa->npoints - 1; length = ptarray_length_2d(ipa); tlength = 0; for ( i = 0; i < nsegs; i++ ) { POINT4D p1, p2; POINT4D *p1ptr=&p1, *p2ptr=&p2; /* don't break * strict-aliasing rules */ getPoint4d_p(ipa, i, &p1); getPoint4d_p(ipa, i+1, &p2); /* Find the relative length of this segment */ slength = distance2d_pt_pt((POINT2D*)p1ptr, (POINT2D*)p2ptr)/length; /* If our target distance is before the total length we've seen * so far. create a new point some distance down the current * segment. */ if ( distance < tlength + slength ) { double dseg = (distance - tlength) / slength; interpolate_point4d(&p1, &p2, &pt, dseg); opa = ptarray_construct_reference_data(FLAGS_GET_Z(line->flags), FLAGS_GET_M(line->flags), 1, (uint8_t*)&pt); point = lwpoint_construct(line->srid, NULL, opa); PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(point))); } tlength += slength; } /* Return the last point on the line. This shouldn't happen, but * could if there's some floating point rounding errors. */ getPoint4d_p(ipa, ipa->npoints-1, &pt); opa = ptarray_construct_reference_data(FLAGS_GET_Z(line->flags), FLAGS_GET_M(line->flags), 1, (uint8_t*)&pt); point = lwpoint_construct(line->srid, NULL, opa); PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(point))); }
/** * Take in a LINESTRING and return a MULTILINESTRING of those portions of the * LINESTRING between the from/to range for the specified ordinate (XYZM) */ LWCOLLECTION* lwline_clip_to_ordinate_range(const LWLINE *line, char ordinate, double from, double to) { POINTARRAY *pa_in = NULL; LWCOLLECTION *lwgeom_out = NULL; POINTARRAY *dp = NULL; int i, rv; int added_last_point = 0; POINT4D *p = NULL, *q = NULL, *r = NULL; double ordinate_value_p = 0.0, ordinate_value_q = 0.0; char hasz = lwgeom_has_z(lwline_as_lwgeom(line)); char hasm = lwgeom_has_m(lwline_as_lwgeom(line)); char dims = FLAGS_NDIMS(line->flags); /* Null input, nothing we can do. */ if ( ! line ) { lwerror("Null input geometry."); return NULL; } /* Ensure 'from' is less than 'to'. */ if ( to < from ) { double t = from; from = to; to = t; } LWDEBUGF(4, "from = %g, to = %g, ordinate = %c", from, to, ordinate); LWDEBUGF(4, "%s", lwgeom_to_ewkt((LWGEOM*)line)); /* Asking for an ordinate we don't have. Error. */ if ( (ordinate == 'Z' && ! hasz) || (ordinate == 'M' && ! hasm) ) { lwerror("Cannot clip on ordinate %d in a %d-d geometry.", ordinate, dims); return NULL; } /* Prepare our working point objects. */ p = lwalloc(sizeof(POINT4D)); q = lwalloc(sizeof(POINT4D)); r = lwalloc(sizeof(POINT4D)); /* Construct a collection to hold our outputs. */ lwgeom_out = lwcollection_construct_empty(MULTILINETYPE, line->srid, hasz, hasm); /* Get our input point array */ pa_in = line->points; for ( i = 0; i < pa_in->npoints; i++ ) { LWDEBUGF(4, "Point #%d", i); LWDEBUGF(4, "added_last_point %d", added_last_point); if ( i > 0 ) { *q = *p; ordinate_value_q = ordinate_value_p; } rv = getPoint4d_p(pa_in, i, p); ordinate_value_p = lwpoint_get_ordinate(p, ordinate); LWDEBUGF(4, " ordinate_value_p %g (current)", ordinate_value_p); LWDEBUGF(4, " ordinate_value_q %g (previous)", ordinate_value_q); /* Is this point inside the ordinate range? Yes. */ if ( ordinate_value_p >= from && ordinate_value_p <= to ) { LWDEBUGF(4, " inside ordinate range (%g, %g)", from, to); if ( ! added_last_point ) { LWDEBUG(4," new ptarray required"); /* We didn't add the previous point, so this is a new segment. * Make a new point array. */ dp = ptarray_construct_empty(hasz, hasm, 32); /* We're transiting into the range so add an interpolated * point at the range boundary. * If we're on a boundary and crossing from the far side, * we also need an interpolated point. */ if ( i > 0 && ( /* Don't try to interpolate if this is the first point */ ( ordinate_value_p > from && ordinate_value_p < to ) || /* Inside */ ( ordinate_value_p == from && ordinate_value_q > to ) || /* Hopping from above */ ( ordinate_value_p == to && ordinate_value_q < from ) ) ) /* Hopping from below */ { double interpolation_value; (ordinate_value_q > to) ? (interpolation_value = to) : (interpolation_value = from); rv = point_interpolate(q, p, r, hasz, hasm, ordinate, interpolation_value); rv = ptarray_append_point(dp, r, LW_FALSE); LWDEBUGF(4, "[0] interpolating between (%g, %g) with interpolation point (%g)", ordinate_value_q, ordinate_value_p, interpolation_value); } } /* Add the current vertex to the point array. */ rv = ptarray_append_point(dp, p, LW_FALSE); if ( ordinate_value_p == from || ordinate_value_p == to ) { added_last_point = 2; /* Added on boundary. */ } else { added_last_point = 1; /* Added inside range. */ } } /* Is this point inside the ordinate range? No. */ else { LWDEBUGF(4, " added_last_point (%d)", added_last_point); if ( added_last_point == 1 ) { /* We're transiting out of the range, so add an interpolated point * to the point array at the range boundary. */ double interpolation_value; (ordinate_value_p > to) ? (interpolation_value = to) : (interpolation_value = from); rv = point_interpolate(q, p, r, hasz, hasm, ordinate, interpolation_value); rv = ptarray_append_point(dp, r, LW_FALSE); LWDEBUGF(4, " [1] interpolating between (%g, %g) with interpolation point (%g)", ordinate_value_q, ordinate_value_p, interpolation_value); } else if ( added_last_point == 2 ) { /* We're out and the last point was on the boundary. * If the last point was the near boundary, nothing to do. * If it was the far boundary, we need an interpolated point. */ if ( from != to && ( (ordinate_value_q == from && ordinate_value_p > from) || (ordinate_value_q == to && ordinate_value_p < to) ) ) { double interpolation_value; (ordinate_value_p > to) ? (interpolation_value = to) : (interpolation_value = from); rv = point_interpolate(q, p, r, hasz, hasm, ordinate, interpolation_value); rv = ptarray_append_point(dp, r, LW_FALSE); LWDEBUGF(4, " [2] interpolating between (%g, %g) with interpolation point (%g)", ordinate_value_q, ordinate_value_p, interpolation_value); } } else if ( i && ordinate_value_q < from && ordinate_value_p > to ) { /* We just hopped over the whole range, from bottom to top, * so we need to add *two* interpolated points! */ dp = ptarray_construct(hasz, hasm, 2); /* Interpolate lower point. */ rv = point_interpolate(p, q, r, hasz, hasm, ordinate, from); ptarray_set_point4d(dp, 0, r); /* Interpolate upper point. */ rv = point_interpolate(p, q, r, hasz, hasm, ordinate, to); ptarray_set_point4d(dp, 1, r); } else if ( i && ordinate_value_q > to && ordinate_value_p < from ) { /* We just hopped over the whole range, from top to bottom, * so we need to add *two* interpolated points! */ dp = ptarray_construct(hasz, hasm, 2); /* Interpolate upper point. */ rv = point_interpolate(p, q, r, hasz, hasm, ordinate, to); ptarray_set_point4d(dp, 0, r); /* Interpolate lower point. */ rv = point_interpolate(p, q, r, hasz, hasm, ordinate, from); ptarray_set_point4d(dp, 1, r); } /* We have an extant point-array, save it out to a multi-line. */ if ( dp ) { LWDEBUG(4, "saving pointarray to multi-line (1)"); /* Only one point, so we have to make an lwpoint to hold this * and set the overall output type to a generic collection. */ if ( dp->npoints == 1 ) { LWPOINT *opoint = lwpoint_construct(line->srid, NULL, dp); lwgeom_out->type = COLLECTIONTYPE; lwgeom_out = lwcollection_add_lwgeom(lwgeom_out, lwpoint_as_lwgeom(opoint)); } else { LWLINE *oline = lwline_construct(line->srid, NULL, dp); lwgeom_out = lwcollection_add_lwgeom(lwgeom_out, lwline_as_lwgeom(oline)); } /* Pointarray is now owned by lwgeom_out, so drop reference to it */ dp = NULL; } added_last_point = 0; } } /* Still some points left to be saved out. */ if ( dp && dp->npoints > 0 ) { LWDEBUG(4, "saving pointarray to multi-line (2)"); LWDEBUGF(4, "dp->npoints == %d", dp->npoints); LWDEBUGF(4, "lwgeom_out->ngeoms == %d", lwgeom_out->ngeoms); if ( dp->npoints == 1 ) { LWPOINT *opoint = lwpoint_construct(line->srid, NULL, dp); lwgeom_out->type = COLLECTIONTYPE; lwgeom_out = lwcollection_add_lwgeom(lwgeom_out, lwpoint_as_lwgeom(opoint)); } else { LWLINE *oline = lwline_construct(line->srid, NULL, dp); lwgeom_out = lwcollection_add_lwgeom(lwgeom_out, lwline_as_lwgeom(oline)); } /* Pointarray is now owned by lwgeom_out, so drop reference to it */ dp = NULL; } lwfree(p); lwfree(q); lwfree(r); if ( lwgeom_out->ngeoms > 0 ) { lwgeom_drop_bbox((LWGEOM*)lwgeom_out); lwgeom_add_bbox((LWGEOM*)lwgeom_out); } return lwgeom_out; }
Datum BOX3D_to_LWGEOM(PG_FUNCTION_ARGS) { BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0); POINTARRAY *pa; GSERIALIZED *result; POINT4D pt; /** * Alter BOX3D cast so that a valid geometry is always * returned depending upon the size of the BOX3D. The * code makes the following assumptions: * - If the BOX3D is a single point then return a * POINT geometry * - If the BOX3D represents either a horizontal or * vertical line, return a LINESTRING geometry * - Otherwise return a POLYGON */ pa = ptarray_construct_empty(0, 0, 5); if ( (box->xmin == box->xmax) && (box->ymin == box->ymax) ) { LWPOINT *lwpt = lwpoint_construct(SRID_UNKNOWN, NULL, pa); pt.x = box->xmin; pt.y = box->ymin; ptarray_append_point(pa, &pt, LW_TRUE); result = geometry_serialize(lwpoint_as_lwgeom(lwpt)); } else if (box->xmin == box->xmax || box->ymin == box->ymax) { LWLINE *lwline = lwline_construct(SRID_UNKNOWN, NULL, pa); 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); result = geometry_serialize(lwline_as_lwgeom(lwline)); } else { LWPOLY *lwpoly = lwpoly_construct(SRID_UNKNOWN, NULL, 1, &pa); 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); result = geometry_serialize(lwpoly_as_lwgeom(lwpoly)); } gserialized_set_srid(result, box->srid); PG_RETURN_POINTER(result); }