/* * Return a fully allocated LWGEOM containing elements * intersected/interpolated with the given M range. * Return NULL if none of the elements fall in the range. * * m0 is assumed to be less-or-equal to m1. * input LWGEOM is assumed to contain an M value. * */ static LWGEOM * lwgeom_locate_between_m(LWGEOM *lwin, double m0, double m1) { POSTGIS_DEBUGF(2, "lwgeom_locate_between called for lwgeom %p", lwin); switch (lwin->type) { case POINTTYPE: return lwpoint_locate_between_m( (LWPOINT *)lwin, m0, m1); case LINETYPE: return lwline_locate_between_m( (LWLINE *)lwin, m0, m1); case MULTIPOINTTYPE: case MULTILINETYPE: case COLLECTIONTYPE: return lwcollection_locate_between_m( (LWCOLLECTION *)lwin, m0, m1); /* Polygon types are not supported */ case POLYGONTYPE: case MULTIPOLYGONTYPE: lwpgerror("Areal geometries are not supported by locate_between_measures"); return NULL; } lwpgerror("Unkonwn geometry type (%s:%d)", __FILE__, __LINE__); return NULL; }
Datum LWGEOM_locate_between_m(PG_FUNCTION_ARGS) { GSERIALIZED *gin = PG_GETARG_GSERIALIZED_P(0); GSERIALIZED *gout; double start_measure = PG_GETARG_FLOAT8(1); double end_measure = PG_GETARG_FLOAT8(2); LWGEOM *lwin, *lwout; int hasz = gserialized_has_z(gin); int hasm = gserialized_has_m(gin); int type; elog(WARNING,"ST_Locate_Between_Measures and ST_Locate_Along_Measure were deprecated in 2.2.0. Please use ST_LocateAlong and ST_LocateBetween"); if ( end_measure < start_measure ) { lwpgerror("locate_between_m: 2nd arg must be bigger then 1st arg"); PG_RETURN_NULL(); } /* * Return error if input doesn't have a measure */ if ( ! hasm ) { lwpgerror("Geometry argument does not have an 'M' ordinate"); PG_RETURN_NULL(); } /* * Raise an error if input is a polygon, a multipolygon * or a collection */ type = gserialized_get_type(gin); if ( type == POLYGONTYPE || type == MULTIPOLYGONTYPE || type == COLLECTIONTYPE ) { lwpgerror("Areal or Collection types are not supported"); PG_RETURN_NULL(); } lwin = lwgeom_from_gserialized(gin); lwout = lwgeom_locate_between_m(lwin, start_measure, end_measure); lwgeom_free(lwin); if ( lwout == NULL ) { lwout = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, gserialized_get_srid(gin), hasz, hasm); } gout = geometry_serialize(lwout); lwgeom_free(lwout); PG_RETURN_POINTER(gout); }
Datum ST_AddMeasure(PG_FUNCTION_ARGS) { GSERIALIZED *gin = PG_GETARG_GSERIALIZED_P(0); GSERIALIZED *gout; double start_measure = PG_GETARG_FLOAT8(1); double end_measure = PG_GETARG_FLOAT8(2); LWGEOM *lwin, *lwout; int type = gserialized_get_type(gin); /* Raise an error if input is not a linestring or multilinestring */ if ( type != LINETYPE && type != MULTILINETYPE ) { lwpgerror("Only LINESTRING and MULTILINESTRING are supported"); PG_RETURN_NULL(); } lwin = lwgeom_from_gserialized(gin); if ( type == LINETYPE ) lwout = (LWGEOM*)lwline_measured_from_lwline((LWLINE*)lwin, start_measure, end_measure); else lwout = (LWGEOM*)lwmline_measured_from_lwmline((LWMLINE*)lwin, start_measure, end_measure); lwgeom_free(lwin); if ( lwout == NULL ) PG_RETURN_NULL(); gout = geometry_serialize(lwout); lwgeom_free(lwout); PG_RETURN_POINTER(gout); }
Datum sfcgal_approximate_medial_axis(PG_FUNCTION_ARGS) { #if POSTGIS_SFCGAL_VERSION < 12 lwpgerror("The SFCGAL version this PostGIS binary " "was compiled against (%d) doesn't support " "'sfcgal_geometry_approximate_medial_axis' function (1.2.0+ required)", POSTGIS_SFCGAL_VERSION); PG_RETURN_NULL(); #else /* POSTGIS_SFCGAL_VERSION >= 12 */ GSERIALIZED *input, *output; sfcgal_geometry_t *geom; sfcgal_geometry_t *result; srid_t srid; sfcgal_postgis_init(); input = PG_GETARG_GSERIALIZED_P(0); srid = gserialized_get_srid(input); geom = POSTGIS2SFCGALGeometry(input); PG_FREE_IF_COPY(input, 0); result = sfcgal_geometry_approximate_medial_axis(geom); sfcgal_geometry_delete(geom); output = SFCGALGeometry2POSTGIS(result, 0, srid); sfcgal_geometry_delete(result); PG_RETURN_POINTER(output); #endif /* POSTGIS_SFCGAL_VERSION >= 12 */ }
Datum LWGEOM_m_point(PG_FUNCTION_ARGS) { GSERIALIZED *geom; LWPOINT *point = NULL; LWGEOM *lwgeom; POINT3DM p; geom = PG_GETARG_GSERIALIZED_P(0); if ( gserialized_get_type(geom) != POINTTYPE ) lwpgerror("Argument to ST_M() must be a point"); lwgeom = lwgeom_from_gserialized(geom); point = lwgeom_as_lwpoint(lwgeom); if ( lwgeom_is_empty(lwgeom) ) PG_RETURN_NULL(); /* no M in input */ if ( ! FLAGS_GET_M(point->flags) ) PG_RETURN_NULL(); getPoint3dm_p(point->point, 0, &p); PG_FREE_IF_COPY(geom, 0); PG_RETURN_FLOAT8(p.m); }
/* Conversion from GSERIALIZED* to SFCGAL::Geometry */ sfcgal_geometry_t* POSTGIS2SFCGALGeometry(GSERIALIZED *pglwgeom) { sfcgal_geometry_t* g; LWGEOM *lwgeom = lwgeom_from_gserialized(pglwgeom); if (! lwgeom) { lwpgerror("POSTGIS2SFCGALGeometry: Unable to deserialize input"); } g = LWGEOM2SFCGAL(lwgeom); lwgeom_free(lwgeom); return g; }
/* Conversion from GSERIALIZED* to SFCGAL::PreparedGeometry */ sfcgal_prepared_geometry_t* POSTGIS2SFCGALPreparedGeometry(GSERIALIZED *pglwgeom) { sfcgal_geometry_t* g; LWGEOM *lwgeom = lwgeom_from_gserialized(pglwgeom); if (!lwgeom) { lwpgerror("POSTGIS2SFCGALPreparedGeometry: Unable to deserialize input"); } g = LWGEOM2SFCGAL(lwgeom); lwgeom_free(lwgeom); return sfcgal_prepared_geometry_create_from_geometry(g, gserialized_get_srid(pglwgeom)); }
Datum LWGEOM_x_point(PG_FUNCTION_ARGS) { GSERIALIZED *geom; LWGEOM *lwgeom; LWPOINT *point = NULL; POINT2D p; geom = PG_GETARG_GSERIALIZED_P(0); if ( gserialized_get_type(geom) != POINTTYPE ) lwpgerror("Argument to ST_X() must be a point"); lwgeom = lwgeom_from_gserialized(geom); point = lwgeom_as_lwpoint(lwgeom); if ( lwgeom_is_empty(lwgeom) ) PG_RETURN_NULL(); getPoint2d_p(point->point, 0, &p); PG_FREE_IF_COPY(geom, 0); PG_RETURN_FLOAT8(p.x); }
static int geography_distance_cache_tolerance(FunctionCallInfoData* fcinfo, const GSERIALIZED* g1, const GSERIALIZED* g2, const SPHEROID* s, double tolerance, double* distance) { CircTreeGeomCache* tree_cache = NULL; int type1 = gserialized_get_type(g1); int type2 = gserialized_get_type(g2); Assert(distance); /* Two points? Get outa here... */ if ( type1 == POINTTYPE && type2 == POINTTYPE ) return LW_FAILURE; /* Fetch/build our cache, if appropriate, etc... */ tree_cache = GetCircTreeGeomCache(fcinfo, g1, g2); /* OK, we have an index at the ready! Use it for the one tree argument and */ /* fill in the other tree argument */ if ( tree_cache && tree_cache->argnum && tree_cache->index ) { CIRC_NODE* circtree_cached = tree_cache->index; CIRC_NODE* circtree = NULL; const GSERIALIZED* g_cached; const GSERIALIZED* g; LWGEOM* lwgeom = NULL; int geomtype_cached; int geomtype; POINT4D p4d; /* We need to dynamically build a tree for the uncached side of the function call */ if ( tree_cache->argnum == 1 ) { g_cached = g1; g = g2; geomtype_cached = type1; geomtype = type2; } else if ( tree_cache->argnum == 2 ) { g_cached = g2; g = g1; geomtype_cached = type2; geomtype = type1; } else { lwpgerror("geography_distance_cache this cannot happen!"); return LW_FAILURE; } lwgeom = lwgeom_from_gserialized(g); if ( geomtype_cached == POLYGONTYPE || geomtype_cached == MULTIPOLYGONTYPE ) { lwgeom_startpoint(lwgeom, &p4d); if ( CircTreePIP(circtree_cached, g_cached, &p4d) ) { *distance = 0.0; lwgeom_free(lwgeom); return LW_SUCCESS; } } circtree = lwgeom_calculate_circ_tree(lwgeom); if ( geomtype == POLYGONTYPE || geomtype == MULTIPOLYGONTYPE ) { POINT2D p2d; circ_tree_get_point(circtree_cached, &p2d); p4d.x = p2d.x; p4d.y = p2d.y; if ( CircTreePIP(circtree, g, &p4d) ) { *distance = 0.0; circ_tree_free(circtree); lwgeom_free(lwgeom); return LW_SUCCESS; } } *distance = circ_tree_distance_tree(circtree_cached, circtree, s, tolerance); circ_tree_free(circtree); lwgeom_free(lwgeom); return LW_SUCCESS; } else { return LW_FAILURE; } }
/* * Line is assumed to have an M value. * * Return NULL if no parts of the line are in the given range (inclusive) * * Return an LWCOLLECTION with LWLINES and LWPOINT being consecutive * and isolated points on the line falling in the range. * * X,Y and Z (if present) ordinates are interpolated. * */ static LWGEOM * lwline_locate_between_m(LWLINE *lwline_in, double m0, double m1) { POINTARRAY *ipa=lwline_in->points; int i; LWGEOM **geoms; int ngeoms; int outtype; int typeflag=0; /* see flags below */ const int pointflag=0x01; const int lineflag=0x10; POINTARRAYSET paset=ptarray_locate_between_m(ipa, m0, m1); POSTGIS_DEBUGF(2, "lwline_locate_between called for lwline %p", lwline_in); POSTGIS_DEBUGF(3, " ptarray_locate... returned %d pointarrays", paset.nptarrays); if ( paset.nptarrays == 0 ) { return NULL; } ngeoms=paset.nptarrays; /* TODO: rework this to reduce used memory */ geoms=lwalloc(sizeof(LWGEOM *)*ngeoms); for (i=0; i<ngeoms; i++) { LWPOINT *lwpoint; LWLINE *lwline; POINTARRAY *pa=paset.ptarrays[i]; /* This is a point */ if ( pa->npoints == 1 ) { lwpoint = lwpoint_construct(lwline_in->srid, NULL, pa); geoms[i]=(LWGEOM *)lwpoint; typeflag|=pointflag; } /* This is a line */ else if ( pa->npoints > 1 ) { lwline = lwline_construct(lwline_in->srid, NULL, pa); geoms[i]=(LWGEOM *)lwline; typeflag|=lineflag; } /* This is a bug */ else { lwpgerror("ptarray_locate_between_m returned a POINARRAY set containing POINTARRAY with 0 points"); } } if ( ngeoms == 1 ) { return geoms[0]; } else { /* Choose best type */ if ( typeflag == 1 ) outtype=MULTIPOINTTYPE; else if ( typeflag == 2 ) outtype=MULTILINETYPE; else outtype = COLLECTIONTYPE; return (LWGEOM *)lwcollection_construct(outtype, lwline_in->srid, NULL, ngeoms, geoms); } }
static POINTARRAYSET ptarray_locate_between_m(POINTARRAY *ipa, double m0, double m1) { POINTARRAYSET ret; POINTARRAY *dpa=NULL; int i; ret.nptarrays=0; /* * We allocate space for as many pointarray as * segments in the input POINTARRAY, as worst * case is for each segment to cross the M range * window. * TODO: rework this to reduce used memory */ ret.ptarrays=lwalloc(sizeof(POINTARRAY *)*ipa->npoints-1); POSTGIS_DEBUGF(2, "ptarray_locate...: called for pointarray %p, m0:%g, m1:%g", ipa, m0, m1); for (i=1; i<ipa->npoints; i++) { POINT4D p1, p2; int clipval; getPoint4d_p(ipa, i-1, &p1); getPoint4d_p(ipa, i, &p2); POSTGIS_DEBUGF(3, " segment %d-%d [ %g %g %g %g - %g %g %g %g ]", i-1, i, p1.x, p1.y, p1.z, p1.m, p2.x, p2.y, p2.z, p2.m); clipval = clip_seg_by_m_range(&p1, &p2, m0, m1); /* segment completely outside, nothing to do */ if (! clipval ) continue; POSTGIS_DEBUGF(3, " clipped to: [ %g %g %g %g - %g %g %g %g ] clipval: %d", p1.x, p1.y, p1.z, p1.m, p2.x, p2.y, p2.z, p2.m, clipval); /* If no points have been accumulated so far, then if clipval != 0 the first point must be the start of the intersection */ if (dpa == NULL) { POSTGIS_DEBUGF(3, " 1 creating new POINTARRAY with first point %g,%g,%g,%g", p1.x, p1.y, p1.z, p1.m); dpa = ptarray_construct_empty(FLAGS_GET_Z(ipa->flags), FLAGS_GET_M(ipa->flags), ipa->npoints-i); ptarray_append_point(dpa, &p1, LW_TRUE); } /* Otherwise always add the next point, avoiding duplicates */ if (dpa) ptarray_append_point(dpa, &p2, LW_FALSE); /* * second point has been clipped */ if ( clipval & 0x0100 || i == ipa->npoints-1 ) { POSTGIS_DEBUGF(3, " closing pointarray %p with %d points", dpa, dpa->npoints); ret.ptarrays[ret.nptarrays++] = dpa; dpa = NULL; } } /* * if dpa!=NULL it means we didn't close it yet. * this should never happen. */ if ( dpa != NULL ) lwpgerror("Something wrong with algorithm"); return ret; }
static void geohash_lwpgerror(char *msg, int error_code) { POSTGIS_DEBUGF(3, "ST_Box2dFromGeoHash ERROR %i", error_code); lwpgerror("%s", msg); }
Datum LWGEOM_snaptogrid_pointoff(PG_FUNCTION_ARGS) { GSERIALIZED *in_geom, *in_point; LWGEOM *in_lwgeom; LWPOINT *in_lwpoint; GSERIALIZED *out_geom = NULL; LWGEOM *out_lwgeom; gridspec grid; /* BOX3D box3d; */ POINT4D offsetpoint; in_geom = PG_GETARG_GSERIALIZED_P(0); /* Return input geometry if input geometry is empty */ if ( gserialized_is_empty(in_geom) ) { PG_RETURN_POINTER(in_geom); } in_point = PG_GETARG_GSERIALIZED_P(1); in_lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(in_point)); if ( in_lwpoint == NULL ) { lwpgerror("Offset geometry must be a point"); } grid.xsize = PG_GETARG_FLOAT8(2); grid.ysize = PG_GETARG_FLOAT8(3); grid.zsize = PG_GETARG_FLOAT8(4); grid.msize = PG_GETARG_FLOAT8(5); /* Take offsets from point geometry */ getPoint4d_p(in_lwpoint->point, 0, &offsetpoint); grid.ipx = offsetpoint.x; grid.ipy = offsetpoint.y; if (FLAGS_GET_Z(in_lwpoint->flags) ) grid.ipz = offsetpoint.z; else grid.ipz=0; if (FLAGS_GET_M(in_lwpoint->flags) ) grid.ipm = offsetpoint.m; else grid.ipm=0; #if POSTGIS_DEBUG_LEVEL >= 4 grid_print(&grid); #endif /* Return input geometry if input grid is meaningless */ if ( grid.xsize==0 && grid.ysize==0 && grid.zsize==0 && grid.msize==0 ) { PG_RETURN_POINTER(in_geom); } in_lwgeom = lwgeom_from_gserialized(in_geom); POSTGIS_DEBUGF(3, "SnapToGrid got a %s", lwtype_name(in_lwgeom->type)); out_lwgeom = lwgeom_grid(in_lwgeom, &grid); if ( out_lwgeom == NULL ) PG_RETURN_NULL(); /* COMPUTE_BBOX TAINTING */ if ( in_lwgeom->bbox ) lwgeom_add_bbox(out_lwgeom); POSTGIS_DEBUGF(3, "SnapToGrid made a %s", lwtype_name(out_lwgeom->type)); out_geom = geometry_serialize(out_lwgeom); PG_RETURN_POINTER(out_geom); }