static LWGEOM* parse_geojson_multipolygon(json_object *geojson, bool *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); if( json_type_array == json_object_get_type( poObjPolys ) ) { const int nPolys = json_object_array_length( poObjPolys ); for(i = 0; i < nPolys; ++i) { POINTARRAY **ppa; json_object* poObjPoly = NULL; poObjPoly = json_object_array_get_idx( poObjPolys, i ); ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*)); if( json_type_array == json_object_get_type( poObjPoly ) ) { int nPoints; json_object* points = NULL; int ring = json_object_array_length( poObjPoly ); ppa[0] = ptarray_construct_empty(1, 0, 1); points = json_object_array_get_idx( poObjPoly, 0 ); nPoints = json_object_array_length( points ); for (j=0; j < nPoints; j++ ) { json_object* coords = NULL; coords = json_object_array_get_idx( points, j ); parse_geojson_coord(coords, hasz, ppa[0]); } for(j = 1; j < ring; ++j) { int nPoints; ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa, sizeof(POINTARRAY*) * (j + 1)); ppa[i] = ptarray_construct_empty(1, 0, 1); points = json_object_array_get_idx( poObjPoly, j ); nPoints = json_object_array_length( points ); for (k=0; k < nPoints; k++ ) { json_object* coords = NULL; coords = json_object_array_get_idx( points, k ); parse_geojson_coord(coords, hasz, ppa[i]); } } geom = (LWGEOM*)lwmpoly_add_lwpoly((LWMPOLY*)geom, (LWPOLY*)lwpoly_construct(*root_srid, NULL, ring, ppa)); } } } return geom; }
/* Return an LWGEOM from a Geometry */ LWGEOM * GEOS2LWGEOM(const GEOSGeometry *geom, char want3d) { int type = GEOSGeomTypeId(geom) ; int hasZ; int SRID = GEOSGetSRID(geom); /* GEOS's 0 is equivalent to our unknown as for SRID values */ if ( SRID == 0 ) SRID = SRID_UNKNOWN; if ( want3d ) { hasZ = GEOSHasZ(geom); if ( ! hasZ ) { LWDEBUG(3, "Geometry has no Z, won't provide one"); want3d = 0; } } /* if ( GEOSisEmpty(geom) ) { return (LWGEOM*)lwcollection_construct_empty(COLLECTIONTYPE, SRID, want3d, 0); } */ switch (type) { const GEOSCoordSequence *cs; POINTARRAY *pa, **ppaa; const GEOSGeometry *g; LWGEOM **geoms; uint32_t i, ngeoms; case GEOS_POINT: LWDEBUG(4, "lwgeom_from_geometry: it's a Point"); cs = GEOSGeom_getCoordSeq(geom); if ( GEOSisEmpty(geom) ) return (LWGEOM*)lwpoint_construct_empty(SRID, want3d, 0); pa = ptarray_from_GEOSCoordSeq(cs, want3d); return (LWGEOM *)lwpoint_construct(SRID, NULL, pa); case GEOS_LINESTRING: case GEOS_LINEARRING: LWDEBUG(4, "lwgeom_from_geometry: it's a LineString or LinearRing"); if ( GEOSisEmpty(geom) ) return (LWGEOM*)lwline_construct_empty(SRID, want3d, 0); cs = GEOSGeom_getCoordSeq(geom); pa = ptarray_from_GEOSCoordSeq(cs, want3d); return (LWGEOM *)lwline_construct(SRID, NULL, pa); case GEOS_POLYGON: LWDEBUG(4, "lwgeom_from_geometry: it's a Polygon"); if ( GEOSisEmpty(geom) ) return (LWGEOM*)lwpoly_construct_empty(SRID, want3d, 0); ngeoms = GEOSGetNumInteriorRings(geom); ppaa = lwalloc(sizeof(POINTARRAY *)*(ngeoms+1)); g = GEOSGetExteriorRing(geom); cs = GEOSGeom_getCoordSeq(g); ppaa[0] = ptarray_from_GEOSCoordSeq(cs, want3d); for (i=0; i<ngeoms; i++) { g = GEOSGetInteriorRingN(geom, i); cs = GEOSGeom_getCoordSeq(g); ppaa[i+1] = ptarray_from_GEOSCoordSeq(cs, want3d); } return (LWGEOM *)lwpoly_construct(SRID, NULL, ngeoms+1, ppaa); case GEOS_MULTIPOINT: case GEOS_MULTILINESTRING: case GEOS_MULTIPOLYGON: case GEOS_GEOMETRYCOLLECTION: LWDEBUG(4, "lwgeom_from_geometry: it's a Collection or Multi"); ngeoms = GEOSGetNumGeometries(geom); geoms = NULL; if ( ngeoms ) { geoms = lwalloc(sizeof(LWGEOM *)*ngeoms); for (i=0; i<ngeoms; i++) { g = GEOSGetGeometryN(geom, i); geoms[i] = GEOS2LWGEOM(g, want3d); } } return (LWGEOM *)lwcollection_construct(type, SRID, NULL, ngeoms, geoms); default: lwerror("GEOS2LWGEOM: unknown geometry type: %d", type); return NULL; } }
int * lwgeom_cluster_2d_kmeans(const LWGEOM **geoms, int ngeoms, int k) { int i; int num_centroids = 0; LWGEOM **centroids; POINT2D *centers_raw; const POINT2D *cp; POINT2D min = { DBL_MAX, DBL_MAX }; POINT2D max = { -DBL_MAX, -DBL_MAX }; double dx, dy; kmeans_config config; kmeans_result result; int *seen; int sidx = 0; assert(k>0); assert(ngeoms>0); assert(geoms); /* Initialize our static structs */ memset(&config, 0, sizeof(kmeans_config)); memset(&result, 0, sizeof(kmeans_result)); if (ngeoms<k) { lwerror("%s: number of geometries is less than the number of clusters requested", __func__); } /* We'll hold the temporary centroid objects here */ centroids = lwalloc(sizeof(LWGEOM*) * ngeoms); memset(centroids, 0, sizeof(LWGEOM*) * ngeoms); /* The vector of cluster means. We have to allocate a */ /* chunk of memory for these because we'll be mutating them */ /* in the kmeans algorithm */ centers_raw = lwalloc(sizeof(POINT2D) * k); memset(centers_raw, 0, sizeof(POINT2D) * k); /* K-means configuration setup */ config.objs = lwalloc(sizeof(Pointer) * ngeoms); config.num_objs = ngeoms; config.clusters = lwalloc(sizeof(int) * ngeoms); config.centers = lwalloc(sizeof(Pointer) * k); config.k = k; config.max_iterations = 0; config.distance_method = lwkmeans_pt_distance; config.centroid_method = lwkmeans_pt_centroid; /* Clean the memory */ memset(config.objs, 0, sizeof(Pointer) * ngeoms); memset(config.clusters, 0, sizeof(int) * ngeoms); memset(config.centers, 0, sizeof(Pointer) * k); /* Prepare the list of object pointers for K-means */ for (i = 0; i < ngeoms; i++) { const LWGEOM *geom = geoms[i]; LWPOINT *lwpoint; /* Null/empty geometries get a NULL pointer */ if ((!geom) || lwgeom_is_empty(geom)) { config.objs[i] = NULL; continue; } /* If the input is a point, use its coordinates */ /* If its not a point, convert it to one via centroid */ if (lwgeom_get_type(geom) != POINTTYPE) { LWGEOM *centroid = lwgeom_centroid(geom); if ((!centroid) || lwgeom_is_empty(centroid)) { config.objs[i] = NULL; continue; } centroids[num_centroids++] = centroid; lwpoint = lwgeom_as_lwpoint(centroid); } else { lwpoint = lwgeom_as_lwpoint(geom); } /* Store a pointer to the POINT2D we are interested in */ cp = getPoint2d_cp(lwpoint->point, 0); config.objs[i] = (Pointer)cp; /* Since we're already here, let's calculate the extrema of the set */ if (cp->x < min.x) min.x = cp->x; if (cp->y < min.y) min.y = cp->y; if (cp->x > max.x) max.x = cp->x; if (cp->y > max.y) max.y = cp->y; } /* * We map a uniform assignment of points in the area covered by the set * onto actual points in the set */ dx = (max.x - min.x)/k; dy = (max.y - min.y)/k; seen = lwalloc(sizeof(int)*config.k); memset(seen, 0, sizeof(int)*config.k); for (i = 0; i < k; i++) { int closest; POINT2D p; int j; /* Calculate a point in the range */ p.x = min.x + dx * (i + 0.5); p.y = min.y + dy * (i + 0.5); /* Find the data point closest to the calculated point */ closest = lwkmeans_pt_closest(config.objs, config.num_objs, &p); /* If something is terrible wrong w/ data, cannot find a closest */ if (closest < 0) lwerror("unable to calculate cluster seed points, too many NULLs or empties?"); /* Ensure we aren't already using that point as a seed */ j = 0; while(j < sidx) { if (seen[j] == closest) { closest = (closest + 1) % config.num_objs; j = 0; } else { j++; } } seen[sidx++] = closest; /* Copy the point coordinates into the initial centers array */ /* This is ugly, but the centers array is an array of */ /* pointers to points, not an array of points */ centers_raw[i] = *((POINT2D*)config.objs[closest]); config.centers[i] = &(centers_raw[i]); } result = kmeans(&config); /* Before error handling, might as well clean up all the inputs */ lwfree(config.objs); lwfree(config.centers); lwfree(centers_raw); lwfree(centroids); lwfree(seen); /* Good result */ if (result == KMEANS_OK) return config.clusters; /* Bad result, not going to need the answer */ lwfree(config.clusters); if (result == KMEANS_EXCEEDED_MAX_ITERATIONS) { lwerror("%s did not converge after %d iterations", __func__, config.max_iterations); return NULL; } /* Unknown error */ return NULL; }
/* We supposed that the geometry is valid we could have wrong result if not */ int lwtin_is_closed(const LWTIN *tin) { int i, j, k; int narcs, carc; int found; tin_arcs arcs; POINT4D pa, pb; LWTRIANGLE *patch; /* If surface is not 3D, it's can't be closed */ if (!FLAGS_GET_Z(tin->flags)) return 0; /* Max theorical arcs number if no one is shared ... */ narcs = 3 * tin->ngeoms; arcs = lwalloc(sizeof(struct struct_tin_arcs) * narcs); for (i=0, carc=0; i < tin->ngeoms ; i++) { patch = (LWTRIANGLE *) tin->geoms[i]; for (j=0; j < 3 ; j++) { getPoint4d_p(patch->points, j, &pa); getPoint4d_p(patch->points, j+1, &pb); /* Make sure to order the 'lower' point first */ if ( (pa.x > pb.x) || (pa.x == pb.x && pa.y > pb.y) || (pa.x == pb.x && pa.y == pb.y && pa.z > pb.z) ) { pa = pb; getPoint4d_p(patch->points, j, &pb); } for (found=0, k=0; k < carc ; k++) { if ( ( arcs[k].ax == pa.x && arcs[k].ay == pa.y && arcs[k].az == pa.z && arcs[k].bx == pb.x && arcs[k].by == pb.y && arcs[k].bz == pb.z && arcs[k].face != i) ) { arcs[k].cnt++; found = 1; /* Look like an invalid TIN anyway not a closed one */ if (arcs[k].cnt > 2) { lwfree(arcs); return 0; } } } if (!found) { arcs[carc].cnt=1; arcs[carc].face=i; arcs[carc].ax = pa.x; arcs[carc].ay = pa.y; arcs[carc].az = pa.z; arcs[carc].bx = pb.x; arcs[carc].by = pb.y; arcs[carc].bz = pb.z; carc++; /* Look like an invalid TIN anyway not a closed one */ if (carc > narcs) { lwfree(arcs); return 0; } } } } /* A TIN is closed if each edge is shared by exactly 2 faces */ for (k=0; k < carc ; k++) { if (arcs[k].cnt != 2) { lwfree(arcs); return 0; } } lwfree(arcs); /* Invalid TIN case */ if (carc < tin->ngeoms) return 0; return 1; }
GEOSGeometry* LWGEOM_GEOS_buildArea(const GEOSGeometry* geom_in) { GEOSGeometry *tmp; GEOSGeometry *geos_result, *shp; GEOSGeometry const *vgeoms[1]; uint32_t i, ngeoms; int srid = GEOSGetSRID(geom_in); Face ** geoms; vgeoms[0] = geom_in; #ifdef LWGEOM_PROFILE_BUILDAREA lwnotice("Polygonizing"); #endif geos_result = GEOSPolygonize(vgeoms, 1); LWDEBUGF(3, "GEOSpolygonize returned @ %p", geos_result); /* Null return from GEOSpolygonize (an exception) */ if ( ! geos_result ) return 0; /* * We should now have a collection */ #if PARANOIA_LEVEL > 0 if ( GEOSGeometryTypeId(geos_result) != COLLECTIONTYPE ) { GEOSGeom_destroy(geos_result); lwerror("Unexpected return from GEOSpolygonize"); return 0; } #endif ngeoms = GEOSGetNumGeometries(geos_result); #ifdef LWGEOM_PROFILE_BUILDAREA lwnotice("Num geometries from polygonizer: %d", ngeoms); #endif LWDEBUGF(3, "GEOSpolygonize: ngeoms in polygonize output: %d", ngeoms); LWDEBUGF(3, "GEOSpolygonize: polygonized:%s", lwgeom_to_ewkt(GEOS2LWGEOM(geos_result, 0))); /* * No geometries in collection, early out */ if ( ngeoms == 0 ) { GEOSSetSRID(geos_result, srid); return geos_result; } /* * Return first geometry if we only have one in collection, * to avoid the unnecessary Geometry clone below. */ if ( ngeoms == 1 ) { tmp = (GEOSGeometry *)GEOSGetGeometryN(geos_result, 0); if ( ! tmp ) { GEOSGeom_destroy(geos_result); return 0; /* exception */ } shp = GEOSGeom_clone(tmp); GEOSGeom_destroy(geos_result); /* only safe after the clone above */ GEOSSetSRID(shp, srid); return shp; } LWDEBUGF(2, "Polygonize returned %d geoms", ngeoms); /* * Polygonizer returns a polygon for each face in the built topology. * * This means that for any face with holes we'll have other faces * representing each hole. We can imagine a parent-child relationship * between these faces. * * In order to maximize the number of visible rings in output we * only use those faces which have an even number of parents. * * Example: * * +---------------+ * | L0 | L0 has no parents * | +---------+ | * | | L1 | | L1 is an hole of L0 * | | +---+ | | * | | |L2 | | | L2 is an hole of L1 (which is an hole of L0) * | | | | | | * | | +---+ | | * | +---------+ | * | | * +---------------+ * * See http://trac.osgeo.org/postgis/ticket/1806 * */ #ifdef LWGEOM_PROFILE_BUILDAREA lwnotice("Preparing face structures"); #endif /* Prepare face structures for later analysis */ geoms = lwalloc(sizeof(Face**)*ngeoms); for (i=0; i<ngeoms; ++i) geoms[i] = newFace(GEOSGetGeometryN(geos_result, i)); #ifdef LWGEOM_PROFILE_BUILDAREA lwnotice("Finding face holes"); #endif /* Find faces representing other faces holes */ findFaceHoles(geoms, ngeoms); #ifdef LWGEOM_PROFILE_BUILDAREA lwnotice("Colletting even ancestor faces"); #endif /* Build a MultiPolygon composed only by faces with an * even number of ancestors */ tmp = collectFacesWithEvenAncestors(geoms, ngeoms); #ifdef LWGEOM_PROFILE_BUILDAREA lwnotice("Cleaning up"); #endif /* Cleanup face structures */ for (i=0; i<ngeoms; ++i) delFace(geoms[i]); lwfree(geoms); /* Faces referenced memory owned by geos_result. * It is safe to destroy geos_result after deleting them. */ GEOSGeom_destroy(geos_result); #ifdef LWGEOM_PROFILE_BUILDAREA lwnotice("Self-unioning"); #endif /* Run a single overlay operation to dissolve shared edges */ shp = GEOSUnionCascaded(tmp); if ( ! shp ) { GEOSGeom_destroy(tmp); return 0; /* exception */ } #ifdef LWGEOM_PROFILE_BUILDAREA lwnotice("Final cleanup"); #endif GEOSGeom_destroy(tmp); GEOSSetSRID(shp, srid); return shp; }
/* * Add an edge to a face in a tgeom * Edge is describded as a starting and an ending point * Points are really copied * Return the new tgeom pointer */ static TGEOM* tgeom_add_face_edge(TGEOM *tgeom, int face_id, POINT4D *s, POINT4D *e) { int nedges, edge_id; assert(tgeom); assert(s); assert(e); edge_id = tgeom_is_edge(tgeom, s, e); if (edge_id) { tgeom->edges[abs(edge_id)]->count++; LWDEBUGF(3, "face [%i] Founded Edge: %i\n", face_id, edge_id); } else { if ((tgeom->nedges + 1) == INT_MAX) lwerror("tgeom_add_face_edge: Unable to alloc more than %i edges", INT_MAX); /* alloc edges array */ if (tgeom->maxedges == 0) { tgeom->edges = (TEDGE**) lwalloc(sizeof(TEDGE*) * 4); tgeom->maxedges = 4; } if (tgeom->maxedges >= (tgeom->nedges + 1)) { tgeom->edges = (TEDGE **) lwrealloc(tgeom->edges, sizeof(TEDGE*) * tgeom->maxedges * 2); tgeom->maxedges *= 2; } edge_id = ++tgeom->nedges; /* edge_id is 1 based */ tgeom->edges[edge_id] = (TEDGE*) lwalloc(sizeof(TEDGE)); tgeom->edges[edge_id]->s = lwalloc(sizeof(POINT4D)); tgeom->edges[edge_id]->e = lwalloc(sizeof(POINT4D)); memcpy(tgeom->edges[edge_id]->s, s, sizeof(POINT4D)); memcpy(tgeom->edges[edge_id]->e, e, sizeof(POINT4D)); tgeom->edges[edge_id]->count = 1; LWDEBUGF(3, "face [%i] adding edge [%i] (%lf, %lf, %lf, %lf) -> (%lf, %lf, %lf, %lf)\n", face_id, edge_id, s->x, s->y, s->z, s->m, e->x, e->y, e->z, e->m); } nedges = tgeom->faces[face_id]->nedges; if (tgeom->faces[face_id]->maxedges == 0) { tgeom->faces[face_id]->edges = (int *) lwalloc(sizeof(int) * 4); tgeom->faces[face_id]->maxedges = 4; } if (tgeom->faces[face_id]->maxedges == nedges) { tgeom->faces[face_id]->edges = (int *) lwrealloc(tgeom->faces[face_id]->edges, sizeof(int) * tgeom->faces[face_id]->maxedges * 2); tgeom->faces[face_id]->maxedges *= 2; } LWDEBUGF(3, "face [%i] add %i in edge array in %i pos\n", face_id, edge_id, tgeom->faces[face_id]->nedges); tgeom->faces[face_id]->edges[nedges]= edge_id; tgeom->faces[face_id]->nedges++; return tgeom; }
/* We supposed that the geometry is valid we could have wrong result if not */ int lwpsurface_is_closed(const LWPSURFACE *psurface) { int i, j, k; int narcs, carc; int found; psurface_arcs arcs; POINT4D pa, pb; LWPOLY *patch; /* If surface is not 3D, it's can't be closed */ if (!FLAGS_GET_Z(psurface->flags)) return 0; /* If surface is less than 4 faces hard to be closed too */ if (psurface->ngeoms < 4) return 0; /* Max theorical arcs number if no one is shared ... */ for (i=0, narcs=0 ; i < psurface->ngeoms ; i++) { patch = (LWPOLY *) psurface->geoms[i]; narcs += patch->rings[0]->npoints - 1; } arcs = lwalloc(sizeof(struct struct_psurface_arcs) * narcs); for (i=0, carc=0; i < psurface->ngeoms ; i++) { patch = (LWPOLY *) psurface->geoms[i]; for (j=0; j < patch->rings[0]->npoints - 1; j++) { getPoint4d_p(patch->rings[0], j, &pa); getPoint4d_p(patch->rings[0], j+1, &pb); /* remove redundant points if any */ if (pa.x == pb.x && pa.y == pb.y && pa.z == pb.z) continue; /* Make sure to order the 'lower' point first */ if ( (pa.x > pb.x) || (pa.x == pb.x && pa.y > pb.y) || (pa.x == pb.x && pa.y == pb.y && pa.z > pb.z) ) { pa = pb; getPoint4d_p(patch->rings[0], j, &pb); } for (found=0, k=0; k < carc ; k++) { if ( ( arcs[k].ax == pa.x && arcs[k].ay == pa.y && arcs[k].az == pa.z && arcs[k].bx == pb.x && arcs[k].by == pb.y && arcs[k].bz == pb.z && arcs[k].face != i) ) { arcs[k].cnt++; found = 1; /* Look like an invalid PolyhedralSurface anyway not a closed one */ if (arcs[k].cnt > 2) { lwfree(arcs); return 0; } } } if (!found) { arcs[carc].cnt=1; arcs[carc].face=i; arcs[carc].ax = pa.x; arcs[carc].ay = pa.y; arcs[carc].az = pa.z; arcs[carc].bx = pb.x; arcs[carc].by = pb.y; arcs[carc].bz = pb.z; carc++; /* Look like an invalid PolyhedralSurface anyway not a closed one */ if (carc > narcs) { lwfree(arcs); return 0; } } } } /* A polyhedron is closed if each edge is shared by exactly 2 faces */ for (k=0; k < carc ; k++) { if (arcs[k].cnt != 2) { lwfree(arcs); return 0; } } lwfree(arcs); /* Invalid Polyhedral case */ if (carc < psurface->ngeoms) return 0; return 1; }
Datum BOX2D_to_LWGEOM(PG_FUNCTION_ARGS) { GBOX *box = (GBOX *)PG_GETARG_POINTER(0); POINTARRAY *pa = ptarray_construct_empty(0, 0, 5); POINT4D pt; GSERIALIZED *result; /* * Alter BOX2D cast so that a valid geometry is always * returned depending upon the size of the BOX2D. The * code makes the following assumptions: * - If the BOX2D is a single point then return a * POINT geometry * - If the BOX2D represents either a horizontal or * vertical line, return a LINESTRING geometry * - Otherwise return a POLYGON */ if ( (box->xmin == box->xmax) && (box->ymin == box->ymax) ) { /* Construct and serialize point */ LWPOINT *point = lwpoint_make2d(SRID_UNKNOWN, box->xmin, box->ymin); result = geometry_serialize(lwpoint_as_lwgeom(point)); lwpoint_free(point); } else if ( (box->xmin == box->xmax) || (box->ymin == box->ymax) ) { LWLINE *line; /* Assign coordinates to point array */ pt.x = box->xmin; pt.y = box->ymin; ptarray_append_point(pa, &pt, LW_TRUE); pt.x = box->xmax; pt.y = box->ymax; ptarray_append_point(pa, &pt, LW_TRUE); /* Construct and serialize linestring */ line = lwline_construct(SRID_UNKNOWN, NULL, pa); result = geometry_serialize(lwline_as_lwgeom(line)); lwline_free(line); } else { LWPOLY *poly; POINTARRAY **ppa = lwalloc(sizeof(POINTARRAY*)); /* Assign coordinates to point array */ pt.x = box->xmin; pt.y = box->ymin; ptarray_append_point(pa, &pt, LW_TRUE); pt.x = box->xmin; pt.y = box->ymax; ptarray_append_point(pa, &pt, LW_TRUE); pt.x = box->xmax; pt.y = box->ymax; ptarray_append_point(pa, &pt, LW_TRUE); pt.x = box->xmax; pt.y = box->ymin; ptarray_append_point(pa, &pt, LW_TRUE); pt.x = box->xmin; pt.y = box->ymin; ptarray_append_point(pa, &pt, LW_TRUE); /* Construct polygon */ ppa[0] = pa; poly = lwpoly_construct(SRID_UNKNOWN, NULL, 1, ppa); result = geometry_serialize(lwpoly_as_lwgeom(poly)); lwpoly_free(poly); } PG_RETURN_POINTER(result); }
GBOX* gbox_clone(const GBOX *gbox) { GBOX *g = lwalloc(sizeof(GBOX)); memcpy(g, gbox, sizeof(GBOX)); return g; }
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); }
Datum LWGEOM_line_substring(PG_FUNCTION_ARGS) { GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(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 isn't within [0,1]"); PG_RETURN_NULL(); } if ( to < 0 || to > 1 ) { elog(ERROR,"line_interpolate_point: 3rd arg isn't 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(SRID_UNKNOWN, NULL, opa); homogeneous = LW_FALSE; } else { geoms[g] = (LWGEOM *)lwline_construct(SRID_UNKNOWN, 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_substring: 1st arg isn't a line"); PG_RETURN_NULL(); } ret = geometry_serialize(olwgeom); lwgeom_free(olwgeom); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(ret); }
/* * Deserialize a TSERIALIZED struct and * return a TGEOM pointer */ TGEOM * tgeom_deserialize(TSERIALIZED *serialized_form) { uint8_t type, flags; TGEOM *result; uint8_t *loc, *data; int i, j; assert(serialized_form); assert(serialized_form->data); data = serialized_form->data; /* type and flags */ type = data[0]; flags = data[1]; result = tgeom_new(type, FLAGS_GET_Z(flags), FLAGS_GET_M(flags)); loc = data + 2; /* srid */ result->srid = lw_get_int32_t(loc); loc += 4; /* bbox */ if (FLAGS_GET_BBOX(flags)) { result->bbox = lwalloc(sizeof(BOX3D)); memcpy(result->bbox, loc, sizeof(BOX3D)); loc += sizeof(BOX3D); } else result->bbox = NULL; /* edges number (0=> EMPTY) */ result->nedges = lw_get_int32_t(loc); loc += 4; /* edges */ result->edges = lwalloc(sizeof(TEDGE*) * (result->nedges + 1)); for (i=1 ; i <= result->nedges ; i++) { result->edges[i] = lwalloc(sizeof(TEDGE)); result->edges[i]->s = lwalloc(sizeof(POINT4D)); result->edges[i]->e = lwalloc(sizeof(POINT4D)); /* 3DM specific handle */ if (!FLAGS_GET_Z(result->flags) && FLAGS_GET_M(result->flags)) { memcpy(result->edges[i]->s, loc, sizeof(double) * 2); loc += sizeof(double) * 2; memcpy(&(result->edges[i]->s->m), loc, sizeof(double)); loc += sizeof(double); memcpy(result->edges[i]->e, loc, sizeof(double) * 2); loc += sizeof(double) * 2; memcpy(&(result->edges[i]->e->m), loc, sizeof(double)); loc += sizeof(double); } else /* 2D,3DZ && 4D */ { memcpy(result->edges[i]->s, loc, sizeof(double) * FLAGS_NDIMS(flags)); loc += sizeof(double) * FLAGS_NDIMS(flags); result->edges[i]->e = lwalloc(sizeof(POINT4D)); memcpy(result->edges[i]->e, loc, sizeof(double) * FLAGS_NDIMS(flags)); loc += sizeof(double) * FLAGS_NDIMS(flags); } result->edges[i]->count = lw_get_int32_t(loc); loc += 4; } /* faces number */ result->nfaces = lw_get_int32_t(loc); loc += 4; /* faces */ result->faces = lwalloc(sizeof(TFACE*) * result->nfaces); for (i=0 ; i < result->nfaces ; i++) { result->faces[i] = lwalloc(sizeof(TFACE)); /* number of edges */ result->faces[i]->nedges = lw_get_int32_t(loc); loc += 4; /* edges array */ result->faces[i]->edges = lwalloc(sizeof(TEDGE*) * result->faces[i]->nedges); memcpy(result->faces[i]->edges, loc, sizeof(TEDGE*) * result->faces[i]->nedges); loc += 4 * result->faces[i]->nedges; /* number of rings */ result->faces[i]->nrings = lw_get_int32_t(loc); loc += 4; if (result->faces[i]->nrings) result->faces[i]->rings = lwalloc(sizeof(POINTARRAY*) * result->faces[i]->nrings); for (j=0 ; j < result->faces[i]->nrings ; j++) { int npoints; /* number of points */ npoints = lw_get_int32_t(loc); loc += 4; /* pointarray */ result->faces[i]->rings[j] = ptarray_construct_reference_data(FLAGS_GET_Z(flags), FLAGS_GET_M(flags), npoints, loc); loc += sizeof(double)* FLAGS_NDIMS(flags) * npoints; } } return result; }
/* * Return a LWGEOM pointer from an TGEOM struct * Geometries are NOT copied */ LWGEOM* lwgeom_from_tgeom(TGEOM *tgeom) { int i, j, k; LWGEOM *geom; POINTARRAY *dpa; POINTARRAY **ppa; int hasz, hasm, edge_id; int dims=0; assert(tgeom); hasz=FLAGS_GET_Z(tgeom->flags); hasm=FLAGS_GET_M(tgeom->flags); geom = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, tgeom->srid, hasz, hasm); switch (tgeom->type) { case TINTYPE: geom->type = TINTYPE; for (i=0 ; i < tgeom->nfaces ; i++) { FLAGS_SET_Z(dims, hasz?1:0); FLAGS_SET_M(dims, hasm?1:0); dpa = ptarray_construct_empty(hasz, hasm, 4); for (j=0 ; j < tgeom->faces[i]->nedges ; j++) { edge_id = tgeom->faces[i]->edges[j]; LWDEBUGF(3, "TIN edge_id: %i\n", edge_id); assert(edge_id); if (edge_id > 0) ptarray_append_point(dpa, tgeom->edges[edge_id]->s, LW_TRUE); else ptarray_append_point(dpa, tgeom->edges[-edge_id]->e, LW_TRUE); } edge_id = tgeom->faces[i]->edges[0]; LWDEBUGF(3, "TIN edge_id: %i\n", edge_id); if (edge_id > 0) ptarray_append_point(dpa, tgeom->edges[edge_id]->s, LW_TRUE); else ptarray_append_point(dpa, tgeom->edges[-edge_id]->e, LW_TRUE); geom = (LWGEOM *) lwtin_add_lwtriangle((LWTIN *) geom, lwtriangle_construct(tgeom->srid, NULL, dpa)); } break; case POLYHEDRALSURFACETYPE: geom->type = POLYHEDRALSURFACETYPE; for (i=0 ; i < tgeom->nfaces ; i++) { FLAGS_SET_Z(dims, hasz?1:0); FLAGS_SET_M(dims, hasm?1:0);; dpa = ptarray_construct_empty(hasz, hasm, 4); for (j=0 ; j < tgeom->faces[i]->nedges ; j++) { edge_id = tgeom->faces[i]->edges[j]; assert(edge_id); LWDEBUGF(3, "POLYHEDRALSURFACE edge_id: %i\n", edge_id); if (edge_id > 0) ptarray_append_point(dpa, tgeom->edges[edge_id]->s, LW_TRUE); else ptarray_append_point(dpa, tgeom->edges[-edge_id]->e, LW_TRUE); } edge_id = tgeom->faces[i]->edges[0]; LWDEBUGF(3, "POLYHEDRALSURFACE edge_id: %i\n", edge_id); if (edge_id > 0) ptarray_append_point(dpa, tgeom->edges[edge_id]->s, LW_TRUE); else ptarray_append_point(dpa, tgeom->edges[-edge_id]->e, LW_TRUE); ppa = lwalloc(sizeof(POINTARRAY*) * (tgeom->faces[i]->nrings + 1)); ppa[0] = dpa; for (k=0; k < tgeom->faces[i]->nrings ; k++) ppa[k+1] = tgeom->faces[i]->rings[k]; geom = (LWGEOM *) lwpsurface_add_lwpoly((LWPSURFACE *) geom, lwpoly_construct(tgeom->srid, NULL, k + 1, ppa)); } break; default: lwerror("lwgeom_from_tgeom: Unkwnown type %i - %s\n", tgeom->type, lwtype_name(tgeom->type)); } if (geom->srid == 0) geom->srid = SRID_UNKNOWN; return geom; }
/* * Add a LWPOLY inside a tgeom * Copy geometries from LWPOLY */ static TGEOM* tgeom_add_polygon(TGEOM *tgeom, LWPOLY *poly) { int i; assert(tgeom); assert(poly); if ((tgeom->nfaces + 1) == INT_MAX) lwerror("tgeom_add_polygon: Unable to alloc more than %i faces", INT_MAX); /* Integrity checks on subgeom, dims and srid */ if (tgeom->type != POLYHEDRALSURFACETYPE) lwerror("tgeom_add_polygon: Unable to handle %s - %s type", tgeom->type, lwtype_name(tgeom->type)); if (FLAGS_NDIMS(tgeom->flags) != FLAGS_NDIMS(poly->flags)) lwerror("tgeom_add_polygon: Mixed dimension"); if (tgeom->srid != poly->srid && (tgeom->srid != 0 && poly->srid != SRID_UNKNOWN)) lwerror("tgeom_add_polygon: Mixed srid. Tgeom: %i / Polygon: %i", tgeom->srid, poly->srid); /* handle face array allocation */ if (tgeom->maxfaces == 0) { tgeom->faces = lwalloc(sizeof(TFACE*) * 2); tgeom->maxfaces = 2; } if ((tgeom->maxfaces - 1) == tgeom->nfaces) { tgeom->faces = lwrealloc(tgeom->faces, sizeof(TFACE*) * tgeom->maxfaces * 2); tgeom->maxfaces *= 2; } /* add an empty face */ tgeom->faces[tgeom->nfaces] = lwalloc(sizeof(TFACE)); tgeom->faces[tgeom->nfaces]->rings = NULL; tgeom->faces[tgeom->nfaces]->nrings = 0; tgeom->faces[tgeom->nfaces]->nedges = 0; tgeom->faces[tgeom->nfaces]->maxedges = 0; /* Compute edge on poly external ring */ for (i=1 ; i < poly->rings[0]->npoints ; i++) { POINT4D p1, p2; getPoint4d_p(poly->rings[0], i-1, &p1); getPoint4d_p(poly->rings[0], i, &p2); tgeom_add_face_edge(tgeom, tgeom->nfaces, &p1, &p2); } /* External ring is already handled by edges */ tgeom->faces[tgeom->nfaces]->nrings = poly->nrings - 1; /* handle rings array allocation */ if (tgeom->faces[tgeom->nfaces]->nrings >= 1) tgeom->faces[tgeom->nfaces]->rings = lwalloc(sizeof(POINTARRAY*) * tgeom->faces[tgeom->nfaces]->nrings); /* clone internal rings */ for (i=0 ; i < tgeom->faces[tgeom->nfaces]->nrings ; i++) tgeom->faces[tgeom->nfaces]->rings[i] = ptarray_clone_deep(poly->rings[i+1]); tgeom->nfaces++; return tgeom; }
Datum LWGEOM_interiorringn_polygon(PG_FUNCTION_ARGS) { GSERIALIZED *geom; int32 wanted_index; LWCURVEPOLY *curvepoly = NULL; LWPOLY *poly = NULL; POINTARRAY *ring; LWLINE *line; LWGEOM *lwgeom; GSERIALIZED *result; GBOX *bbox = NULL; int type; POSTGIS_DEBUG(2, "LWGEOM_interierringn_polygon called."); wanted_index = PG_GETARG_INT32(1); if ( wanted_index < 1 ) { /* elog(ERROR, "InteriorRingN: ring number is 1-based"); */ PG_RETURN_NULL(); /* index out of range */ } geom = PG_GETARG_GSERIALIZED_P(0); type = gserialized_get_type(geom); if ( (type != POLYGONTYPE) && (type != CURVEPOLYTYPE) ) { elog(ERROR, "InteriorRingN: geom is not a polygon"); PG_FREE_IF_COPY(geom, 0); PG_RETURN_NULL(); } lwgeom = lwgeom_from_gserialized(geom); if( lwgeom_is_empty(lwgeom) ) { lwpoly_free(poly); PG_FREE_IF_COPY(geom, 0); PG_RETURN_NULL(); } if ( type == POLYGONTYPE) { poly = lwgeom_as_lwpoly(lwgeom_from_gserialized(geom)); /* Ok, now we have a polygon. Let's see if it has enough holes */ if ( wanted_index >= poly->nrings ) { lwpoly_free(poly); PG_FREE_IF_COPY(geom, 0); PG_RETURN_NULL(); } ring = poly->rings[wanted_index]; /* COMPUTE_BBOX==TAINTING */ if ( poly->bbox ) { bbox = lwalloc(sizeof(GBOX)); ptarray_calculate_gbox_cartesian(ring, bbox); } /* This is a LWLINE constructed by interior ring POINTARRAY */ line = lwline_construct(poly->srid, bbox, ring); result = geometry_serialize((LWGEOM *)line); lwline_release(line); lwpoly_free(poly); } else { curvepoly = lwgeom_as_lwcurvepoly(lwgeom_from_gserialized(geom)); if (wanted_index >= curvepoly->nrings) { PG_FREE_IF_COPY(geom, 0); lwgeom_release((LWGEOM *)curvepoly); PG_RETURN_NULL(); } result = geometry_serialize(curvepoly->rings[wanted_index]); lwgeom_free((LWGEOM*)curvepoly); } PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(result); }
/** * Create a new internal node, calculating the new measure range for the node, * and storing pointers to the child nodes. */ static CIRC_NODE* circ_node_internal_new(CIRC_NODE** c, int num_nodes) { CIRC_NODE *node = NULL; GEOGRAPHIC_POINT new_center, c1; double new_radius; double offset1, dist, D, r1, ri; int i; LWDEBUGF(3, "called with %d nodes --", num_nodes); /* Can't do anything w/ empty input */ if ( num_nodes < 1 ) return node; /* Initialize calculation with values of the first circle */ new_center = c[0]->center; new_radius = c[0]->radius; /* Merge each remaining circle into the new circle */ for ( i = 1; i < num_nodes; i++ ) { c1 = new_center; r1 = new_radius; dist = sphere_distance(&c1, &(c[i]->center)); ri = c[i]->radius; LWDEBUGF(3, "distance between new (%g %g) and %i (%g %g) is %g", c1.lon, c1.lat, i, c[i]->center.lon, c[i]->center.lat, dist); if ( FP_EQUALS(dist, 0) ) { LWDEBUG(3, " distance between centers is zero"); new_radius = r1 + 2*dist; new_center = c1; } else if ( dist < fabs(r1 - ri) ) { /* new contains next */ if ( r1 > ri ) { LWDEBUG(3, " c1 contains ci"); new_center = c1; new_radius = r1; } /* next contains new */ else { LWDEBUG(3, " ci contains c1"); new_center = c[i]->center; new_radius = ri; } } else { LWDEBUG(3, " calculating new center"); /* New circle diameter */ D = dist + r1 + ri; LWDEBUGF(3," D is %g", D); /* New radius */ new_radius = D / 2.0; /* Distance from cn1 center to the new center */ offset1 = ri + (D - (2.0*r1 + 2.0*ri)) / 2.0; LWDEBUGF(3," offset1 is %g", offset1); /* Sometimes the sphere_direction function fails... this causes the center calculation */ /* to fail too. In that case, we're going to fall back ot a cartesian calculation, which */ /* is less exact, so we also have to pad the radius by (hack alert) an arbitrary amount */ /* which is hopefully always big enough to contain the input edges */ if ( circ_center_spherical(&c1, &(c[i]->center), dist, offset1, &new_center) == LW_FAILURE ) { circ_center_cartesian(&c1, &(c[i]->center), dist, offset1, &new_center); new_radius *= 1.1; } } LWDEBUGF(3, " new center is (%g %g) new radius is %g", new_center.lon, new_center.lat, new_radius); } node = lwalloc(sizeof(CIRC_NODE)); node->p1 = NULL; node->p2 = NULL; node->center = new_center; node->radius = new_radius; node->num_nodes = num_nodes; node->nodes = c; node->edge_num = -1; return node; }
GBOX* gbox_copy(const GBOX *box) { GBOX *copy = (GBOX*)lwalloc(sizeof(GBOX)); memcpy(copy, box, sizeof(GBOX)); return copy; }
/** The new faster calculation comparing pointarray to another pointarray the arrays can come from both polygons and linestrings. The naming is not good but comes from that it compares a chosen selection of the points not all of them */ int lw_dist2d_fast_ptarray_ptarray(POINTARRAY *l1, POINTARRAY *l2,DISTPTS *dl, GBOX *box1, GBOX *box2) { /*here we define two lists to hold our calculated "z"-values and the order number in the geometry*/ double k, thevalue; float deltaX, deltaY, c1m, c2m; POINT2D theP,c1, c2; float min1X, max1X, max1Y, min1Y,min2X, max2X, max2Y, min2Y; int t; int n1 = l1->npoints; int n2 = l2->npoints; LISTSTRUCT *list1, *list2; list1 = (LISTSTRUCT*)lwalloc(sizeof(LISTSTRUCT)*n1); list2 = (LISTSTRUCT*)lwalloc(sizeof(LISTSTRUCT)*n2); LWDEBUG(2, "lw_dist2d_fast_ptarray_ptarray is called"); max1X = box1->xmax; min1X = box1->xmin; max1Y = box1->ymax; min1Y = box1->ymin; max2X = box2->xmax; min2X = box2->xmin; max2Y = box2->ymax; min2Y = box2->ymin; /*we want the center of the bboxes, and calculate the slope between the centerpoints*/ c1.x = min1X + (max1X-min1X)/2; c1.y = min1Y + (max1Y-min1Y)/2; c2.x = min2X + (max2X-min2X)/2; c2.y = min2Y + (max2Y-min2Y)/2; deltaX=(c2.x-c1.x); deltaY=(c2.y-c1.y); /*Here we calculate where the line perpendicular to the center-center line crosses the axes for each vertex if the center-center line is vertical the perpendicular line will be horizontal and we find it's crossing the Y-axes with z = y-kx */ if ((deltaX*deltaX)<(deltaY*deltaY)) /*North or South*/ { k = -deltaX/deltaY; for (t=0; t<n1; t++) /*for each segment in L1 */ { getPoint2d_p(l1, t, &theP); thevalue = theP.y-(k*theP.x); list1[t].themeasure=thevalue; list1[t].pnr=t; } for (t=0; t<n2; t++) /*for each segment in L2*/ { getPoint2d_p(l2, t, &theP); thevalue = theP.y-(k*theP.x); list2[t].themeasure=thevalue; list2[t].pnr=t; } c1m = c1.y-(k*c1.x); c2m = c2.y-(k*c2.x); } /*if the center-center line is horizontal the perpendicular line will be vertical. To eliminate problems with deviding by zero we are here mirroring the coordinate-system and we find it's crossing the X-axes with z = x-(1/k)y */ else /*West or East*/ { k = -deltaY/deltaX; for (t=0; t<n1; t++) /*for each segment in L1 */ { getPoint2d_p(l1, t, &theP); thevalue = theP.x-(k*theP.y); list1[t].themeasure=thevalue; list1[t].pnr=t; /* lwnotice("l1 %d, measure=%f",t,thevalue ); */ } for (t=0; t<n2; t++) /*for each segment in L2*/ { getPoint2d_p(l2, t, &theP); thevalue = theP.x-(k*theP.y); list2[t].themeasure=thevalue; list2[t].pnr=t; /* lwnotice("l2 %d, measure=%f",t,thevalue ); */ } c1m = c1.x-(k*c1.y); c2m = c2.x-(k*c2.y); } /*we sort our lists by the calculated values*/ qsort(list1, n1, sizeof(LISTSTRUCT), struct_cmp_by_measure); qsort(list2, n2, sizeof(LISTSTRUCT), struct_cmp_by_measure); if (c1m < c2m) { if (!lw_dist2d_pre_seg_seg(l1,l2,list1,list2,k,dl)) { lwfree(list1); lwfree(list2); return LW_FALSE; } } else { dl->twisted= ((dl->twisted) * (-1)); if (!lw_dist2d_pre_seg_seg(l2,l1,list2,list1,k,dl)) { lwfree(list1); lwfree(list2); return LW_FALSE; } } lwfree(list1); lwfree(list2); return LW_TRUE; }