/* * Construct a polygon from a LWLINE being * the shell and an array of LWLINE (possibly NULL) being holes. * Pointarrays from intput geoms are cloned. * SRID must be the same for each input line. * Input lines must have at least 4 points, and be closed. */ LWPOLY * lwpoly_from_lwlines(const LWLINE *shell, uint32_t nholes, const LWLINE **holes) { uint32_t nrings; POINTARRAY **rings = lwalloc((nholes+1)*sizeof(POINTARRAY *)); int srid = shell->srid; LWPOLY *ret; if ( shell->points->npoints < 4 ) lwerror("lwpoly_from_lwlines: shell must have at least 4 points"); if ( ! ptarray_is_closed_2d(shell->points) ) lwerror("lwpoly_from_lwlines: shell must be closed"); rings[0] = ptarray_clone_deep(shell->points); for (nrings=1; nrings<=nholes; nrings++) { const LWLINE *hole = holes[nrings-1]; if ( hole->srid != srid ) lwerror("lwpoly_from_lwlines: mixed SRIDs in input lines"); if ( hole->points->npoints < 4 ) lwerror("lwpoly_from_lwlines: holes must have at least 4 points"); if ( ! ptarray_is_closed_2d(hole->points) ) lwerror("lwpoly_from_lwlines: holes must be closed"); rings[nrings] = ptarray_clone_deep(hole->points); } ret = lwpoly_construct(srid, NULL, nrings, rings); return ret; }
LWMLINE * lwmcurve_segmentize(LWMCURVE *mcurve, uint32_t perQuad) { LWMLINE *ogeom; LWGEOM *tmp; LWGEOM **lines; int i; LWDEBUGF(2, "lwmcurve_segmentize called, geoms=%d, dim=%d.", mcurve->ngeoms, FLAGS_NDIMS(mcurve->flags)); lines = lwalloc(sizeof(LWGEOM *)*mcurve->ngeoms); for (i = 0; i < mcurve->ngeoms; i++) { tmp = mcurve->geoms[i]; if (tmp->type == CIRCSTRINGTYPE) { lines[i] = (LWGEOM *)lwcircstring_segmentize((LWCIRCSTRING *)tmp, perQuad); } else if (tmp->type == LINETYPE) { lines[i] = (LWGEOM *)lwline_construct(mcurve->srid, NULL, ptarray_clone_deep(((LWLINE *)tmp)->points)); } else { lwerror("Unsupported geometry found in MultiCurve."); return NULL; } } ogeom = (LWMLINE *)lwcollection_construct(MULTILINETYPE, mcurve->srid, NULL, mcurve->ngeoms, lines); return ogeom; }
LWMPOLY * lwmsurface_segmentize(LWMSURFACE *msurface, uint32_t perQuad) { LWMPOLY *ogeom; LWGEOM *tmp; LWPOLY *poly; LWGEOM **polys; POINTARRAY **ptarray; int i, j; LWDEBUG(2, "lwmsurface_segmentize called."); polys = lwalloc(sizeof(LWGEOM *)*msurface->ngeoms); for (i = 0; i < msurface->ngeoms; i++) { tmp = msurface->geoms[i]; if (tmp->type == CURVEPOLYTYPE) { polys[i] = (LWGEOM *)lwcurvepoly_segmentize((LWCURVEPOLY *)tmp, perQuad); } else if (tmp->type == POLYGONTYPE) { poly = (LWPOLY *)tmp; ptarray = lwalloc(sizeof(POINTARRAY *)*poly->nrings); for (j = 0; j < poly->nrings; j++) { ptarray[j] = ptarray_clone_deep(poly->rings[j]); } polys[i] = (LWGEOM *)lwpoly_construct(msurface->srid, NULL, poly->nrings, ptarray); } } ogeom = (LWMPOLY *)lwcollection_construct(MULTIPOLYGONTYPE, msurface->srid, NULL, msurface->ngeoms, polys); return ogeom; }
/* * @param icompound input curve polygon * @param tol tolerance, semantic driven by tolerance_type * @param tolerance_type see LW_LINEARIZE_TOLERANCE_TYPE * @param flags see flags in lwarc_linearize * * @return a newly allocated LWPOLY */ static LWPOLY * lwcurvepoly_linearize(const LWCURVEPOLY *curvepoly, double tol, LW_LINEARIZE_TOLERANCE_TYPE tolerance_type, int flags) { LWPOLY *ogeom; LWGEOM *tmp; LWLINE *line; POINTARRAY **ptarray; int i; LWDEBUG(2, "lwcurvepoly_linearize called."); ptarray = lwalloc(sizeof(POINTARRAY *)*curvepoly->nrings); for (i = 0; i < curvepoly->nrings; i++) { tmp = curvepoly->rings[i]; if (tmp->type == CIRCSTRINGTYPE) { line = lwcircstring_linearize((LWCIRCSTRING *)tmp, tol, tolerance_type, flags); ptarray[i] = ptarray_clone_deep(line->points); lwline_free(line); } else if (tmp->type == LINETYPE) { line = (LWLINE *)tmp; ptarray[i] = ptarray_clone_deep(line->points); } else if (tmp->type == COMPOUNDTYPE) { line = lwcompound_linearize((LWCOMPOUND *)tmp, tol, tolerance_type, flags); ptarray[i] = ptarray_clone_deep(line->points); lwline_free(line); } else { lwerror("Invalid ring type found in CurvePoly."); return NULL; } } ogeom = lwpoly_construct(curvepoly->srid, NULL, curvepoly->nrings, ptarray); return ogeom; }
LWPOLY * lwcurvepoly_segmentize(const LWCURVEPOLY *curvepoly, uint32_t perQuad) { LWPOLY *ogeom; LWGEOM *tmp; LWLINE *line; POINTARRAY **ptarray; int i; LWDEBUG(2, "lwcurvepoly_segmentize called."); ptarray = lwalloc(sizeof(POINTARRAY *)*curvepoly->nrings); for (i = 0; i < curvepoly->nrings; i++) { tmp = curvepoly->rings[i]; if (tmp->type == CIRCSTRINGTYPE) { line = lwcircstring_segmentize((LWCIRCSTRING *)tmp, perQuad); ptarray[i] = ptarray_clone_deep(line->points); lwfree(line); } else if (tmp->type == LINETYPE) { line = (LWLINE *)tmp; ptarray[i] = ptarray_clone_deep(line->points); } else if (tmp->type == COMPOUNDTYPE) { line = lwcompound_segmentize((LWCOMPOUND *)tmp, perQuad); ptarray[i] = ptarray_clone_deep(line->points); lwfree(line); } else { lwerror("Invalid ring type found in CurvePoly."); return NULL; } } ogeom = lwpoly_construct(curvepoly->srid, NULL, curvepoly->nrings, ptarray); return ogeom; }
/* Deep clone LWPOLY object. POINTARRAY are copied, as is ring array */ LWPOLY * lwpoly_clone_deep(const LWPOLY *g) { int i; LWPOLY *ret = lwalloc(sizeof(LWPOLY)); memcpy(ret, g, sizeof(LWPOLY)); if ( g->bbox ) ret->bbox = gbox_copy(g->bbox); ret->rings = lwalloc(sizeof(POINTARRAY *)*g->nrings); for ( i = 0; i < ret->nrings; i++ ) { ret->rings[i] = ptarray_clone_deep(g->rings[i]); } FLAGS_SET_READONLY(ret->flags,0); return ret; }
/* * Returns a POINTARRAY with consecutive equal points * removed. Equality test on all dimensions of input. * * Always returns a newly allocated object. * */ POINTARRAY * ptarray_remove_repeated_points(POINTARRAY *in) { POINTARRAY* out; size_t ptsize; size_t ipn, opn; LWDEBUG(3, "ptarray_remove_repeated_points called."); /* Single or zero point arrays can't have duplicates */ if ( in->npoints < 3 ) return ptarray_clone_deep(in); ptsize = ptarray_point_size(in); LWDEBUGF(3, "ptsize: %d", ptsize); /* Allocate enough space for all points */ out = ptarray_construct(FLAGS_GET_Z(in->flags), FLAGS_GET_M(in->flags), in->npoints); /* Now fill up the actual points (NOTE: could be optimized) */ opn=1; memcpy(getPoint_internal(out, 0), getPoint_internal(in, 0), ptsize); LWDEBUGF(3, " first point copied, out points: %d", opn); for (ipn=1; ipn<in->npoints; ++ipn) { if ( (ipn==in->npoints-1 && opn==1) || memcmp(getPoint_internal(in, ipn-1), getPoint_internal(in, ipn), ptsize) ) { /* The point is different from the previous, * we add it to output */ memcpy(getPoint_internal(out, opn++), getPoint_internal(in, ipn), ptsize); LWDEBUGF(3, " Point %d differs from point %d. Out points: %d", ipn, ipn-1, opn); } } LWDEBUGF(3, " in:%d out:%d", out->npoints, opn); out->npoints = opn; return out; }
/* * Construct a triangle from a LWLINE being * the shell * Pointarray from intput geom are cloned. * Input line must have 4 points, and be closed. */ LWTRIANGLE * lwtriangle_from_lwline(const LWLINE *shell) { LWTRIANGLE *ret; POINTARRAY *pa; if ( shell->points->npoints != 4 ) lwerror("lwtriangle_from_lwline: shell must have exactly 4 points"); if ( (!FLAGS_GET_Z(shell->flags) && !ptarray_is_closed_2d(shell->points)) || (FLAGS_GET_Z(shell->flags) && !ptarray_is_closed_3d(shell->points)) ) lwerror("lwtriangle_from_lwline: shell must be closed"); pa = ptarray_clone_deep(shell->points); ret = lwtriangle_construct(shell->srid, NULL, pa); if (lwtriangle_is_repeated_points(ret)) lwerror("lwtriangle_from_lwline: some points are repeated in triangle"); return ret; }
/** * @param mcurve input compound curve * @param tol tolerance, semantic driven by tolerance_type * @param tolerance_type see LW_LINEARIZE_TOLERANCE_TYPE * @param flags see flags in lwarc_linearize * * @return a newly allocated LWMLINE */ static LWMLINE * lwmcurve_linearize(const LWMCURVE *mcurve, double tol, LW_LINEARIZE_TOLERANCE_TYPE type, int flags) { LWMLINE *ogeom; LWGEOM **lines; int i; LWDEBUGF(2, "lwmcurve_linearize called, geoms=%d, dim=%d.", mcurve->ngeoms, FLAGS_NDIMS(mcurve->flags)); lines = lwalloc(sizeof(LWGEOM *)*mcurve->ngeoms); for (i = 0; i < mcurve->ngeoms; i++) { const LWGEOM *tmp = mcurve->geoms[i]; if (tmp->type == CIRCSTRINGTYPE) { lines[i] = (LWGEOM *)lwcircstring_linearize((LWCIRCSTRING *)tmp, tol, type, flags); } else if (tmp->type == LINETYPE) { lines[i] = (LWGEOM *)lwline_construct(mcurve->srid, NULL, ptarray_clone_deep(((LWLINE *)tmp)->points)); } else if (tmp->type == COMPOUNDTYPE) { lines[i] = (LWGEOM *)lwcompound_linearize((LWCOMPOUND *)tmp, tol, type, flags); } else { lwerror("Unsupported geometry found in MultiCurve."); return NULL; } } ogeom = (LWMLINE *)lwcollection_construct(MULTILINETYPE, mcurve->srid, NULL, mcurve->ngeoms, lines); return ogeom; }
/** * @param msurface input multi surface * @param tol tolerance, semantic driven by tolerance_type * @param tolerance_type see LW_LINEARIZE_TOLERANCE_TYPE * @param flags see flags in lwarc_linearize * * @return a newly allocated LWMPOLY */ static LWMPOLY * lwmsurface_linearize(const LWMSURFACE *msurface, double tol, LW_LINEARIZE_TOLERANCE_TYPE type, int flags) { LWMPOLY *ogeom; LWGEOM *tmp; LWPOLY *poly; LWGEOM **polys; POINTARRAY **ptarray; int i, j; LWDEBUG(2, "lwmsurface_linearize called."); polys = lwalloc(sizeof(LWGEOM *)*msurface->ngeoms); for (i = 0; i < msurface->ngeoms; i++) { tmp = msurface->geoms[i]; if (tmp->type == CURVEPOLYTYPE) { polys[i] = (LWGEOM *)lwcurvepoly_linearize((LWCURVEPOLY *)tmp, tol, type, flags); } else if (tmp->type == POLYGONTYPE) { poly = (LWPOLY *)tmp; ptarray = lwalloc(sizeof(POINTARRAY *)*poly->nrings); for (j = 0; j < poly->nrings; j++) { ptarray[j] = ptarray_clone_deep(poly->rings[j]); } polys[i] = (LWGEOM *)lwpoly_construct(msurface->srid, NULL, poly->nrings, ptarray); } } ogeom = (LWMPOLY *)lwcollection_construct(MULTIPOLYGONTYPE, msurface->srid, NULL, msurface->ngeoms, polys); return ogeom; }
/** * Parse kml:coordinates */ static POINTARRAY* parse_kml_coordinates(xmlNodePtr xnode, bool *hasz) { xmlChar *kml_coord; bool digit, found; POINTARRAY *dpa; int kml_dims; char *p, *q; POINT4D pt; if (xnode == NULL) lwerror("invalid KML representation"); for (found = false ; xnode != NULL ; xnode = xnode->next) { if (xnode->type != XML_ELEMENT_NODE) continue; if (!is_kml_namespace(xnode, false)) continue; if (strcmp((char *) xnode->name, "coordinates")) continue; found = true; break; } if (!found) lwerror("invalid KML representation"); /* We begin to retrieve coordinates string */ kml_coord = xmlNodeGetContent(xnode); p = (char *) kml_coord; /* KML coordinates pattern: x1,y1 x2,y2 * x1,y1,z1 x2,y2,z2 */ /* Now we create PointArray from coordinates values */ /* HasZ, !HasM, 1pt */ dpa = ptarray_construct_empty(1, 0, 1); for (q = p, kml_dims=0, digit = false ; *p ; p++) { if (isdigit(*p)) digit = true; /* One state parser */ /* Coordinate Separator */ if (*p == ',') { *p = '\0'; kml_dims++; if (*(p+1) == '\0') lwerror("invalid KML representation"); if (kml_dims == 1) pt.x = parse_kml_double(q, true, true); else if (kml_dims == 2) pt.y = parse_kml_double(q, true, true); q = p+1; /* Tuple Separator (or end string) */ } else if (digit && (isspace(*p) || *(p+1) == '\0')) { if (isspace(*p)) *p = '\0'; kml_dims++; if (kml_dims < 2 || kml_dims > 3) lwerror("invalid KML representation"); if (kml_dims == 3) pt.z = parse_kml_double(q, true, true); else { pt.y = parse_kml_double(q, true, true); *hasz = false; } ptarray_append_point(dpa, &pt, LW_FALSE); digit = false; q = p+1; kml_dims = 0; } } xmlFree(kml_coord); /* TODO: we shouldn't need to clone here */ return ptarray_clone_deep(dpa); }
/* * Returns a POINTARRAY with consecutive equal points * removed. Equality test on all dimensions of input. * * Always returns a newly allocated object. * */ POINTARRAY * ptarray_remove_repeated_points_minpoints(const POINTARRAY *in, double tolerance, int minpoints) { POINTARRAY* out; size_t ptsize; size_t ipn, opn; const POINT2D *last_point, *this_point; double tolsq = tolerance * tolerance; if ( minpoints < 1 ) minpoints = 1; LWDEBUGF(3, "%s called", __func__); /* Single or zero point arrays can't have duplicates */ if ( in->npoints < 3 ) return ptarray_clone_deep(in); ptsize = ptarray_point_size(in); LWDEBUGF(3, " ptsize: %d", ptsize); /* Allocate enough space for all points */ out = ptarray_construct(FLAGS_GET_Z(in->flags), FLAGS_GET_M(in->flags), in->npoints); /* Now fill up the actual points (NOTE: could be optimized) */ opn=1; /* Keep the first point */ memcpy(getPoint_internal(out, 0), getPoint_internal(in, 0), ptsize); last_point = getPoint2d_cp(in, 0); LWDEBUGF(3, " first point copied, out points: %d", opn); for ( ipn = 1; ipn < in->npoints; ++ipn) { this_point = getPoint2d_cp(in, ipn); if ( ipn < in->npoints-minpoints+1 || opn >= minpoints ) /* need extra points to hit minponts */ { if ( (tolerance == 0 && memcmp(getPoint_internal(in, ipn-1), getPoint_internal(in, ipn), ptsize) == 0) || /* exact dupe */ (tolerance > 0.0 && distance2d_sqr_pt_pt(last_point, this_point) <= tolsq) /* within the removal tolerance */ ) continue; } /* * The point is different (see above) from the previous, * so we add it to output */ memcpy(getPoint_internal(out, opn++), getPoint_internal(in, ipn), ptsize); last_point = this_point; LWDEBUGF(3, " Point %d differs from point %d. Out points: %d", ipn, ipn-1, opn); } /* Keep the last point */ if ( memcmp(last_point, getPoint_internal(in, ipn-1), ptsize) != 0 ) { memcpy(getPoint_internal(out, opn-1), getPoint_internal(in, ipn-1), ptsize); } LWDEBUGF(3, " in:%d out:%d", out->npoints, opn); out->npoints = opn; return out; }
/* * 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; }