/** * POLYGON */ static LWPOLY* lwpoly_from_twkb_state(twkb_parse_state *s) { uint32_t nrings; int i; LWPOLY *poly; LWDEBUG(2,"Entering lwpoly_from_twkb_state"); if ( s->is_empty ) return lwpoly_construct_empty(SRID_UNKNOWN, s->has_z, s->has_m); /* Read number of rings */ nrings = twkb_parse_state_uvarint(s); /* Start w/ empty polygon */ poly = lwpoly_construct_empty(SRID_UNKNOWN, s->has_z, s->has_m); LWDEBUGF(4,"Polygon has %d rings", nrings); /* Empty polygon? */ if( nrings == 0 ) return poly; for( i = 0; i < nrings; i++ ) { /* Ret number of points */ uint32_t npoints = twkb_parse_state_uvarint(s); POINTARRAY *pa = ptarray_from_twkb_state(s, npoints); /* Skip empty rings */ if( pa == NULL ) continue; /* Force first and last points to be the same. */ if( ! ptarray_is_closed_2d(pa) ) { POINT4D pt; getPoint4d_p(pa, 0, &pt); ptarray_append_point(pa, &pt, LW_FALSE); } /* Check for at least four points. */ if( s->check & LW_PARSER_CHECK_MINPOINTS && pa->npoints < 4 ) { LWDEBUGF(2, "%s must have at least four points in each ring", lwtype_name(s->lwtype)); lwerror("%s must have at least four points in each ring", lwtype_name(s->lwtype)); return NULL; } /* Add ring to polygon */ if ( lwpoly_add_ring(poly, pa) == LW_FAILURE ) { LWDEBUG(2, "Unable to add ring to polygon"); lwerror("Unable to add ring to polygon"); } } return poly; }
LWPOLY* lwpoly_simplify(const LWPOLY *ipoly, double dist, int preserve_collapsed) { int i; LWPOLY *opoly = lwpoly_construct_empty(ipoly->srid, FLAGS_GET_Z(ipoly->flags), FLAGS_GET_M(ipoly->flags)); LWDEBUGF(2, "%s: simplifying polygon with %d rings", __func__, ipoly->nrings); if ( lwpoly_is_empty(ipoly) ) { lwpoly_free(opoly); return NULL; } for ( i = 0; i < ipoly->nrings; i++ ) { POINTARRAY *opts; int minvertices = 0; /* We'll still let holes collapse, but if we're preserving */ /* and this is a shell, we ensure it is kept */ if ( preserve_collapsed && i == 0 ) minvertices = 4; opts = ptarray_simplify(ipoly->rings[i], dist, minvertices); LWDEBUGF(3, "ring%d simplified from %d to %d points", i, ipoly->rings[i]->npoints, opts->npoints); /* Less points than are needed to form a closed ring, we can't use this */ if ( opts->npoints < 4 ) { LWDEBUGF(3, "ring%d skipped (% pts)", i, opts->npoints); ptarray_free(opts); if ( i ) continue; else break; /* Don't scan holes if shell is collapsed */ } /* Add ring to simplified polygon */ if( lwpoly_add_ring(opoly, opts) == LW_FAILURE ) { lwpoly_free(opoly); return NULL; } } LWDEBUGF(3, "simplified polygon with %d rings", ipoly->nrings); opoly->type = ipoly->type; if( lwpoly_is_empty(opoly) ) { lwpoly_free(opoly); return NULL; } return opoly; }
LWPOLY* lwpoly_grid(const LWPOLY *poly, const gridspec *grid) { LWPOLY *opoly; int ri; #if 0 /* * TODO: control this assertion * it is assumed that, since the grid size will be a pixel, * a visible ring should show at least a white pixel inside, * thus, for a square, that would be grid_xsize*grid_ysize */ double minvisiblearea = grid->xsize * grid->ysize; #endif LWDEBUGF(3, "lwpoly_grid: applying grid to polygon with %d rings", poly->nrings); opoly = lwpoly_construct_empty(poly->srid, lwgeom_has_z((LWGEOM*)poly), lwgeom_has_m((LWGEOM*)poly)); for (ri=0; ri<poly->nrings; ri++) { POINTARRAY *ring = poly->rings[ri]; POINTARRAY *newring; newring = ptarray_grid(ring, grid); /* Skip ring if not composed by at least 4 pts (3 segments) */ if ( newring->npoints < 4 ) { ptarray_free(newring); LWDEBUGF(3, "grid_polygon3d: ring%d skipped ( <4 pts )", ri); if ( ri ) continue; else break; /* this is the external ring, no need to work on holes */ } if ( ! lwpoly_add_ring(opoly, newring) ) { lwerror("lwpoly_grid, memory error"); return NULL; } } LWDEBUGF(3, "lwpoly_grid: simplified polygon with %d rings", opoly->nrings); if ( ! opoly->nrings ) { lwpoly_free(opoly); return NULL; } return opoly; }
LWGEOM* wkt_parser_polygon_add_ring(LWGEOM *poly, POINTARRAY *pa, char dimcheck) { LWDEBUG(4,"entered"); /* Bad inputs are a problem */ if( ! (pa && poly) ) { SET_PARSER_ERROR(PARSER_ERROR_OTHER); return NULL; } /* Rings must agree on dimensionality */ if( FLAGS_NDIMS(poly->flags) != FLAGS_NDIMS(pa->flags) ) { ptarray_free(pa); 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) && (pa->npoints < 4) ) { ptarray_free(pa); 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) && ! (dimcheck == 'Z' ? ptarray_isclosedz(pa) : ptarray_isclosed2d(pa)) ) { ptarray_free(pa); lwgeom_free(poly); SET_PARSER_ERROR(PARSER_ERROR_UNCLOSED); return NULL; } /* If something goes wrong adding a ring, error out. */ if ( LW_FAILURE == lwpoly_add_ring(lwgeom_as_lwpoly(poly), pa) ) { ptarray_free(pa); lwgeom_free(poly); SET_PARSER_ERROR(PARSER_ERROR_OTHER); return NULL; } return poly; }
LWPOLY* lwpoly_construct_rectangle(char hasz, char hasm, POINT4D *p1, POINT4D *p2, POINT4D *p3, POINT4D *p4) { POINTARRAY *pa = ptarray_construct_empty(hasz, hasm, 5); LWPOLY *lwpoly = lwpoly_construct_empty(SRID_UNKNOWN, hasz, hasm); ptarray_append_point(pa, p1, LW_TRUE); ptarray_append_point(pa, p2, LW_TRUE); ptarray_append_point(pa, p3, LW_TRUE); ptarray_append_point(pa, p4, LW_TRUE); ptarray_append_point(pa, p1, LW_TRUE); lwpoly_add_ring(lwpoly, pa); return lwpoly; }
/** * POLYGON * Read a WKB polygon, starting just after the endian byte, * type number and optional srid number. Advance the parse state * forward appropriately. * First read the number of rings, then read each ring * (which are structured as point arrays) */ static LWPOLY* lwpoly_from_wkb_state(wkb_parse_state *s) { uint32_t nrings = integer_from_wkb_state(s); int i = 0; LWPOLY *poly = lwpoly_construct_empty(s->srid, s->has_z, s->has_m); LWDEBUGF(4,"Polygon has %d rings", nrings); /* Empty polygon? */ if( nrings == 0 ) return poly; for( i = 0; i < nrings; i++ ) { POINTARRAY *pa = ptarray_from_wkb_state(s); if( pa == NULL ) continue; /* Check for at least four points. */ if( s->check & LW_PARSER_CHECK_MINPOINTS && pa->npoints < 4 ) { LWDEBUGF(2, "%s must have at least four points in each ring", lwtype_name(s->lwtype)); lwerror("%s must have at least four points in each ring", lwtype_name(s->lwtype)); return NULL; } /* Check that first and last points are the same. */ if( s->check & LW_PARSER_CHECK_CLOSURE && ! ptarray_is_closed_2d(pa) ) { LWDEBUGF(2, "%s must have closed rings", lwtype_name(s->lwtype)); lwerror("%s must have closed rings", lwtype_name(s->lwtype)); return NULL; } /* Add ring to polygon */ if ( lwpoly_add_ring(poly, pa) == LW_FAILURE ) { LWDEBUG(2, "Unable to add ring to polygon"); lwerror("Unable to add ring to polygon"); } } return poly; }
LWPOLY* lwpoly_construct_circle(int srid, double x, double y, double radius, uint32_t segments_per_quarter, char exterior) { const int segments = 4*segments_per_quarter; double theta; LWPOLY *lwpoly; POINTARRAY *pa; POINT4D pt; uint32_t i; if (segments_per_quarter == 0) { lwerror("Need at least one segment per quarter-circle."); return NULL; } if (radius < 0) { lwerror("Radius must be positive."); return NULL; } theta = 2*M_PI / segments; lwpoly = lwpoly_construct_empty(srid, LW_FALSE, LW_FALSE); pa = ptarray_construct_empty(LW_FALSE, LW_FALSE, segments + 1); if (exterior) radius *= sqrt(1 + pow(tan(theta/2), 2)); for (i = 0; i <= segments; i++) { pt.x = x + radius*sin(i * theta); pt.y = y + radius*cos(i * theta); ptarray_append_point(pa, &pt, LW_TRUE); } lwpoly_add_ring(lwpoly, pa); return lwpoly; }
LWPOLY* lwpoly_simplify(const LWPOLY *ipoly, double dist) { int i; LWPOLY *opoly = lwpoly_construct_empty(ipoly->srid, FLAGS_GET_Z(ipoly->flags), FLAGS_GET_M(ipoly->flags)); LWDEBUGF(2, "simplify_polygon3d: simplifying polygon with %d rings", ipoly->nrings); if( lwpoly_is_empty(ipoly) ) return opoly; /* should we return NULL instead ? */ for (i = 0; i < ipoly->nrings; i++) { static const int minvertices = 0; /* TODO: allow setting this */ POINTARRAY *opts = ptarray_simplify(ipoly->rings[i], dist, minvertices); LWDEBUGF(3, "ring%d simplified from %d to %d points", i, ipoly->rings[i]->npoints, opts->npoints); /* Less points than are needed to form a closed ring, we can't use this */ if ( opts->npoints < 4 ) { LWDEBUGF(3, "ring%d skipped (% pts)", i, opts->npoints); ptarray_free(opts); if ( i ) continue; else break; /* Don't scan holes if shell is collapsed */ } /* Add ring to simplified polygon */ if( lwpoly_add_ring(opoly, opts) == LW_FAILURE ) return NULL; } LWDEBUGF(3, "simplified polygon with %d rings", ipoly->nrings); opoly->type = ipoly->type; if( lwpoly_is_empty(opoly) ) return NULL; return opoly; }
static LWPOLY* lwpoly_set_effective_area(const LWPOLY *ipoly,int set_area, double trshld) { LWDEBUG(2, "Entered lwpoly_set_effective_area"); int i; int set_m; int avoid_collapse=4; if(set_area) set_m=1; else set_m=FLAGS_GET_M(ipoly->flags); LWPOLY *opoly = lwpoly_construct_empty(ipoly->srid, FLAGS_GET_Z(ipoly->flags), set_m); if( lwpoly_is_empty(ipoly) ) return opoly; /* should we return NULL instead ? */ for (i = 0; i < ipoly->nrings; i++) { POINTARRAY *pa = ptarray_set_effective_area(ipoly->rings[i],avoid_collapse,set_area,trshld); /* Add ring to simplified polygon */ if(pa->npoints>=4) { if( lwpoly_add_ring(opoly,pa ) == LW_FAILURE ) return NULL; } /*Inner rings we allow to ocollapse and then we remove them*/ avoid_collapse=0; } opoly->type = ipoly->type; if( lwpoly_is_empty(opoly) ) return NULL; return opoly; }
/** * @brief Generate an allocated geometry string for shapefile object obj using the state parameters * * This function basically deals with the polygon case. It sorts the polys in order of outer, * inner,inner, so that inners always come after outers they are within. * */ int GeneratePolygonGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry) { Ring **Outer; int polygon_total, ring_total; int pi, vi; /* part index and vertex index */ LWGEOM **lwpolygons; LWGEOM *lwgeom; POINT4D point4d; int dims = 0; char *mem; size_t mem_length; FLAGS_SET_Z(dims, state->has_z); FLAGS_SET_M(dims, state->has_m); polygon_total = FindPolygons(obj, &Outer); if (state->config->simple_geometries == 1 && polygon_total != 1) /* We write Non-MULTI geometries, but have several parts: */ { snprintf(state->message, SHPLOADERMSGLEN, _("We have a Multipolygon with %d parts, can't use -S switch!"), polygon_total); return SHPLOADERERR; } /* Allocate memory for our array of LWPOLYs */ lwpolygons = malloc(sizeof(LWPOLY *) * polygon_total); /* Cycle through each individual polygon */ for (pi = 0; pi < polygon_total; pi++) { LWPOLY *lwpoly = lwpoly_construct_empty(state->from_srid, state->has_z, state->has_m); Ring *polyring; int ring_index = 0; /* Firstly count through the total number of rings in this polygon */ ring_total = 0; polyring = Outer[pi]; while (polyring) { ring_total++; polyring = polyring->next; } /* Cycle through each ring within the polygon, starting with the outer */ polyring = Outer[pi]; while (polyring) { /* Create a POINTARRAY containing the points making up the ring */ POINTARRAY *pa = ptarray_construct_empty(state->has_z, state->has_m, polyring->n); for (vi = 0; vi < polyring->n; vi++) { /* Build up a point array of all the points in this ring */ point4d.x = polyring->list[vi].x; point4d.y = polyring->list[vi].y; if (state->has_z) point4d.z = polyring->list[vi].z; if (state->has_m) point4d.m = polyring->list[vi].m; ptarray_append_point(pa, &point4d, LW_TRUE); } /* Copy the POINTARRAY pointer so we can use the LWPOLY constructor */ lwpoly_add_ring(lwpoly, pa); polyring = polyring->next; ring_index++; } /* Generate the LWGEOM */ lwpolygons[pi] = lwpoly_as_lwgeom(lwpoly); } /* If using MULTIPOLYGONS then generate the serialized collection, otherwise just a single POLYGON */ if (state->config->simple_geometries == 0) { lwgeom = lwcollection_as_lwgeom(lwcollection_construct(MULTIPOLYGONTYPE, state->from_srid, NULL, polygon_total, lwpolygons)); } else { lwgeom = lwpolygons[0]; lwfree(lwpolygons); } 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); /* Free the linked list of rings */ ReleasePolygons(Outer, polygon_total); /* Return the string - everything ok */ *geometry = mem; return SHPLOADEROK; }
static LWGEOM* parse_geojson_multipolygon(json_object *geojson, int *hasz, int root_srid) { LWGEOM *geom = NULL; int i, j, k; json_object* poObjPolys = NULL; if (!root_srid) { geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOLYGONTYPE, root_srid, 1, 0); } else { geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOLYGONTYPE, -1, 1, 0); } poObjPolys = findMemberByName( geojson, "coordinates" ); if ( ! poObjPolys ) { geojson_lwerror("Unable to find 'coordinates' in GeoJSON string", 4); return NULL; } if( json_type_array == json_object_get_type( poObjPolys ) ) { const int nPolys = json_object_array_length( poObjPolys ); for(i = 0; i < nPolys; ++i) { json_object* poObjPoly = json_object_array_get_idx( poObjPolys, i ); if( json_type_array == json_object_get_type( poObjPoly ) ) { LWPOLY *lwpoly = lwpoly_construct_empty(geom->srid, lwgeom_has_z(geom), lwgeom_has_m(geom)); int nRings = json_object_array_length( poObjPoly ); for(j = 0; j < nRings; ++j) { json_object* points = json_object_array_get_idx( poObjPoly, j ); if( json_type_array == json_object_get_type( points ) ) { POINTARRAY *pa = ptarray_construct_empty(1, 0, 1); int nPoints = json_object_array_length( points ); for ( k=0; k < nPoints; k++ ) { json_object* coords = json_object_array_get_idx( points, k ); parse_geojson_coord(coords, hasz, pa); } lwpoly_add_ring(lwpoly, pa); } } geom = (LWGEOM*)lwmpoly_add_lwpoly((LWMPOLY*)geom, lwpoly); } } } return geom; }