/*
 * 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);
}
Esempio n. 4
0
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 */
}
Esempio n. 5
0
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);
}
Esempio n. 6
0
/* 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;
}
Esempio n. 7
0
/* 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));
}
Esempio n. 8
0
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;
    }
}
Esempio n. 10
0
/*
 * 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);
	}
}
Esempio n. 11
0
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;
}
Esempio n. 12
0
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);
}