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; }
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; }
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; }
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++; } }