static LWGEOM* lwcollection_homogenize(const LWCOLLECTION *col) { int i; int ntypes = 0; int type = 0; LWGEOM *outgeom = NULL; HomogenizeBuffer buffer; /* Sort all the parts into a buffer */ init_homogenizebuffer(&buffer); lwcollection_build_buffer(col, &buffer); /* Check for homogeneity */ for ( i = 0; i < NUMTYPES; i++ ) { if ( buffer.cnt[i] > 0 ) { ntypes++; type = i; } } /* No types? Huh. Return empty. */ if ( ntypes == 0 ) { LWCOLLECTION *outcol; outcol = lwcollection_construct_empty(COLLECTIONTYPE, col->srid, FLAGS_GET_Z(col->flags), FLAGS_GET_M(col->flags)); outgeom = lwcollection_as_lwgeom(outcol); } /* One type, return homogeneous collection */ else if ( ntypes == 1 ) { LWCOLLECTION *outcol; outcol = buffer.buf[type]; if ( outcol->ngeoms == 1 ) { outgeom = outcol->geoms[0]; outcol->ngeoms=0; lwcollection_free(outcol); } else { outgeom = lwcollection_as_lwgeom(outcol); } outgeom->srid = col->srid; } /* Bah, more than out type, return anonymous collection */ else if ( ntypes > 1 ) { int j; LWCOLLECTION *outcol; outcol = lwcollection_construct_empty(COLLECTIONTYPE, col->srid, FLAGS_GET_Z(col->flags), FLAGS_GET_M(col->flags)); for ( j = 0; j < NUMTYPES; j++ ) { if ( buffer.buf[j] ) { LWCOLLECTION *bcol = buffer.buf[j]; if ( bcol->ngeoms == 1 ) { lwcollection_add_lwgeom(outcol, bcol->geoms[0]); bcol->ngeoms=0; lwcollection_free(bcol); } else { lwcollection_add_lwgeom(outcol, lwcollection_as_lwgeom(bcol)); } } } outgeom = lwcollection_as_lwgeom(outcol); } return outgeom; }
/* ** Given a generic geometry, return the "simplest" form. ** ** eg: ** LINESTRING() => LINESTRING() ** ** MULTILINESTRING(with a single line) => LINESTRING() ** ** GEOMETRYCOLLECTION(MULTILINESTRING()) => MULTILINESTRING() ** ** GEOMETRYCOLLECTION(MULTILINESTRING(), MULTILINESTRING(), POINT()) ** => GEOMETRYCOLLECTION(MULTILINESTRING(), POINT()) */ LWGEOM * lwgeom_homogenize(const LWGEOM *geom) { LWGEOM *hgeom; /* EMPTY Geometry */ if (lwgeom_is_empty(geom)) { if( lwgeom_is_collection(geom) ) { return lwcollection_as_lwgeom(lwcollection_construct_empty(geom->type, geom->srid, lwgeom_has_z(geom), lwgeom_has_m(geom))); } return lwgeom_clone(geom); } switch (geom->type) { /* Return simple geometries untouched */ case POINTTYPE: case LINETYPE: case CIRCSTRINGTYPE: case COMPOUNDTYPE: case TRIANGLETYPE: case CURVEPOLYTYPE: case POLYGONTYPE: return lwgeom_clone(geom); /* Process homogeneous geometries lightly */ case MULTIPOINTTYPE: case MULTILINETYPE: case MULTIPOLYGONTYPE: case MULTICURVETYPE: case MULTISURFACETYPE: case POLYHEDRALSURFACETYPE: case TINTYPE: { LWCOLLECTION *col = (LWCOLLECTION*)geom; /* Strip single-entry multi-geometries down to singletons */ if ( col->ngeoms == 1 ) { hgeom = lwgeom_clone((LWGEOM*)(col->geoms[0])); hgeom->srid = geom->srid; if (geom->bbox) hgeom->bbox = gbox_copy(geom->bbox); return hgeom; } /* Return proper multigeometry untouched */ return lwgeom_clone(geom); } /* Work on anonymous collections separately */ case COLLECTIONTYPE: return lwcollection_homogenize((LWCOLLECTION *) geom); } /* Unknown type */ lwerror("lwgeom_homogenize: Geometry Type not supported (%i)", lwtype_name(geom->type)); return NULL; /* Never get here! */ }
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; }
LWGEOM* pta_desegmentize(POINTARRAY *points, int type, int srid) { int i = 0, j, k; POINT4D a1, a2, a3, b; char *edges_in_arcs; int found_arc = LW_FALSE; int current_arc = 1; int num_edges; int edge_type = -1; int start, end; LWCOLLECTION *outcol; /* Die on null input */ if ( ! points ) lwerror("pta_desegmentize called with null pointarray"); /* Null on empty input? */ if ( points->npoints == 0 ) return NULL; /* We can't desegmentize anything shorter than four points */ if ( points->npoints < 4 ) { /* Return a linestring here*/ lwerror("pta_desegmentize needs implementation for npoints < 4"); } /* Allocate our result array of vertices that are part of arcs */ num_edges = points->npoints - 1; edges_in_arcs = lwalloc(num_edges); memset(edges_in_arcs, 0, num_edges); /* We make a candidate arc of the first two edges, */ /* And then see if the next edge follows it */ while( i < num_edges-2 ) { found_arc = LW_FALSE; /* Make candidate arc */ getPoint4d_p(points, i , &a1); getPoint4d_p(points, i+1, &a2); getPoint4d_p(points, i+2, &a3); for( j = i+3; j < num_edges+1; j++ ) { LWDEBUGF(4, "i=%d, j=%d", i, j); getPoint4d_p(points, j, &b); /* Does this point fall on our candidate arc? */ if ( pt_continues_arc(&a1, &a2, &a3, &b) ) { /* Yes. Mark this edge and the two preceding it as arc components */ LWDEBUGF(4, "pt_continues_arc #%d", current_arc); found_arc = LW_TRUE; for ( k = j-1; k > j-4; k-- ) edges_in_arcs[k] = current_arc; } else { /* No. So we're done with this candidate arc */ LWDEBUG(4, "pt_continues_arc = false"); current_arc++; break; } } /* Jump past all the edges that were added to the arc */ if ( found_arc ) { i = j-1; } else { /* Mark this edge as a linear edge */ edges_in_arcs[i] = 0; i = i+1; } } #if POSTGIS_DEBUG_LEVEL > 3 { char *edgestr = lwalloc(num_edges+1); for ( i = 0; i < num_edges; i++ ) { if ( edges_in_arcs[i] ) edgestr[i] = 48 + edges_in_arcs[i]; else edgestr[i] = '.'; } edgestr[num_edges] = 0; LWDEBUGF(3, "edge pattern %s", edgestr); lwfree(edgestr); } #endif start = 0; edge_type = edges_in_arcs[0]; outcol = lwcollection_construct_empty(COMPOUNDTYPE, srid, ptarray_has_z(points), ptarray_has_m(points)); for( i = 1; i < num_edges; i++ ) { if( edge_type != edges_in_arcs[i] ) { end = i - 1; lwcollection_add_lwgeom(outcol, geom_from_pa(points, srid, edge_type, start, end)); start = i; edge_type = edges_in_arcs[i]; } } /* Roll out last item */ end = num_edges - 1; lwcollection_add_lwgeom(outcol, geom_from_pa(points, srid, edge_type, start, end)); /* Strip down to singleton if only one entry */ if ( outcol->ngeoms == 1 ) { LWGEOM *outgeom = outcol->geoms[0]; lwfree(outcol); return outgeom; } return lwcollection_as_lwgeom(outcol); }
/** * @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; }
/** * @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 * if "force_multi" is true, single points will instead be created as multipoints with a single vertice. */ int GeneratePointGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry, int force_multi) { LWGEOM **lwmultipoints; LWGEOM *lwgeom = NULL; POINT4D point4d; int dims = 0; int u; char *mem; size_t mem_length; FLAGS_SET_Z(dims, state->has_z); FLAGS_SET_M(dims, state->has_m); /* Allocate memory for our array of LWPOINTs and our dynptarrays */ lwmultipoints = malloc(sizeof(LWPOINT *) * obj->nVertices); /* We need an array of pointers to each of our sub-geometries */ for (u = 0; u < obj->nVertices; u++) { /* Create a ptarray containing a single point */ POINTARRAY *pa = ptarray_construct_empty(state->has_z, state->has_m, 1); /* Generate the point */ point4d.x = obj->padfX[u]; point4d.y = obj->padfY[u]; if (state->has_z) point4d.z = obj->padfZ[u]; if (state->has_m) point4d.m = obj->padfM[u]; /* Add in the point! */ ptarray_append_point(pa, &point4d, LW_TRUE); /* Generate the LWPOINT */ lwmultipoints[u] = lwpoint_as_lwgeom(lwpoint_construct(state->from_srid, NULL, pa)); } /* If we have more than 1 vertex then we are working on a MULTIPOINT and so generate a MULTIPOINT rather than a POINT */ if ((obj->nVertices > 1) || force_multi) { lwgeom = lwcollection_as_lwgeom(lwcollection_construct(MULTIPOINTTYPE, state->from_srid, NULL, obj->nVertices, lwmultipoints)); } else { lwgeom = lwmultipoints[0]; lwfree(lwmultipoints); } if (state->config->use_wkt) { mem = lwgeom_to_wkt(lwgeom, WKT_EXTENDED, WKT_PRECISION, &mem_length); } else { mem = lwgeom_to_hexwkb(lwgeom, WKB_EXTENDED, &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; }
/** * @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; }
/** * @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; }
/** * @brief Generate an allocated geometry string for shapefile object obj using the state parameters */ int GeneratePointGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry) { LWCOLLECTION *lwcollection; LWGEOM **lwmultipoints; uchar *serialized_lwgeom; LWGEOM_UNPARSER_RESULT lwg_unparser_result; DYNPTARRAY **dpas; POINT4D point4d; int dims = 0, hasz = 0, hasm = 0; int result; int u; 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); /* Allocate memory for our array of LWPOINTs and our dynptarrays */ lwmultipoints = malloc(sizeof(LWPOINT *) * obj->nVertices); dpas = malloc(sizeof(DYNPTARRAY *) * obj->nVertices); /* We need an array of pointers to each of our sub-geometries */ for (u = 0; u < obj->nVertices; u++) { /* Generate the point */ point4d.x = obj->padfX[u]; point4d.y = obj->padfY[u]; if (state->wkbtype & WKBZOFFSET) point4d.z = obj->padfZ[u]; if (state->wkbtype & WKBMOFFSET) point4d.m = obj->padfM[u]; /* Create a dynptarray containing a single point */ dpas[u] = dynptarray_create(1, dims); dynptarray_addPoint4d(dpas[u], &point4d, 0); /* Generate the LWPOINT */ lwmultipoints[u] = lwpoint_as_lwgeom(lwpoint_construct(state->config->sr_id, NULL, dpas[u]->pa)); } /* If we have more than 1 vertex then we are working on a MULTIPOINT and so generate a MULTIPOINT rather than a POINT */ if (obj->nVertices > 1) { lwcollection = lwcollection_construct(MULTIPOINTTYPE, state->config->sr_id, NULL, obj->nVertices, lwmultipoints); serialized_lwgeom = lwgeom_serialize(lwcollection_as_lwgeom(lwcollection)); } else { serialized_lwgeom = lwgeom_serialize(lwmultipoints[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); 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->nVertices; u++) { if (dpas[u]->pa->serialized_pointlist) lwfree(dpas[u]->pa->serialized_pointlist); lwpoint_free(lwgeom_as_lwpoint(lwmultipoints[u])); lwfree(dpas[u]); } lwfree(dpas); lwfree(lwmultipoints); /* Return the string - everything ok */ *geometry = mem; return SHPLOADEROK; }
LWGEOM* pta_unstroke(const POINTARRAY *points, int type, int srid) { int i = 0, j, k; POINT4D a1, a2, a3, b; POINT4D first, center; char *edges_in_arcs; int found_arc = LW_FALSE; int current_arc = 1; int num_edges; int edge_type; /* non-zero if edge is part of an arc */ int start, end; LWCOLLECTION *outcol; /* Minimum number of edges, per quadrant, required to define an arc */ const unsigned int min_quad_edges = 2; /* Die on null input */ if ( ! points ) lwerror("pta_unstroke called with null pointarray"); /* Null on empty input? */ if ( points->npoints == 0 ) return NULL; /* We can't desegmentize anything shorter than four points */ if ( points->npoints < 4 ) { /* Return a linestring here*/ lwerror("pta_unstroke needs implementation for npoints < 4"); } /* Allocate our result array of vertices that are part of arcs */ num_edges = points->npoints - 1; edges_in_arcs = lwalloc(num_edges + 1); memset(edges_in_arcs, 0, num_edges + 1); /* We make a candidate arc of the first two edges, */ /* And then see if the next edge follows it */ while( i < num_edges-2 ) { unsigned int arc_edges; double num_quadrants; double angle; found_arc = LW_FALSE; /* Make candidate arc */ getPoint4d_p(points, i , &a1); getPoint4d_p(points, i+1, &a2); getPoint4d_p(points, i+2, &a3); memcpy(&first, &a1, sizeof(POINT4D)); for( j = i+3; j < num_edges+1; j++ ) { LWDEBUGF(4, "i=%d, j=%d", i, j); getPoint4d_p(points, j, &b); /* Does this point fall on our candidate arc? */ if ( pt_continues_arc(&a1, &a2, &a3, &b) ) { /* Yes. Mark this edge and the two preceding it as arc components */ LWDEBUGF(4, "pt_continues_arc #%d", current_arc); found_arc = LW_TRUE; for ( k = j-1; k > j-4; k-- ) edges_in_arcs[k] = current_arc; } else { /* No. So we're done with this candidate arc */ LWDEBUG(4, "pt_continues_arc = false"); current_arc++; break; } memcpy(&a1, &a2, sizeof(POINT4D)); memcpy(&a2, &a3, sizeof(POINT4D)); memcpy(&a3, &b, sizeof(POINT4D)); } /* Jump past all the edges that were added to the arc */ if ( found_arc ) { /* Check if an arc was composed by enough edges to be * really considered an arc * See http://trac.osgeo.org/postgis/ticket/2420 */ arc_edges = j - 1 - i; LWDEBUGF(4, "arc defined by %d edges found", arc_edges); if ( first.x == b.x && first.y == b.y ) { LWDEBUG(4, "arc is a circle"); num_quadrants = 4; } else { lw_arc_center((POINT2D*)&first, (POINT2D*)&b, (POINT2D*)&a1, (POINT2D*)¢er); angle = lw_arc_angle((POINT2D*)&first, (POINT2D*)¢er, (POINT2D*)&b); int p2_side = lw_segment_side((POINT2D*)&first, (POINT2D*)&a1, (POINT2D*)&b); if ( p2_side >= 0 ) angle = -angle; if ( angle < 0 ) angle = 2 * M_PI + angle; num_quadrants = ( 4 * angle ) / ( 2 * M_PI ); LWDEBUGF(4, "arc angle (%g %g, %g %g, %g %g) is %g (side is %d), quandrants:%g", first.x, first.y, center.x, center.y, b.x, b.y, angle, p2_side, num_quadrants); } /* a1 is first point, b is last point */ if ( arc_edges < min_quad_edges * num_quadrants ) { LWDEBUGF(4, "Not enough edges for a %g quadrants arc, %g needed", num_quadrants, min_quad_edges * num_quadrants); for ( k = j-1; k >= i; k-- ) edges_in_arcs[k] = 0; } i = j-1; } else { /* Mark this edge as a linear edge */ edges_in_arcs[i] = 0; i = i+1; } } #if POSTGIS_DEBUG_LEVEL > 3 { char *edgestr = lwalloc(num_edges+1); for ( i = 0; i < num_edges; i++ ) { if ( edges_in_arcs[i] ) edgestr[i] = 48 + edges_in_arcs[i]; else edgestr[i] = '.'; } edgestr[num_edges] = 0; LWDEBUGF(3, "edge pattern %s", edgestr); lwfree(edgestr); } #endif start = 0; edge_type = edges_in_arcs[0]; outcol = lwcollection_construct_empty(COMPOUNDTYPE, srid, ptarray_has_z(points), ptarray_has_m(points)); for( i = 1; i < num_edges; i++ ) { if( edge_type != edges_in_arcs[i] ) { end = i - 1; lwcollection_add_lwgeom(outcol, geom_from_pa(points, srid, edge_type, start, end)); start = i; edge_type = edges_in_arcs[i]; } } lwfree(edges_in_arcs); /* not needed anymore */ /* Roll out last item */ end = num_edges - 1; lwcollection_add_lwgeom(outcol, geom_from_pa(points, srid, edge_type, start, end)); /* Strip down to singleton if only one entry */ if ( outcol->ngeoms == 1 ) { LWGEOM *outgeom = outcol->geoms[0]; outcol->ngeoms = 0; lwcollection_free(outcol); return outgeom; } return lwcollection_as_lwgeom(outcol); }