static void test_ptarray_signed_area() { LWLINE *line; double area; /* parallelogram */ line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,1 1, 2 1, 1 0, 0 0)")); area = ptarray_signed_area(line->points); CU_ASSERT_DOUBLE_EQUAL(area, 1.0, 0.0000001); lwline_free(line); /* square */ line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,0 2, 2 2, 2 0, 0 0)")); area = ptarray_signed_area(line->points); CU_ASSERT_DOUBLE_EQUAL(area, 4.0, 0.0000001); lwline_free(line); /* square backwares*/ line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,2 0, 2 2, 0 2, 0 0)")); area = ptarray_signed_area(line->points); //printf("%g\n",area); CU_ASSERT_DOUBLE_EQUAL(area, -4.0, 0.0000001); lwline_free(line); }
Datum ST_LineCrossingDirection(PG_FUNCTION_ARGS) { int type1, type2, rv; LWLINE *l1 = NULL; LWLINE *l2 = NULL; GSERIALIZED *geom1 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); GSERIALIZED *geom2 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); error_if_srid_mismatch(gserialized_get_srid(geom1), gserialized_get_srid(geom2)); type1 = gserialized_get_type(geom1); type2 = gserialized_get_type(geom2); if ( type1 != LINETYPE || type2 != LINETYPE ) { elog(ERROR,"This function only accepts LINESTRING as arguments."); PG_RETURN_NULL(); } l1 = lwgeom_as_lwline(lwgeom_from_gserialized(geom1)); l2 = lwgeom_as_lwline(lwgeom_from_gserialized(geom2)); rv = lwline_crossing_direction(l1, l2); PG_FREE_IF_COPY(geom1, 0); PG_FREE_IF_COPY(geom2, 1); PG_RETURN_INT32(rv); }
static void test_ptarray_locate_point(void) { LWLINE *line; double loc, dist; POINT4D p, l; line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 3,20 4)")); p = getPoint4d(line->points, 0); loc = ptarray_locate_point(line->points, &p, &dist, &l); CU_ASSERT_EQUAL(loc, 0); CU_ASSERT_EQUAL(dist, 0.0); p = getPoint4d(line->points, 1); loc = ptarray_locate_point(line->points, &p, &dist, &l); CU_ASSERT_EQUAL(loc, 1); CU_ASSERT_EQUAL(dist, 0.0); p.x = 21; p.y = 4; loc = ptarray_locate_point(line->points, &p, &dist, NULL); CU_ASSERT_EQUAL(loc, 1); CU_ASSERT_EQUAL(dist, 1.0); p.x = 0; p.y = 2; loc = ptarray_locate_point(line->points, &p, &dist, &l); CU_ASSERT_EQUAL(loc, 0); CU_ASSERT_EQUAL(dist, 1.0); lwline_free(line); line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,20 0,40 0)")); p.x = 20; p.y = 0; loc = ptarray_locate_point(line->points, &p, &dist, &l); CU_ASSERT_EQUAL(loc, 0.5); CU_ASSERT_EQUAL(dist, 0.0); lwline_free(line); line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-40 0,0 0,20 0,40 0)")); p.x = 20; p.y = 0; loc = ptarray_locate_point(line->points, &p, &dist, &l); CU_ASSERT_EQUAL(loc, 0.75); CU_ASSERT_EQUAL(dist, 0.0); lwline_free(line); line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING M (0 0 0, 10 0 20)")); p.x = 5; p.y = 0; loc = ptarray_locate_point(line->points, &p, &dist, &l); CU_ASSERT_EQUAL(loc, 0.5); CU_ASSERT_EQUAL(dist, 0.0); CU_ASSERT_EQUAL(l.m, 10.0); lwline_free(line); }
double lwgeom_interpolate_point(const LWGEOM *lwin, const LWPOINT *lwpt) { POINT4D p, p_proj; double ret = 0.0; if ( ! lwin ) lwerror("lwgeom_interpolate_point: null input geometry!"); if ( ! lwgeom_has_m(lwin) ) lwerror("Input geometry does not have a measure dimension"); if ( lwgeom_is_empty(lwin) || lwpoint_is_empty(lwpt) ) lwerror("Input geometry is empty"); switch ( lwin->type ) { case LINETYPE: { LWLINE *lwline = lwgeom_as_lwline(lwin); lwpoint_getPoint4d_p(lwpt, &p); ret = ptarray_locate_point(lwline->points, &p, NULL, &p_proj); ret = p_proj.m; break; } default: lwerror("This function does not accept %s geometries.", lwtype_name(lwin->type)); } return ret; }
Datum LWGEOM_line_locate_point(PG_FUNCTION_ARGS) { GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0); GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1); LWLINE *lwline; LWPOINT *lwpoint; POINTARRAY *pa; POINT4D p, p_proj; double ret; if ( gserialized_get_type(geom1) != LINETYPE ) { elog(ERROR,"line_locate_point: 1st arg isn't a line"); PG_RETURN_NULL(); } if ( gserialized_get_type(geom2) != POINTTYPE ) { elog(ERROR,"line_locate_point: 2st arg isn't a point"); PG_RETURN_NULL(); } error_if_srid_mismatch(gserialized_get_srid(geom1), gserialized_get_srid(geom2)); lwline = lwgeom_as_lwline(lwgeom_from_gserialized(geom1)); lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(geom2)); pa = lwline->points; lwpoint_getPoint4d_p(lwpoint, &p); ret = ptarray_locate_point(pa, &p, NULL, &p_proj); PG_RETURN_FLOAT8(ret); }
int lwcompound_contains_point(const LWCOMPOUND *comp, const POINT2D *pt) { int i; LWLINE *lwline; LWCIRCSTRING *lwcirc; int wn = 0; int winding_number = 0; int result; for ( i = 0; i < comp->ngeoms; i++ ) { LWGEOM *lwgeom = comp->geoms[i]; if ( lwgeom->type == LINETYPE ) { lwline = lwgeom_as_lwline(lwgeom); if ( comp->ngeoms == 1 ) { return ptarray_contains_point(lwline->points, pt); } else { /* Don't check closure while doing p-i-p test */ result = ptarray_contains_point_partial(lwline->points, pt, LW_FALSE, &winding_number); } } else { lwcirc = lwgeom_as_lwcircstring(lwgeom); if ( ! lwcirc ) { lwerror("Unexpected component of type %s in compound curve", lwtype_name(lwgeom->type)); return 0; } if ( comp->ngeoms == 1 ) { return ptarrayarc_contains_point(lwcirc->points, pt); } else { /* Don't check closure while doing p-i-p test */ result = ptarrayarc_contains_point_partial(lwcirc->points, pt, LW_FALSE, &winding_number); } } /* Propogate boundary condition */ if ( result == LW_BOUNDARY ) return LW_BOUNDARY; wn += winding_number; } /* Outside */ if (wn == 0) return LW_OUTSIDE; /* Inside */ return LW_INSIDE; }
static void test_ptarray_isccw(void) { LWLINE *line; LWPOLY* poly; int ccw; /* clockwise rectangle */ line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,0 10,10 10,10 0, 0 0)")); ccw = ptarray_isccw(line->points); CU_ASSERT_EQUAL(ccw, 0); lwline_free(line); /* clockwise triangle */ line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 3,20 4,20 3, 0 3)")); ccw = ptarray_isccw(line->points); CU_ASSERT_EQUAL(ccw, 0); lwline_free(line); /* counterclockwise triangle */ line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 3,20 3,20 4, 0 3)")); ccw = ptarray_isccw(line->points); CU_ASSERT_EQUAL(ccw, 1); lwline_free(line); /* counterclockwise narrow ring (see ticket #1302) */ line = lwgeom_as_lwline(lwgeom_from_hexwkb("01020000000500000000917E9BA468294100917E9B8AEA284137894120A4682941C976BE9F8AEA2841B39ABE1FA46829415ACCC29F8AEA2841C976BE1FA4682941C976BE9F8AEA284100917E9BA468294100917E9B8AEA2841", LW_PARSER_CHECK_NONE)); ccw = ptarray_isccw(line->points); CU_ASSERT_EQUAL(ccw, 1); lwline_free(line); /* clockwise narrow ring (see ticket #1302) */ line = lwgeom_as_lwline(lwgeom_from_hexwkb("01020000000500000000917E9BA468294100917E9B8AEA2841C976BE1FA4682941C976BE9F8AEA2841B39ABE1FA46829415ACCC29F8AEA284137894120A4682941C976BE9F8AEA284100917E9BA468294100917E9B8AEA2841", LW_PARSER_CHECK_NONE)); ccw = ptarray_isccw(line->points); CU_ASSERT_EQUAL(ccw, 0); lwline_free(line); /* Clockwise narrow ring (see ticket #1302) */ poly = lwgeom_as_lwpoly(lwgeom_from_hexwkb("0103000000010000000500000000917E9BA468294100917E9B8AEA2841C976BE1FA4682941C976BE9F8AEA2841B39ABE1FA46829415ACCC29F8AEA284137894120A4682941C976BE9F8AEA284100917E9BA468294100917E9B8AEA2841", LW_PARSER_CHECK_NONE)); ccw = ptarray_isccw(poly->rings[0]); CU_ASSERT_EQUAL(ccw, 0); lwpoly_free(poly); }
LWGEOM* lwgeom_flip_coordinates(LWGEOM *in) { LWCOLLECTION *col; LWPOLY *poly; int i; LWDEBUGF(4, "lwgeom_flip_coordinates, got type: %s", lwtype_name(in->type)); switch (in->type) { case POINTTYPE: ptarray_flip_coordinates(lwgeom_as_lwpoint(in)->point); return in; case LINETYPE: ptarray_flip_coordinates(lwgeom_as_lwline(in)->points); return in; case CIRCSTRINGTYPE: ptarray_flip_coordinates(lwgeom_as_lwcircstring(in)->points); return in; case POLYGONTYPE: poly = (LWPOLY *) in; for (i=0; i<poly->nrings; i++) ptarray_flip_coordinates(poly->rings[i]); return in; case TRIANGLETYPE: ptarray_flip_coordinates(lwgeom_as_lwtriangle(in)->points); return in; case MULTIPOINTTYPE: case MULTILINETYPE: case MULTIPOLYGONTYPE: case COLLECTIONTYPE: case COMPOUNDTYPE: case CURVEPOLYTYPE: case MULTISURFACETYPE: case MULTICURVETYPE: case POLYHEDRALSURFACETYPE: case TINTYPE: col = (LWCOLLECTION *) in; for (i=0; i<col->ngeoms; i++) lwgeom_flip_coordinates(col->geoms[i]); return in; default: lwerror("lwgeom_flip_coordinates: unsupported geometry type: %s", lwtype_name(in->type)); } return NULL; }
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_tree_circ_create(void) { LWLINE *g; CIRC_NODE *c; /* Line with 4 edges */ g = lwgeom_as_lwline(lwgeom_from_wkt("LINESTRING(0 88,0 89,0 90,180 89,180 88)", LW_PARSER_CHECK_NONE)); c = circ_tree_new(g->points); //circ_tree_print(c, 0); if ( CIRC_NODE_SIZE > 4 ) { CU_ASSERT(c->num_nodes == 4); } else { CU_ASSERT(c->num_nodes == ( 4 % CIRC_NODE_SIZE ? 1 : 0 ) + 4 / CIRC_NODE_SIZE); } circ_tree_free(c); lwline_free(g); }
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); }
Datum LWGEOM_line_locate_point(PG_FUNCTION_ARGS) { GSERIALIZED *geom1 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); GSERIALIZED *geom2 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); LWLINE *lwline; LWPOINT *lwpoint; POINTARRAY *pa; POINT2D p; double ret; if ( gserialized_get_type(geom1) != LINETYPE ) { elog(ERROR,"line_locate_point: 1st arg isnt a line"); PG_RETURN_NULL(); } if ( gserialized_get_type(geom2) != POINTTYPE ) { elog(ERROR,"line_locate_point: 2st arg isnt a point"); PG_RETURN_NULL(); } if ( gserialized_get_srid(geom1) != gserialized_get_srid(geom2) ) { elog(ERROR, "Operation on two geometries with different SRIDs"); PG_RETURN_NULL(); } lwline = lwgeom_as_lwline(lwgeom_from_gserialized(geom1)); lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(geom2)); pa = lwline->points; lwpoint_getPoint2d_p(lwpoint, &p); ret = ptarray_locate_point(pa, &p, NULL); PG_RETURN_FLOAT8(ret); }
static void test_ptarray_contains_point() { /* int ptarray_contains_point(const POINTARRAY *pa, const POINT2D *pt, int *winding_number) */ LWLINE *lwline; POINTARRAY *pa; POINT2D pt; int rv; lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0, 0 1, 1 1, 1 0, 0 0)")); pa = lwline->points; /* Point in middle of square */ pt.x = 0.5; pt.y = 0.5; rv = ptarray_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_INSIDE); /* Point on left edge of square */ pt.x = 0; pt.y = 0.5; rv = ptarray_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_BOUNDARY); /* Point on top edge of square */ pt.x = 0.5; pt.y = 1; rv = ptarray_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_BOUNDARY); /* Point on bottom left corner of square */ pt.x = 0; pt.y = 0; rv = ptarray_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_BOUNDARY); /* Point on top left corner of square */ pt.x = 0; pt.y = 1; rv = ptarray_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_BOUNDARY); /* Point outside top left corner of square */ pt.x = -0.1; pt.y = 1; rv = ptarray_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_OUTSIDE); /* Point outside top left corner of square */ pt.x = 0; pt.y = 1.1; rv = ptarray_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_OUTSIDE); /* Point outside left side of square */ pt.x = -0.2; pt.y = 0.5; rv = ptarray_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_OUTSIDE); lwline_free(lwline); lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0, 1 1, 2 0, 0 0)")); pa = lwline->points; /* Point outside grazing top of triangle */ pt.x = 0; pt.y = 1; rv = ptarray_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_OUTSIDE); lwline_free(lwline); lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0, 0 4, 1 4, 2 2, 3 4, 4 4, 4 0, 0 0)")); pa = lwline->points; /* Point outside grazing top of triangle */ pt.x = 1; pt.y = 2; rv = ptarray_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_INSIDE); /* Point outside grazing top of triangle */ pt.x = 3; pt.y = 2; rv = ptarray_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_INSIDE); lwline_free(lwline); }
Datum LWGEOM_dumppoints(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; MemoryContext oldcontext, newcontext; GSERIALIZED *pglwgeom; LWCOLLECTION *lwcoll; LWGEOM *lwgeom; struct dumpstate *state; struct dumpnode *node; HeapTuple tuple; Datum pathpt[2]; /* used to construct the composite return value */ bool isnull[2] = {0,0}; /* needed to say neither value is null */ Datum result; /* the actual composite return value */ if (SRF_IS_FIRSTCALL()) { funcctx = SRF_FIRSTCALL_INIT(); newcontext = funcctx->multi_call_memory_ctx; oldcontext = MemoryContextSwitchTo(newcontext); /* get a local copy of what we're doing a dump points on */ pglwgeom = PG_GETARG_GSERIALIZED_P_COPY(0); lwgeom = lwgeom_from_gserialized(pglwgeom); /* return early if nothing to do */ if (!lwgeom || lwgeom_is_empty(lwgeom)) { MemoryContextSwitchTo(oldcontext); funcctx = SRF_PERCALL_SETUP(); SRF_RETURN_DONE(funcctx); } /* Create function state */ state = lwalloc(sizeof *state); state->root = lwgeom; state->stacklen = 0; state->pathlen = 0; state->pt = 0; state->ring = 0; funcctx->user_fctx = state; /* * Push a struct dumpnode on the state stack */ state->stack[0].idx = 0; state->stack[0].geom = lwgeom; state->stacklen++; /* * get tuple description for return type */ if (get_call_result_type(fcinfo, 0, &funcctx->tuple_desc) != TYPEFUNC_COMPOSITE) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("set-valued function called in context that cannot accept a set"))); } BlessTupleDesc(funcctx->tuple_desc); /* get and cache data for constructing int4 arrays */ get_typlenbyvalalign(INT4OID, &state->typlen, &state->byval, &state->align); MemoryContextSwitchTo(oldcontext); } /* stuff done on every call of the function */ funcctx = SRF_PERCALL_SETUP(); newcontext = funcctx->multi_call_memory_ctx; /* get state */ state = funcctx->user_fctx; while (1) { node = &state->stack[state->stacklen-1]; lwgeom = node->geom; /* need to return a point from this geometry */ if (!lwgeom_is_collection(lwgeom)) { /* either return a point, or pop the stack */ /* TODO use a union? would save a tiny amount of stack space. * probably not worth the bother */ LWLINE *line; LWCIRCSTRING *circ; LWPOLY *poly; LWTRIANGLE *tri; LWPOINT *lwpoint = NULL; POINT4D pt; /* * net result of switch should be to set lwpoint to the * next point to return, or leave at NULL if there * are no more points in the geometry */ switch(lwgeom->type) { case TRIANGLETYPE: tri = lwgeom_as_lwtriangle(lwgeom); if (state->pt == 0) { state->path[state->pathlen++] = Int32GetDatum(state->ring+1); } if (state->pt <= 3) { getPoint4d_p(tri->points, state->pt, &pt); lwpoint = lwpoint_make(tri->srid, FLAGS_GET_Z(tri->points->flags), FLAGS_GET_M(tri->points->flags), &pt); } if (state->pt > 3) { state->pathlen--; } break; case POLYGONTYPE: poly = lwgeom_as_lwpoly(lwgeom); if (state->pt == poly->rings[state->ring]->npoints) { state->pt = 0; state->ring++; state->pathlen--; } if (state->pt == 0 && state->ring < poly->nrings) { /* handle new ring */ state->path[state->pathlen] = Int32GetDatum(state->ring+1); state->pathlen++; } if (state->ring == poly->nrings) { } else { /* TODO should be able to directly get the point * into the point array of a fixed lwpoint */ /* can't get the point directly from the ptarray because * it might be aligned wrong, so at least one memcpy * seems unavoidable * It might be possible to pass it directly to gserialized * depending how that works, it might effectively be gserialized * though a brief look at the code indicates not */ getPoint4d_p(poly->rings[state->ring], state->pt, &pt); lwpoint = lwpoint_make(poly->srid, FLAGS_GET_Z(poly->rings[state->ring]->flags), FLAGS_GET_M(poly->rings[state->ring]->flags), &pt); } break; case POINTTYPE: if (state->pt == 0) lwpoint = lwgeom_as_lwpoint(lwgeom); break; case LINETYPE: line = lwgeom_as_lwline(lwgeom); if (line->points && state->pt <= line->points->npoints) { lwpoint = lwline_get_lwpoint((LWLINE*)lwgeom, state->pt); } break; case CIRCSTRINGTYPE: circ = lwgeom_as_lwcircstring(lwgeom); if (circ->points && state->pt <= circ->points->npoints) { lwpoint = lwcircstring_get_lwpoint((LWCIRCSTRING*)lwgeom, state->pt); } break; default: ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), errmsg("Invalid Geometry type %d passed to ST_DumpPoints()", lwgeom->type))); } /* * At this point, lwpoint is either NULL, in which case * we need to pop the geometry stack and get the next * geometry, if amy, or lwpoint is set and we construct * a record type with the integer array of geometry * indexes and the point number, and the actual point * geometry itself */ if (!lwpoint) { /* no point, so pop the geom and look for more */ if (--state->stacklen == 0) SRF_RETURN_DONE(funcctx); state->pathlen--; continue; } else { /* write address of current geom/pt */ state->pt++; state->path[state->pathlen] = Int32GetDatum(state->pt); pathpt[0] = PointerGetDatum(construct_array(state->path, state->pathlen+1, INT4OID, state->typlen, state->byval, state->align)); pathpt[1] = PointerGetDatum(gserialized_from_lwgeom((LWGEOM*)lwpoint,0,0)); tuple = heap_form_tuple(funcctx->tuple_desc, pathpt, isnull); result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } } lwcoll = (LWCOLLECTION*)node->geom; /* if a collection and we have more geoms */ if (node->idx < lwcoll->ngeoms) { /* push the next geom on the path and the stack */ lwgeom = lwcoll->geoms[node->idx++]; state->path[state->pathlen++] = Int32GetDatum(node->idx); node = &state->stack[state->stacklen++]; node->idx = 0; node->geom = lwgeom; state->pt = 0; state->ring = 0; /* loop back to beginning, which will then check whatever node we just pushed */ continue; } /* no more geometries in the current collection */ if (--state->stacklen == 0) SRF_RETURN_DONE(funcctx); state->pathlen--; state->stack[state->stacklen-1].idx++; } }
LWCOLLECTION* lwgeom_clip_to_ordinate_range(const LWGEOM *lwin, char ordinate, double from, double to, double offset) { LWCOLLECTION *out_col; LWCOLLECTION *out_offset; int i; if ( ! lwin ) lwerror("lwgeom_clip_to_ordinate_range: null input geometry!"); switch ( lwin->type ) { case LINETYPE: out_col = lwline_clip_to_ordinate_range((LWLINE*)lwin, ordinate, from, to); break; case MULTILINETYPE: out_col = lwmline_clip_to_ordinate_range((LWMLINE*)lwin, ordinate, from, to); break; case MULTIPOINTTYPE: out_col = lwmpoint_clip_to_ordinate_range((LWMPOINT*)lwin, ordinate, from, to); break; case POINTTYPE: out_col = lwpoint_clip_to_ordinate_range((LWPOINT*)lwin, ordinate, from, to); break; default: lwerror("This function does not accept %s geometries.", lwtype_name(lwin->type)); return NULL;; } /* Stop if result is NULL */ if ( out_col == NULL ) lwerror("lwgeom_clip_to_ordinate_range clipping routine returned NULL"); /* Return if we aren't going to offset the result */ if ( FP_EQUALS(offset, 0.0) || lwgeom_is_empty(lwcollection_as_lwgeom(out_col)) ) return out_col; /* Construct a collection to hold our outputs. */ /* Things get ugly: GEOS offset drops Z's and M's so we have to drop ours */ out_offset = lwcollection_construct_empty(MULTILINETYPE, lwin->srid, 0, 0); /* Try and offset the linear portions of the return value */ for ( i = 0; i < out_col->ngeoms; i++ ) { int type = out_col->geoms[i]->type; if ( type == POINTTYPE ) { lwnotice("lwgeom_clip_to_ordinate_range cannot offset a clipped point"); continue; } else if ( type == LINETYPE ) { /* lwgeom_offsetcurve(line, offset, quadsegs, joinstyle (round), mitrelimit) */ LWGEOM *lwoff = lwgeom_offsetcurve(lwgeom_as_lwline(out_col->geoms[i]), offset, 8, 1, 5.0); if ( ! lwoff ) { lwerror("lwgeom_offsetcurve returned null"); } lwcollection_add_lwgeom(out_offset, lwoff); } else { lwerror("lwgeom_clip_to_ordinate_range found an unexpected type (%s) in the offset routine",lwtype_name(type)); } } return out_offset; }
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); }
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); }
LWGEOM* wkt_parser_curvepolygon_add_ring(LWGEOM *poly, LWGEOM *ring) { LWDEBUG(4,"entered"); /* Toss error on null input */ if( ! (ring && poly) ) { SET_PARSER_ERROR(PARSER_ERROR_OTHER); LWDEBUG(4,"inputs are null"); return NULL; } /* All the elements must agree on dimensionality */ if( FLAGS_NDIMS(poly->flags) != FLAGS_NDIMS(ring->flags) ) { LWDEBUG(4,"dimensionality does not match"); lwgeom_free(ring); lwgeom_free(poly); SET_PARSER_ERROR(PARSER_ERROR_MIXDIMS); return NULL; } /* Apply check for minimum number of points, if requested. */ if( (global_parser_result.parser_check_flags & LW_PARSER_CHECK_MINPOINTS) && (lwgeom_count_vertices(ring) < 4) ) { LWDEBUG(4,"number of points is incorrect"); lwgeom_free(ring); lwgeom_free(poly); SET_PARSER_ERROR(PARSER_ERROR_MOREPOINTS); return NULL; } /* Apply check for not closed rings, if requested. */ if( (global_parser_result.parser_check_flags & LW_PARSER_CHECK_CLOSURE) ) { int is_closed = 1; LWDEBUG(4,"checking ring closure"); switch ( ring->type ) { case LINETYPE: is_closed = lwline_is_closed(lwgeom_as_lwline(ring)); break; case CIRCSTRINGTYPE: is_closed = lwcircstring_is_closed(lwgeom_as_lwcircstring(ring)); break; case COMPOUNDTYPE: is_closed = lwcompound_is_closed(lwgeom_as_lwcompound(ring)); break; } if ( ! is_closed ) { LWDEBUG(4,"ring is not closed"); lwgeom_free(ring); lwgeom_free(poly); SET_PARSER_ERROR(PARSER_ERROR_UNCLOSED); return NULL; } } if( LW_FAILURE == lwcurvepoly_add_ring(lwgeom_as_lwcurvepoly(poly), ring) ) { LWDEBUG(4,"failed to add ring"); lwgeom_free(ring); lwgeom_free(poly); SET_PARSER_ERROR(PARSER_ERROR_OTHER); return NULL; } return poly; }
static void test_lwline_split_by_point_to(void) { #if POSTGIS_GEOS_VERSION >= 33 LWLINE *line; LWPOINT *point; LWMLINE *coll; int ret; /* Because i don't trust that much prior tests... ;) */ cu_error_msg_reset(); coll = lwmline_construct_empty(SRID_UNKNOWN, 0, 0); CU_ASSERT_EQUAL(coll->ngeoms, 0); line = lwgeom_as_lwline(lwgeom_from_wkt("LINESTRING(0 0,5 5, 10 0)", LW_PARSER_CHECK_NONE)); CU_ASSERT(line != NULL); point = lwgeom_as_lwpoint(lwgeom_from_wkt( "POINT(0 0)", LW_PARSER_CHECK_NONE)); ret = lwline_split_by_point_to(line, point, coll); CU_ASSERT_EQUAL(ret, 1); CU_ASSERT_EQUAL(coll->ngeoms, 0); lwpoint_free(point); point = lwgeom_as_lwpoint(lwgeom_from_wkt( "POINT(10 0)", LW_PARSER_CHECK_NONE)); ret = lwline_split_by_point_to(line, point, coll); CU_ASSERT_EQUAL(ret, 1); CU_ASSERT_EQUAL(coll->ngeoms, 0); lwpoint_free(point); point = lwgeom_as_lwpoint(lwgeom_from_wkt( "POINT(5 0)", LW_PARSER_CHECK_NONE)); ret = lwline_split_by_point_to(line, point, coll); CU_ASSERT_EQUAL(ret, 0); CU_ASSERT_EQUAL(coll->ngeoms, 0); lwpoint_free(point); point = lwgeom_as_lwpoint(lwgeom_from_wkt( "POINT(5 5)", LW_PARSER_CHECK_NONE)); ret = lwline_split_by_point_to(line, point, coll); CU_ASSERT_EQUAL(ret, 2); CU_ASSERT_EQUAL(coll->ngeoms, 2); lwpoint_free(point); point = lwgeom_as_lwpoint(lwgeom_from_wkt( "POINT(2 2)", LW_PARSER_CHECK_NONE)); ret = lwline_split_by_point_to(line, point, coll); CU_ASSERT_EQUAL(ret, 2); CU_ASSERT_EQUAL(coll->ngeoms, 4); lwpoint_free(point); lwcollection_free((LWCOLLECTION*)coll); lwline_free(line); #endif /* POSTGIS_GEOS_VERSION >= 33 */ }
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))); }
/** * @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; }
static void test_ptarrayarc_contains_point() { /* int ptarrayarc_contains_point(const POINTARRAY *pa, const POINT2D *pt) */ LWLINE *lwline; POINTARRAY *pa; POINT2D pt; int rv; /*** Collection of semi-circles surrounding unit square ***/ lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-1 -1, -2 0, -1 1, 0 2, 1 1, 2 0, 1 -1, 0 -2, -1 -1)")); pa = lwline->points; /* Point in middle of square */ pt.x = 0; pt.y = 0; rv = ptarrayarc_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_INSIDE); /* Point in left lobe */ pt.x = -1.1; pt.y = 0.1; rv = ptarrayarc_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_INSIDE); /* Point on boundary of left lobe */ pt.x = -1; pt.y = 0; rv = ptarrayarc_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_INSIDE); /* Point on boundary vertex */ pt.x = -1; pt.y = 1; rv = ptarrayarc_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_BOUNDARY); /* Point outside */ pt.x = -1.5; pt.y = 1.5; rv = ptarrayarc_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_OUTSIDE); /*** Two-edge ring made up of semi-circles (really, a circle) ***/ lwline_free(lwline); lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-1 0, 0 1, 1 0, 0 -1, -1 0)")); pa = lwline->points; /* Point outside */ pt.x = -1.5; pt.y = 1.5; rv = ptarrayarc_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_OUTSIDE); /* Point more outside */ pt.x = 2.5; pt.y = 1.5; rv = ptarrayarc_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_OUTSIDE); /* Point more outside */ pt.x = 2.5; pt.y = 2.5; rv = ptarrayarc_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_OUTSIDE); /* Point inside at middle */ pt.x = 0; pt.y = 0; rv = ptarrayarc_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_INSIDE); /* Point inside offset from middle */ pt.x = 0.01; pt.y = 0.01; rv = ptarrayarc_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_INSIDE); /* Point on edge vertex */ pt.x = 0; pt.y = 1; rv = ptarrayarc_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_BOUNDARY); /*** Two-edge ring, closed ***/ lwline_free(lwline); lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(1 6, 6 1, 9 7, 6 10, 1 6)")); pa = lwline->points; /* Point to left of ring */ pt.x = 20; pt.y = 4; rv = ptarrayarc_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_OUTSIDE); /*** One-edge ring, closed circle ***/ lwline_free(lwline); lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-1 0, 1 0, -1 0)")); pa = lwline->points; /* Point inside */ pt.x = 0; pt.y = 0; rv = ptarrayarc_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_INSIDE); /* Point outside */ pt.x = 0; pt.y = 2; rv = ptarrayarc_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_OUTSIDE); /* Point on boundary */ pt.x = 0; pt.y = 1; rv = ptarrayarc_contains_point(pa, &pt); CU_ASSERT_EQUAL(rv, LW_BOUNDARY); /*** Overshort ring ***/ lwline_free(lwline); lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-1 0, 1 0)")); pa = lwline->points; cu_error_msg_reset(); rv = ptarrayarc_contains_point(pa, &pt); //printf("%s\n", cu_error_msg); CU_ASSERT_STRING_EQUAL("ptarrayarc_contains_point called with even number of points", cu_error_msg); /*** Unclosed ring ***/ lwline_free(lwline); lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-1 0, 1 0, 2 0)")); pa = lwline->points; cu_error_msg_reset(); rv = ptarrayarc_contains_point(pa, &pt); CU_ASSERT_STRING_EQUAL("ptarrayarc_contains_point called on unclosed ring", cu_error_msg); lwline_free(lwline); }
static void test_tree_circ_pip(void) { LWLINE *g; CIRC_NODE *c; POINT2D pt, pt_outside; int rv, on_boundary; pt.x = 0.0; pt.y = 0.0; pt_outside.x = -2.0; pt_outside.y = 0.0; /* Point in square */ g = lwgeom_as_lwline(lwgeom_from_wkt("LINESTRING(-1 -1,1 -1,1 1,-1 1,-1 -1)", LW_PARSER_CHECK_NONE)); c = circ_tree_new(g->points); rv = circ_tree_contains_point(c, &pt, &pt_outside, &on_boundary); CU_ASSERT_EQUAL(rv, 1); /* Point on other side of square */ pt.x = 2.0; pt.y = 0.0; rv = circ_tree_contains_point(c, &pt, &pt_outside, &on_boundary); CU_ASSERT_EQUAL(rv, 0); /* Clean and do new shape */ circ_tree_free(c); lwline_free(g); /* Point in square, stab passing through vertex */ pt.x = 0.0; pt.y = 0.0; g = lwgeom_as_lwline(lwgeom_from_wkt("LINESTRING(-1 -1,0 -1,1 -1,1 0,1 1,0 1,-1 1,-1 0,-1 -1)", LW_PARSER_CHECK_NONE)); c = circ_tree_new(g->points); //circ_tree_print(c, 0); rv = circ_tree_contains_point(c, &pt, &pt_outside, &on_boundary); CU_ASSERT_EQUAL(rv, 1); /* Point on other side of square, stab passing through vertex */ pt.x = 2.0; pt.y = 0.0; rv = circ_tree_contains_point(c, &pt, &pt_outside, &on_boundary); CU_ASSERT_EQUAL(rv, 0); /* Clean and do new shape */ circ_tree_free(c); lwline_free(g); /* Point outside "w" thing, stab passing through vertexes and grazing pointy thing */ pt.x = 2.0; pt.y = 0.0; g = lwgeom_as_lwline(lwgeom_from_wkt("LINESTRING(-1 -1,0 -1,1 -1,1 0,1 1,0 0,-1 1,-1 0,-1 -1)", LW_PARSER_CHECK_NONE)); c = circ_tree_new(g->points); //circ_tree_print(c, 0); rv = circ_tree_contains_point(c, &pt, &pt_outside, &on_boundary); //printf("rv %d\n", rv); CU_ASSERT_EQUAL(rv, 0); /* Point inside "w" thing, stab passing through vertexes and grazing pointy thing */ pt.x = 0.8; pt.y = 0.0; rv = circ_tree_contains_point(c, &pt, &pt_outside, &on_boundary); //printf("rv %d\n", rv); CU_ASSERT_EQUAL(rv, 1); /* Clean and do new shape */ circ_tree_free(c); lwline_free(g); }
static void test_lwgeom_split(void) { LWGEOM *geom, *blade, *ret; char *wkt, *in_wkt; geom = lwgeom_from_wkt( "MULTILINESTRING((-5 -2,0 0),(0 0,10 10))", LW_PARSER_CHECK_NONE); CU_ASSERT(geom != NULL); blade = lwgeom_from_wkt( "POINT(0 0)", LW_PARSER_CHECK_NONE); CU_ASSERT(blade != NULL); ret = lwgeom_split(geom, blade); CU_ASSERT(ret != NULL); wkt = lwgeom_to_ewkt(ret); in_wkt = "GEOMETRYCOLLECTION(LINESTRING(-5 -2,0 0),LINESTRING(0 0,10 10))"; if (strcmp(in_wkt, wkt)) fprintf(stderr, "\nExp: %s\nObt: %s\n", in_wkt, wkt); CU_ASSERT_STRING_EQUAL(wkt, in_wkt); lwfree(wkt); lwgeom_free(ret); lwgeom_free(geom); lwgeom_free(blade); /* See #1311 */ geom = lwgeom_from_wkt( "LINESTRING(0 0,10 0,20 4,0 3)", LW_PARSER_CHECK_NONE); CU_ASSERT(geom != NULL); blade = lwgeom_from_wkt("POINT(10 0)", LW_PARSER_CHECK_NONE); ret = lwgeom_split(geom, blade); CU_ASSERT(ret != NULL); wkt = lwgeom_to_ewkt(ret); in_wkt = "GEOMETRYCOLLECTION(LINESTRING(0 0,10 0),LINESTRING(10 0,20 4,0 3))"; if (strcmp(in_wkt, wkt)) fprintf(stderr, "\nExp: %s\nObt: %s\n", in_wkt, wkt); CU_ASSERT_STRING_EQUAL(wkt, in_wkt); lwfree(wkt); lwgeom_free(ret); lwgeom_free(geom); lwgeom_free(blade); /* See #2528 (1) -- memory leak test, needs valgrind to check */ geom = lwgeom_from_wkt("SRID=1;LINESTRING(0 1,10 1)", LW_PARSER_CHECK_NONE); CU_ASSERT(geom != NULL); blade = lwgeom_from_wkt("LINESTRING(7 0,7 3)", LW_PARSER_CHECK_NONE); ret = lwgeom_split(geom, blade); CU_ASSERT(ret != NULL); wkt = lwgeom_to_ewkt(ret); in_wkt = "SRID=1;GEOMETRYCOLLECTION(LINESTRING(0 1,7 1),LINESTRING(7 1,10 1))"; if (strcmp(in_wkt, wkt)) fprintf(stderr, "\nExp: %s\nObt: %s\n", in_wkt, wkt); CU_ASSERT_STRING_EQUAL(wkt, in_wkt); lwfree(wkt); lwgeom_free(ret); lwgeom_free(geom); lwgeom_free(blade); /* See #2528 (2) -- memory leak test, needs valgrind to check */ geom = lwgeom_from_wkt("SRID=1;POLYGON((0 1, 10 1, 10 10, 0 10, 0 1))", LW_PARSER_CHECK_NONE); CU_ASSERT(geom != NULL); blade = lwgeom_from_wkt("LINESTRING(7 0,7 20)", LW_PARSER_CHECK_NONE); ret = lwgeom_split(geom, blade); CU_ASSERT(ret != NULL); wkt = lwgeom_to_ewkt(ret); in_wkt = "SRID=1;GEOMETRYCOLLECTION(POLYGON((7 1,0 1,0 10,7 10,7 1)),POLYGON((7 10,10 10,10 1,7 1,7 10)))"; if (strcmp(in_wkt, wkt)) fprintf(stderr, "\nExp: %s\nObt: %s\n", in_wkt, wkt); CU_ASSERT_STRING_EQUAL(wkt, in_wkt); lwfree(wkt); lwgeom_free(ret); lwgeom_free(geom); lwgeom_free(blade); /* Split line by multiline */ geom = lwgeom_from_wkt("LINESTRING(0 0, 10 0)", LW_PARSER_CHECK_NONE); CU_ASSERT_FATAL(geom != NULL); blade = lwgeom_from_wkt("MULTILINESTRING((1 1,1 -1),(2 1,2 -1,3 -1,3 1))", LW_PARSER_CHECK_NONE); ret = lwgeom_split(geom, blade); if ( ! ret ) printf("%s", cu_error_msg); CU_ASSERT_FATAL(ret != NULL); wkt = lwgeom_to_ewkt(ret); CU_ASSERT_FATAL(wkt != NULL); in_wkt = "GEOMETRYCOLLECTION(LINESTRING(0 0,1 0),LINESTRING(1 0,2 0),LINESTRING(2 0,3 0),LINESTRING(3 0,10 0))"; if (strcmp(in_wkt, wkt)) fprintf(stderr, "\nExp: %s\nObt: %s\n", in_wkt, wkt); CU_ASSERT_STRING_EQUAL(wkt, in_wkt); lwfree(wkt); lwgeom_free(ret); lwgeom_free(geom); lwgeom_free(blade); /* Split line by polygon (boundary) */ geom = lwgeom_from_wkt("LINESTRING(0 0, 10 0)", LW_PARSER_CHECK_NONE); CU_ASSERT_FATAL(geom != NULL); blade = lwgeom_from_wkt( "POLYGON((1 -2,1 1,2 1,2 -1,3 -1,3 1,11 1,11 -2,1 -2))", LW_PARSER_CHECK_NONE); ret = lwgeom_split(geom, blade); if ( ! ret ) printf("%s", cu_error_msg); CU_ASSERT_FATAL(ret != NULL); wkt = lwgeom_to_ewkt(ret); CU_ASSERT_FATAL(wkt != NULL); in_wkt = "GEOMETRYCOLLECTION(LINESTRING(0 0,1 0),LINESTRING(1 0,2 0),LINESTRING(2 0,3 0),LINESTRING(3 0,10 0))"; if (strcmp(in_wkt, wkt)) fprintf(stderr, "\nExp: %s\nObt: %s\n", in_wkt, wkt); CU_ASSERT_STRING_EQUAL(wkt, in_wkt); lwfree(wkt); lwgeom_free(ret); lwgeom_free(geom); lwgeom_free(blade); /* Split line by EMPTY polygon (boundary) */ geom = lwgeom_from_wkt("LINESTRING(0 0, 10 0)", LW_PARSER_CHECK_NONE); CU_ASSERT_FATAL(geom != NULL); blade = lwgeom_from_wkt("POLYGON EMPTY", LW_PARSER_CHECK_NONE); ret = lwgeom_split(geom, blade); if ( ! ret ) printf("%s", cu_error_msg); CU_ASSERT_FATAL(ret != NULL); wkt = lwgeom_to_ewkt(ret); CU_ASSERT_FATAL(wkt != NULL); in_wkt = "GEOMETRYCOLLECTION(LINESTRING(0 0,10 0))"; if (strcmp(in_wkt, wkt)) fprintf(stderr, "\nExp: %s\nObt: %s\n", in_wkt, wkt); CU_ASSERT_STRING_EQUAL(wkt, in_wkt); lwfree(wkt); lwgeom_free(ret); lwgeom_free(geom); lwgeom_free(blade); /* Split line by multipolygon (boundary) */ geom = lwgeom_from_wkt("LINESTRING(0 0, 10 0)", LW_PARSER_CHECK_NONE); CU_ASSERT_FATAL(geom != NULL); blade = lwgeom_from_wkt( "MULTIPOLYGON(((1 -1,1 1,2 1,2 -1,1 -1)),((3 -1,3 1,11 1,11 -1,3 -1)))", LW_PARSER_CHECK_NONE); ret = lwgeom_split(geom, blade); if ( ! ret ) printf("%s", cu_error_msg); CU_ASSERT_FATAL(ret != NULL); wkt = lwgeom_to_ewkt(ret); CU_ASSERT_FATAL(wkt != NULL); in_wkt = "GEOMETRYCOLLECTION(LINESTRING(0 0,1 0),LINESTRING(1 0,2 0),LINESTRING(2 0,3 0),LINESTRING(3 0,10 0))"; if (strcmp(in_wkt, wkt)) fprintf(stderr, "\nExp: %s\nObt: %s\n", in_wkt, wkt); CU_ASSERT_STRING_EQUAL(wkt, in_wkt); lwfree(wkt); lwgeom_free(ret); lwgeom_free(geom); lwgeom_free(blade); /* Split line by multipoint */ geom = lwgeom_from_wkt("LINESTRING(0 0, 10 0)", LW_PARSER_CHECK_NONE); CU_ASSERT_FATAL(geom != NULL); blade = lwgeom_from_wkt("MULTIPOINT(2 0,8 0,4 0)", LW_PARSER_CHECK_NONE); ret = lwgeom_split(geom, blade); if ( ! ret ) printf("%s", cu_error_msg); CU_ASSERT_FATAL(ret != NULL); wkt = lwgeom_to_ewkt(ret); CU_ASSERT_FATAL(wkt != NULL); in_wkt = "GEOMETRYCOLLECTION(LINESTRING(8 0,10 0),LINESTRING(0 0,2 0),LINESTRING(4 0,8 0),LINESTRING(2 0,4 0))"; if (strcmp(in_wkt, wkt)) fprintf(stderr, "\nExp: %s\nObt: %s\n", in_wkt, wkt); CU_ASSERT_STRING_EQUAL(wkt, in_wkt); lwfree(wkt); lwgeom_free(ret); lwgeom_free(geom); lwgeom_free(blade); /* See #3401 -- robustness issue */ geom = lwgeom_from_wkt("LINESTRING(-180 0,0 0)", LW_PARSER_CHECK_NONE); CU_ASSERT(geom != NULL); blade = lwgeom_from_wkt("POINT(-20 0)", LW_PARSER_CHECK_NONE); ret = lwgeom_split(geom, blade); CU_ASSERT(ret != NULL); { LWCOLLECTION *split = lwgeom_as_lwcollection(ret); LWLINE *l1, *l2; POINT2D pt; CU_ASSERT(split != NULL); l1 = lwgeom_as_lwline(split->geoms[0]); CU_ASSERT(l1 != NULL); getPoint2d_p(l1->points, 1, &pt); ASSERT_DOUBLE_EQUAL(pt.x, -20); ASSERT_DOUBLE_EQUAL(pt.y, 0); l2 = lwgeom_as_lwline(split->geoms[1]); CU_ASSERT(l2 != NULL); getPoint2d_p(l2->points, 0, &pt); ASSERT_DOUBLE_EQUAL(pt.x, -20); ASSERT_DOUBLE_EQUAL(pt.y, 0); } lwgeom_free(ret); lwgeom_free(geom); lwgeom_free(blade); }