/** * 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)); }
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; } }
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; } }
/** * MULTILINESTRING */ static LWCOLLECTION* lwmultiline_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 lwmultilinestring_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 = lwline_as_lwgeom(lwline_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 * lwline_unstroke(const LWLINE *line) { LWDEBUG(2, "lwline_unstroke called."); if ( line->points->npoints < 4 ) return lwline_as_lwgeom(lwline_clone(line)); else return pta_unstroke(line->points, line->flags, line->srid); }
static void test_ptarray_insert_point(void) { LWLINE *line; char *wkt; POINT4D p; line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING EMPTY")); p.x = 1; p.y = 1; ptarray_insert_point(line->points, &p, 0); wkt = lwgeom_to_text(lwline_as_lwgeom(line)); CU_ASSERT_STRING_EQUAL(wkt,"LINESTRING(1 1)"); lwfree(wkt); p.x = 2; p.y = 20; ptarray_insert_point(line->points, &p, 0); wkt = lwgeom_to_text(lwline_as_lwgeom(line)); CU_ASSERT_STRING_EQUAL(wkt,"LINESTRING(2 20,1 1)"); lwfree(wkt); p.x = 3; p.y = 30; ptarray_insert_point(line->points, &p, 1); wkt = lwgeom_to_text(lwline_as_lwgeom(line)); CU_ASSERT_STRING_EQUAL(wkt,"LINESTRING(2 20,3 30,1 1)"); lwfree(wkt); p.x = 4; p.y = 40; ptarray_insert_point(line->points, &p, 0); wkt = lwgeom_to_text(lwline_as_lwgeom(line)); CU_ASSERT_STRING_EQUAL(wkt,"LINESTRING(4 40,2 20,3 30,1 1)"); lwfree(wkt); p.x = 5; p.y = 50; ptarray_insert_point(line->points, &p, 4); wkt = lwgeom_to_text(lwline_as_lwgeom(line)); CU_ASSERT_STRING_EQUAL(wkt,"LINESTRING(4 40,2 20,3 30,1 1,5 50)"); lwfree(wkt); lwline_free(line); }
static void test_ptarray_append_point(void) { LWLINE *line; char *wkt; POINT4D p; line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,1 1)")); p.x = 1; p.y = 1; ptarray_append_point(line->points, &p, LW_TRUE); wkt = lwgeom_to_text(lwline_as_lwgeom(line)); CU_ASSERT_STRING_EQUAL(wkt,"LINESTRING(0 0,1 1,1 1)"); lwfree(wkt); ptarray_append_point(line->points, &p, LW_FALSE); wkt = lwgeom_to_text(lwline_as_lwgeom(line)); CU_ASSERT_STRING_EQUAL(wkt,"LINESTRING(0 0,1 1,1 1)"); lwfree(wkt); lwline_free(line); }
LWGEOM* lwgeom_offsetcurve(const LWLINE *lwline, double size, int quadsegs, int joinStyle, double mitreLimit) { #if POSTGIS_GEOS_VERSION < 32 lwerror("lwgeom_offsetcurve: GEOS 3.2 or higher required"); #else GEOSGeometry *g1, *g3; LWGEOM *lwgeom_result; LWGEOM *lwgeom_in = lwline_as_lwgeom(lwline); initGEOS(lwnotice, lwgeom_geos_error); g1 = (GEOSGeometry *)LWGEOM2GEOS(lwgeom_in); if ( ! g1 ) { lwerror("lwgeom_offsetcurve: Geometry could not be converted to GEOS: %s", lwgeom_geos_errmsg); return NULL; } #if POSTGIS_GEOS_VERSION < 33 /* Size is always positive for GEOSSingleSidedBuffer, and a flag determines left/right */ g3 = GEOSSingleSidedBuffer(g1, size < 0 ? -size : size, quadsegs, joinStyle, mitreLimit, size < 0 ? 0 : 1); #else g3 = GEOSOffsetCurve(g1, size, quadsegs, joinStyle, mitreLimit); #endif /* Don't need input geometry anymore */ GEOSGeom_destroy(g1); if (g3 == NULL) { GEOSGeom_destroy(g1); lwerror("GEOSOffsetCurve: %s", lwgeom_geos_errmsg); return NULL; } LWDEBUGF(3, "result: %s", GEOSGeomToWKT(g3)); GEOSSetSRID(g3, lwgeom_get_srid(lwgeom_in)); lwgeom_result = GEOS2LWGEOM(g3, lwgeom_has_z(lwgeom_in)); GEOSGeom_destroy(g3); if (lwgeom_result == NULL) { lwerror("lwgeom_offsetcurve: GEOS2LWGEOM returned null"); return NULL; } return lwgeom_result; #endif /* POSTGIS_GEOS_VERSION < 32 */ }
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)); }
static LWMPOINT* lwline_locate_along(const LWLINE *lwline, double m, double offset) { POINTARRAY *opa = NULL; LWMPOINT *mp = NULL; LWGEOM *lwg = lwline_as_lwgeom(lwline); int hasz, hasm, srid; /* Return degenerates upwards */ if ( ! lwline ) return NULL; /* Create empty return shell */ srid = lwgeom_get_srid(lwg); hasz = lwgeom_has_z(lwg); hasm = lwgeom_has_m(lwg); if ( hasm ) { /* Find points along */ opa = ptarray_locate_along(lwline->points, m, offset); } else { LWLINE *lwline_measured = lwline_measured_from_lwline(lwline, 0.0, 1.0); opa = ptarray_locate_along(lwline_measured->points, m, offset); lwline_free(lwline_measured); } /* Return NULL as EMPTY */ if ( ! opa ) return lwmpoint_construct_empty(srid, hasz, hasm); /* Convert pointarray into a multipoint */ mp = lwmpoint_construct(srid, opa); ptarray_free(opa); return mp; }
static void test_ptarray_append_ptarray(void) { LWLINE *line1, *line2; int ret; char *wkt; /* Empty first line */ line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING EMPTY")); line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,0 10,5 5)")); ret = ptarray_append_ptarray(line1->points, line2->points, -1); CU_ASSERT(ret == LW_SUCCESS); wkt = lwgeom_to_text(lwline_as_lwgeom(line1)); CU_ASSERT_STRING_EQUAL(wkt, "LINESTRING(0 0,0 10,5 5)"); lwfree(wkt); lwline_free(line2); lwline_free(line1); /* Empty second line */ line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0, 5 5, 6 3)")); line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING EMPTY")); ret = ptarray_append_ptarray(line1->points, line2->points, -1); CU_ASSERT(ret == LW_SUCCESS); wkt = lwgeom_to_text(lwline_as_lwgeom(line1)); CU_ASSERT_STRING_EQUAL(wkt, "LINESTRING(0 0,5 5,6 3)"); lwfree(wkt); lwline_free(line2); lwline_free(line1); /* Both lines empty */ line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING EMPTY")); line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING EMPTY")); ret = ptarray_append_ptarray(line1->points, line2->points, -1); CU_ASSERT(ret == LW_SUCCESS); wkt = lwgeom_to_text(lwline_as_lwgeom(line1)); CU_ASSERT_STRING_EQUAL(wkt, "LINESTRING EMPTY"); lwfree(wkt); lwline_free(line2); lwline_free(line1); /* Sane sewing */ line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(10 4, 0 0,5 7)")); line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(5 7,12 43, 42 15)")); ret = ptarray_append_ptarray(line1->points, line2->points, 0); CU_ASSERT(ret == LW_SUCCESS); wkt = lwgeom_to_text(lwline_as_lwgeom(line1)); CU_ASSERT_STRING_EQUAL(wkt, "LINESTRING(10 4,0 0,5 7,12 43,42 15)"); lwfree(wkt); lwline_free(line2); lwline_free(line1); /* Untolerated sewing */ line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(10 4, 0 0,5 7)")); line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(5.5 7,12 43, 42 15)")); ret = ptarray_append_ptarray(line1->points, line2->points, 0); CU_ASSERT(ret == LW_FAILURE); lwline_free(line2); lwline_free(line1); /* Tolerated sewing */ line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(10 4, 0 0,5 7)")); line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(5.5 7,12 43, 42 15)")); ret = ptarray_append_ptarray(line1->points, line2->points, .7); CU_ASSERT(ret == LW_SUCCESS); wkt = lwgeom_to_text(lwline_as_lwgeom(line1)); CU_ASSERT_STRING_EQUAL(wkt, "LINESTRING(10 4,0 0,5 7,5.5 7,12 43,42 15)"); lwfree(wkt); lwline_free(line2); lwline_free(line1); /* Check user input trust (creates non-simple line */ line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,0 10)")); line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,0 10)")); ret = ptarray_append_ptarray(line1->points, line2->points, -1); CU_ASSERT(ret == LW_SUCCESS); wkt = lwgeom_to_text(lwline_as_lwgeom(line1)); CU_ASSERT_STRING_EQUAL(wkt, "LINESTRING(0 0,0 10,0 0,0 10)"); lwfree(wkt); lwline_free(line2); lwline_free(line1); /* Mixed dimensionality is not allowed */ line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 10 0, 10 0 0)")); line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(10 0,11 0)")); ret = ptarray_append_ptarray(line1->points, line2->points, -1); CU_ASSERT(ret == LW_FAILURE); lwline_free(line2); lwline_free(line1); /* Appending a read-only pointarray is allowed */ line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 10, 10 0)")); line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(10 0,11 0)")); FLAGS_SET_READONLY(line2->points->flags, 1); ret = ptarray_append_ptarray(line1->points, line2->points, -1); CU_ASSERT(ret == LW_SUCCESS); wkt = lwgeom_to_text(lwline_as_lwgeom(line1)); CU_ASSERT_STRING_EQUAL(wkt, "LINESTRING(0 10,10 0,11 0)"); lwfree(wkt); FLAGS_SET_READONLY(line2->points->flags, 0); /* for lwline_free */ lwline_free(line2); lwline_free(line1); /* Appending to a read-only pointarray is forbidden */ line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 10, 10 0)")); line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(10 0,11 0)")); FLAGS_SET_READONLY(line1->points->flags, 1); ret = ptarray_append_ptarray(line1->points, line2->points, -1); CU_ASSERT(ret == LW_FAILURE); lwline_free(line2); FLAGS_SET_READONLY(line1->points->flags, 0); /* for lwline_free */ lwline_free(line1); }
void lwline_release(LWLINE *lwline) { lwgeom_release(lwline_as_lwgeom(lwline)); }
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); }
Datum LWGEOM_exteriorring_polygon(PG_FUNCTION_ARGS) { GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); GSERIALIZED *result; POINTARRAY *extring; LWGEOM *lwgeom; LWLINE *line; GBOX *bbox=NULL; int type = gserialized_get_type(geom); POSTGIS_DEBUG(2, "LWGEOM_exteriorring_polygon called."); if ( (type != POLYGONTYPE) && (type != CURVEPOLYTYPE) && (type != TRIANGLETYPE)) { elog(ERROR, "ExteriorRing: geom is not a polygon"); PG_RETURN_NULL(); } lwgeom = lwgeom_from_gserialized(geom); if( lwgeom_is_empty(lwgeom) ) { line = lwline_construct_empty(lwgeom->srid, lwgeom_has_z(lwgeom), lwgeom_has_m(lwgeom)); result = geometry_serialize(lwline_as_lwgeom(line)); } else if ( lwgeom->type == POLYGONTYPE ) { LWPOLY *poly = lwgeom_as_lwpoly(lwgeom); /* 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 = gbox_copy(poly->bbox); line = lwline_construct(poly->srid, bbox, extring); result = geometry_serialize((LWGEOM *)line); lwgeom_release((LWGEOM *)line); } else if ( lwgeom->type == TRIANGLETYPE ) { LWTRIANGLE *triangle = lwgeom_as_lwtriangle(lwgeom); /* * 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 ( triangle->bbox ) bbox = gbox_copy(triangle->bbox); line = lwline_construct(triangle->srid, bbox, triangle->points); result = geometry_serialize((LWGEOM *)line); lwgeom_release((LWGEOM *)line); } else { LWCURVEPOLY *curvepoly = lwgeom_as_lwcurvepoly(lwgeom); result = geometry_serialize(curvepoly->rings[0]); } lwgeom_free(lwgeom); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(result); }
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); }
/** * @brief Generate an allocated geometry string for shapefile object obj using the state parameters */ int GenerateLineStringGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry) { LWCOLLECTION *lwcollection = NULL; LWGEOM **lwmultilinestrings; uchar *serialized_lwgeom; LWGEOM_UNPARSER_RESULT lwg_unparser_result; DYNPTARRAY **dpas; POINT4D point4d; int dims = 0, hasz = 0, hasm = 0; int result; int u, v, start_vertex, end_vertex; 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); if (state->config->simple_geometries == 1 && obj->nParts > 1) { snprintf(state->message, SHPLOADERMSGLEN, "We have a Multilinestring with %d parts, can't use -S switch!", obj->nParts); return SHPLOADERERR; } /* Allocate memory for our array of LWLINEs and our dynptarrays */ lwmultilinestrings = malloc(sizeof(LWPOINT *) * obj->nParts); dpas = malloc(sizeof(DYNPTARRAY *) * obj->nParts); /* We need an array of pointers to each of our sub-geometries */ for (u = 0; u < obj->nParts; u++) { /* Create a dynptarray containing the line points */ dpas[u] = dynptarray_create(obj->nParts, dims); /* Set the start/end vertices depending upon whether this is a MULTILINESTRING or not */ if ( u == obj->nParts-1 ) end_vertex = obj->nVertices; else end_vertex = obj->panPartStart[u + 1]; start_vertex = obj->panPartStart[u]; for (v = start_vertex; v < end_vertex; v++) { /* Generate the point */ point4d.x = obj->padfX[v]; point4d.y = obj->padfY[v]; if (state->wkbtype & WKBZOFFSET) point4d.z = obj->padfZ[v]; if (state->wkbtype & WKBMOFFSET) point4d.m = obj->padfM[v]; dynptarray_addPoint4d(dpas[u], &point4d, 0); } /* Generate the LWLINE */ lwmultilinestrings[u] = lwline_as_lwgeom(lwline_construct(state->config->sr_id, NULL, dpas[u]->pa)); } /* If using MULTILINESTRINGs then generate the serialized collection, otherwise just a single LINESTRING */ if (state->config->simple_geometries == 0) { lwcollection = lwcollection_construct(MULTILINETYPE, state->config->sr_id, NULL, obj->nParts, lwmultilinestrings); /* When outputting wkt rather than wkb, we need to remove the SRID from the inner geometries */ if (state->config->hwgeom) { for (u = 0; u < obj->nParts; u++) lwmultilinestrings[u]->SRID = -1; } serialized_lwgeom = lwgeom_serialize(lwcollection_as_lwgeom(lwcollection)); } else { serialized_lwgeom = lwgeom_serialize(lwmultilinestrings[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); /* Return the error message if we failed */ 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->nParts; u++) { lwfree(dpas[u]->pa->serialized_pointlist); lwline_free(lwgeom_as_lwline(lwmultilinestrings[u])); lwfree(dpas[u]); } lwfree(dpas); lwfree(lwmultilinestrings); if (lwcollection) lwfree(lwcollection); /* Return the string - everything ok */ *geometry = mem; return SHPLOADEROK; }
/** * 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; }
/** * @brief Generate an allocated geometry string for shapefile object obj using the state parameters */ int GenerateLineStringGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry) { LWGEOM **lwmultilinestrings; LWGEOM *lwgeom = NULL; POINT4D point4d; int dims = 0; int u, v, start_vertex, end_vertex; char *mem; size_t mem_length; FLAGS_SET_Z(dims, state->has_z); FLAGS_SET_M(dims, state->has_m); if (state->config->simple_geometries == 1 && obj->nParts > 1) { snprintf(state->message, SHPLOADERMSGLEN, _("We have a Multilinestring with %d parts, can't use -S switch!"), obj->nParts); return SHPLOADERERR; } /* Allocate memory for our array of LWLINEs and our dynptarrays */ lwmultilinestrings = malloc(sizeof(LWPOINT *) * obj->nParts); /* We need an array of pointers to each of our sub-geometries */ for (u = 0; u < obj->nParts; u++) { /* Create a ptarray containing the line points */ POINTARRAY *pa = ptarray_construct_empty(state->has_z, state->has_m, obj->nParts); /* Set the start/end vertices depending upon whether this is a MULTILINESTRING or not */ if ( u == obj->nParts-1 ) end_vertex = obj->nVertices; else end_vertex = obj->panPartStart[u + 1]; start_vertex = obj->panPartStart[u]; for (v = start_vertex; v < end_vertex; v++) { /* Generate the point */ point4d.x = obj->padfX[v]; point4d.y = obj->padfY[v]; if (state->has_z) point4d.z = obj->padfZ[v]; if (state->has_m) point4d.m = obj->padfM[v]; ptarray_append_point(pa, &point4d, LW_FALSE); } /* Generate the LWLINE */ lwmultilinestrings[u] = lwline_as_lwgeom(lwline_construct(state->from_srid, NULL, pa)); } /* If using MULTILINESTRINGs then generate the serialized collection, otherwise just a single LINESTRING */ if (state->config->simple_geometries == 0) { lwgeom = lwcollection_as_lwgeom(lwcollection_construct(MULTILINETYPE, state->from_srid, NULL, obj->nParts, lwmultilinestrings)); } else { lwgeom = lwmultilinestrings[0]; lwfree(lwmultilinestrings); } if (!state->config->use_wkt) mem = lwgeom_to_hexwkb(lwgeom, WKB_EXTENDED, &mem_length); else mem = lwgeom_to_wkt(lwgeom, WKT_EXTENDED, WKT_PRECISION, &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; }