/** * @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; }
/** * @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 */ int u; LWCOLLECTION *lwcollection = NULL; LWGEOM **lwpolygons; uchar *serialized_lwgeom; LWGEOM_UNPARSER_RESULT lwg_unparser_result; LWPOLY *lwpoly; DYNPTARRAY *dpas; POINTARRAY ***pas; POINT4D point4d; int dims = 0, hasz = 0, hasm = 0; int result; 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); 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); /* Allocate memory for our POINTARRAY pointers for each polygon */ pas = malloc(sizeof(POINTARRAY **) * polygon_total); /* Cycle through each individual polygon */ for (pi = 0; pi < polygon_total; pi++) { 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; } /* Reserve memory for the POINTARRAYs representing each ring */ pas[pi] = malloc(sizeof(POINTARRAY *) * ring_total); /* Cycle through each ring within the polygon, starting with the outer */ polyring = Outer[pi]; while (polyring) { /* Create a DYNPTARRAY containing the points making up the ring */ dpas = dynptarray_create(polyring->n, dims); 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->wkbtype & WKBZOFFSET) point4d.z = polyring->list[vi].z; if (state->wkbtype & WKBMOFFSET) point4d.m = polyring->list[vi].m; dynptarray_addPoint4d(dpas, &point4d, 0); } /* Copy the POINTARRAY pointer from the DYNPTARRAY structure so we can use the LWPOLY constructor */ pas[pi][ring_index] = dpas->pa; /* Free the DYNPTARRAY structure (we don't need this part anymore as we have the reference to the internal POINTARRAY) */ lwfree(dpas); polyring = polyring->next; ring_index++; } /* Generate the LWGEOM */ lwpoly = lwpoly_construct(state->config->sr_id, NULL, ring_total, pas[pi]); 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) { lwcollection = lwcollection_construct(MULTIPOLYGONTYPE, state->config->sr_id, NULL, polygon_total, lwpolygons); /* When outputting wkt rather than wkb, we need to remove the SRID from the inner geometries */ if (state->config->hwgeom) { for (u = 0; u < pi; u++) lwpolygons[u]->SRID = -1; } serialized_lwgeom = lwgeom_serialize(lwcollection_as_lwgeom(lwcollection)); } else { serialized_lwgeom = lwgeom_serialize(lwpolygons[0]); } /* Note: lwpoly_free() currently doesn't free its serialized pointlist, so do it manually */ for (pi = 0; pi < polygon_total; pi++) { Ring *polyring = Outer[pi]; int ring_index = 0; while (polyring) { if (pas[pi][ring_index]->serialized_pointlist) lwfree(pas[pi][ring_index]->serialized_pointlist); polyring = polyring->next; ring_index++; } } ReleasePolygons(Outer, polygon_total); if (!state->config->hwgeom) result = serialized_lwgeom_to_hexwkb(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_NONE, -1); else result = serialized_lwgeom_to_ewkt(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_NONE); if (result) { snprintf(state->message, SHPLOADERMSGLEN, "%s", lwg_unparser_result.message); return SHPLOADERERR; } /* Allocate a string containing the resulting geometry */ mem = malloc(strlen(lwg_unparser_result.wkoutput) + 1); strcpy(mem, lwg_unparser_result.wkoutput); /* Free all of the allocated items */ lwfree(lwg_unparser_result.wkoutput); lwfree(serialized_lwgeom); /* Cycle through each polygon, freeing everything we need... */ for (u = 0; u < polygon_total; u++) lwpoly_free(lwgeom_as_lwpoly(lwpolygons[u])); /* Free the pointer arrays */ lwfree(pas); lwfree(lwpolygons); if (lwcollection) lwfree(lwcollection); /* Return the string - everything ok */ *geometry = mem; return SHPLOADEROK; }