예제 #1
0
/**
* COLLECTION, MULTIPOINTTYPE, MULTILINETYPE, MULTIPOLYGONTYPE
**/
static LWCOLLECTION* lwcollection_from_twkb_state(twkb_parse_state *s)
{
	int ngeoms, i;
	LWGEOM *geom = NULL;
	LWCOLLECTION *col = lwcollection_construct_empty(s->lwtype, SRID_UNKNOWN, s->has_z, s->has_m);

	LWDEBUG(2,"Entering lwcollection_from_twkb_state");

	if ( s->is_empty )
		return col;

	/* Read number of geometries */
	ngeoms = twkb_parse_state_uvarint(s);

	LWDEBUGF(4,"Number of geometries %d",ngeoms);

	/* It has an idlist, we need to skip that */
	if ( s->has_idlist )
	{
		for ( i = 0; i < ngeoms; i++ )
			twkb_parse_state_varint_skip(s);
	}

	for ( i = 0; i < ngeoms; i++ )
	{
		geom = lwgeom_from_twkb_state(s);
		if ( lwcollection_add_lwgeom(col, geom) == NULL )
		{
			lwerror("Unable to add geometry (%p) to collection (%p)", geom, col);
			return NULL;
		}
	}


	return col;
}
예제 #2
0
/**

Here the geometries are distributed for the new faster distance-calculations
*/
int
lw_dist2d_distribute_fast(LWGEOM *lwg1, LWGEOM *lwg2, DISTPTS *dl)
{
	POINTARRAY *pa1, *pa2;
	int	type1 = lwg1->type;
	int	type2 = lwg2->type;

	LWDEBUGF(2, "lw_dist2d_distribute_fast is called with typ1=%d, type2=%d", lwg1->type, lwg2->type);

	switch (type1)
	{
	case LINETYPE:
		pa1 = ((LWLINE *)lwg1)->points;
		break;
	case POLYGONTYPE:
		pa1 = ((LWPOLY *)lwg1)->rings[0];
		break;
	default:
		lwerror("Unsupported geometry1 type: %s", lwtype_name(type1));
		return LW_FALSE;
	}
	switch (type2)
	{
	case LINETYPE:
		pa2 = ((LWLINE *)lwg2)->points;
		break;
	case POLYGONTYPE:
		pa2 = ((LWPOLY *)lwg2)->rings[0];
		break;
	default:
		lwerror("Unsupported geometry2 type: %s", lwtype_name(type1));
		return LW_FALSE;
	}
	dl->twisted=1;
	return lw_dist2d_fast_ptarray_ptarray(pa1, pa2, dl, lwg1->bbox, lwg2->bbox);
}
예제 #3
0
static int lwgeom_to_twkb_buf(const LWGEOM *geom, TWKB_GLOBALS *globals, TWKB_STATE *ts)
{
	LWDEBUGF(2, "Entered %s", __func__);

	switch ( geom->type )
	{
		case POINTTYPE:
		{
			LWDEBUGF(4,"Type found is Point, %d", geom->type);
			return lwpoint_to_twkb_buf((LWPOINT*) geom, globals, ts);
		}
		case LINETYPE:
		{
			LWDEBUGF(4,"Type found is Linestring, %d", geom->type);
			return lwline_to_twkb_buf((LWLINE*) geom, globals, ts);
		}
		/* Polygon has 'nrings' and 'rings' elements */
		case POLYGONTYPE:
		{
			LWDEBUGF(4,"Type found is Polygon, %d", geom->type);
			return lwpoly_to_twkb_buf((LWPOLY*)geom, globals, ts);
		}

		/* All these Collection types have 'ngeoms' and 'geoms' elements */
		case MULTIPOINTTYPE:
		case MULTILINETYPE:
		case MULTIPOLYGONTYPE:
		{
			LWDEBUGF(4,"Type found is Multi, %d", geom->type);
			return lwmulti_to_twkb_buf((LWCOLLECTION*)geom, globals, ts);
		}
		case COLLECTIONTYPE:
		{
			LWDEBUGF(4,"Type found is collection, %d", geom->type);
			return lwcollection_to_twkb_buf((LWCOLLECTION*) geom, globals, ts);
		}
		/* Unknown type! */
		default:
			lwerror("Unsupported geometry type: %s [%d]", lwtype_name((geom)->type), (geom)->type);
	}

	return 0;
}
예제 #4
0
파일: ptarray.c 프로젝트: TesseractG/lwgeom
POINTARRAY *
ptarray_substring(POINTARRAY *ipa, double from, double to, double tolerance)
{
	POINTARRAY *dpa;
	POINT4D pt;
	POINT4D p1, p2;
	POINT4D *p1ptr=&p1; /* don't break strict-aliasing rule */
	POINT4D *p2ptr=&p2;
	int nsegs, i;
	double length, slength, tlength;
	int state = 0; /* 0=before, 1=inside */

	/*
	 * Create a dynamic pointarray with an initial capacity
	 * equal to full copy of input points
	 */
	dpa = ptarray_construct_empty(FLAGS_GET_Z(ipa->flags), FLAGS_GET_M(ipa->flags), ipa->npoints);

	/* Compute total line length */
	length = ptarray_length_2d(ipa);


	LWDEBUGF(3, "Total length: %g", length);


	/* Get 'from' and 'to' lengths */
	from = length*from;
	to = length*to;


	LWDEBUGF(3, "From/To: %g/%g", from, to);


	tlength = 0;
	getPoint4d_p(ipa, 0, &p1);
	nsegs = ipa->npoints - 1;
	for ( i = 0; i < nsegs; i++ )
	{
		double dseg;

		getPoint4d_p(ipa, i+1, &p2);


		LWDEBUGF(3 ,"Segment %d: (%g,%g,%g,%g)-(%g,%g,%g,%g)",
		         i, p1.x, p1.y, p1.z, p1.m, p2.x, p2.y, p2.z, p2.m);


		/* Find the length of this segment */
		slength = distance2d_pt_pt((POINT2D *)p1ptr, (POINT2D *)p2ptr);

		/*
		 * We are before requested start.
		 */
		if ( state == 0 ) /* before */
		{

			LWDEBUG(3, " Before start");

			if ( fabs ( from - ( tlength + slength ) ) <= tolerance )
			{

				LWDEBUG(3, "  Second point is our start");

				/*
				 * Second point is our start
				 */
				ptarray_append_point(dpa, &p2, LW_FALSE);
				state=1; /* we're inside now */
				goto END;
			}

			else if ( fabs(from - tlength) <= tolerance )
			{

				LWDEBUG(3, "  First point is our start");

				/*
				 * First point is our start
				 */
				ptarray_append_point(dpa, &p1, LW_FALSE);

				/*
				 * We're inside now, but will check
				 * 'to' point as well
				 */
				state=1;
			}

			/*
			 * Didn't reach the 'from' point,
			 * nothing to do
			 */
			else if ( from > tlength + slength ) goto END;

			else  /* tlength < from < tlength+slength */
			{

				LWDEBUG(3, "  Seg contains first point");

				/*
				 * Our start is between first and
				 * second point
				 */
				dseg = (from - tlength) / slength;

				interpolate_point4d(&p1, &p2, &pt, dseg);

				ptarray_append_point(dpa, &pt, LW_FALSE);

				/*
				 * We're inside now, but will check
				 * 'to' point as well
				 */
				state=1;
			}
		}

		if ( state == 1 ) /* inside */
		{

			LWDEBUG(3, " Inside");

			/*
			 * 'to' point is our second point.
			 */
			if ( fabs(to - ( tlength + slength ) ) <= tolerance )
			{

				LWDEBUG(3, " Second point is our end");

				ptarray_append_point(dpa, &p2, LW_FALSE);
				break; /* substring complete */
			}

			/*
			 * 'to' point is our first point.
			 * (should only happen if 'to' is 0)
			 */
			else if ( fabs(to - tlength) <= tolerance )
			{

				LWDEBUG(3, " First point is our end");

				ptarray_append_point(dpa, &p1, LW_FALSE);

				break; /* substring complete */
			}

			/*
			 * Didn't reach the 'end' point,
			 * just copy second point
			 */
			else if ( to > tlength + slength )
			{
				ptarray_append_point(dpa, &p2, LW_FALSE);
				goto END;
			}

			/*
			 * 'to' point falls on this segment
			 * Interpolate and break.
			 */
			else if ( to < tlength + slength )
			{

				LWDEBUG(3, " Seg contains our end");

				dseg = (to - tlength) / slength;
				interpolate_point4d(&p1, &p2, &pt, dseg);

				ptarray_append_point(dpa, &pt, LW_FALSE);

				break;
			}

			else
			{
				LWDEBUG(3, "Unhandled case");
			}
		}


END:

		tlength += slength;
		memcpy(&p1, &p2, sizeof(POINT4D));
	}

	LWDEBUGF(3, "Out of loop, ptarray has %d points", dpa->npoints);

	return dpa;
}
예제 #5
0
GEOSGeometry *
LWGEOM2GEOS(const LWGEOM *lwgeom)
{
	GEOSCoordSeq sq;
	GEOSGeom g, shell;
	GEOSGeom *geoms = NULL;
	/*
	LWGEOM *tmp;
	*/
	uint32_t ngeoms, i;
	int geostype;
#if LWDEBUG_LEVEL >= 4
	char *wkt;
#endif

	LWDEBUGF(4, "LWGEOM2GEOS got a %s", lwtype_name(lwgeom->type));

	if (lwgeom_has_arc(lwgeom))
	{
		LWDEBUG(3, "LWGEOM2GEOS: arced geometry found.");

		lwerror("Exception in LWGEOM2GEOS: curved geometry not supported.");
		return NULL;
	}
	
	switch (lwgeom->type)
	{
		LWPOINT *lwp = NULL;
		LWPOLY *lwpoly = NULL;
		LWLINE *lwl = NULL;
		LWCOLLECTION *lwc = NULL;
#if POSTGIS_GEOS_VERSION < 33
		POINTARRAY *pa = NULL;
#endif
		
	case POINTTYPE:
		lwp = (LWPOINT *)lwgeom;
		
		if ( lwgeom_is_empty(lwgeom) )
		{
#if POSTGIS_GEOS_VERSION < 33
			pa = ptarray_construct_empty(lwgeom_has_z(lwgeom), lwgeom_has_m(lwgeom), 2);
			sq = ptarray_to_GEOSCoordSeq(pa);
			shell = GEOSGeom_createLinearRing(sq);
			g = GEOSGeom_createPolygon(shell, NULL, 0);
#else
			g = GEOSGeom_createEmptyPolygon();
#endif
		}
		else
		{
			sq = ptarray_to_GEOSCoordSeq(lwp->point);
			g = GEOSGeom_createPoint(sq);
		}
		if ( ! g )
		{
			/* lwnotice("Exception in LWGEOM2GEOS"); */
			return NULL;
		}
		break;
	case LINETYPE:
		lwl = (LWLINE *)lwgeom;
		if ( lwl->points->npoints == 1 ) {
			/* Duplicate point, to make geos-friendly */
			lwl->points = ptarray_addPoint(lwl->points,
		                           getPoint_internal(lwl->points, 0),
		                           FLAGS_NDIMS(lwl->points->flags),
		                           lwl->points->npoints);
		}
		sq = ptarray_to_GEOSCoordSeq(lwl->points);
		g = GEOSGeom_createLineString(sq);
		if ( ! g )
		{
			/* lwnotice("Exception in LWGEOM2GEOS"); */
			return NULL;
		}
		break;

	case POLYGONTYPE:
		lwpoly = (LWPOLY *)lwgeom;
		if ( lwgeom_is_empty(lwgeom) )
		{
#if POSTGIS_GEOS_VERSION < 33
			POINTARRAY *pa = ptarray_construct_empty(lwgeom_has_z(lwgeom), lwgeom_has_m(lwgeom), 2);
			sq = ptarray_to_GEOSCoordSeq(pa);
			shell = GEOSGeom_createLinearRing(sq);
			g = GEOSGeom_createPolygon(shell, NULL, 0);
#else
			g = GEOSGeom_createEmptyPolygon();
#endif
		}
		else
		{
			sq = ptarray_to_GEOSCoordSeq(lwpoly->rings[0]);
			/* TODO: check ring for being closed and fix if not */
			shell = GEOSGeom_createLinearRing(sq);
			if ( ! shell ) return NULL;
			/*lwerror("LWGEOM2GEOS: exception during polygon shell conversion"); */
			ngeoms = lwpoly->nrings-1;
			if ( ngeoms > 0 )
				geoms = malloc(sizeof(GEOSGeom)*ngeoms);

			for (i=1; i<lwpoly->nrings; ++i)
			{
				sq = ptarray_to_GEOSCoordSeq(lwpoly->rings[i]);
				geoms[i-1] = GEOSGeom_createLinearRing(sq);
				if ( ! geoms[i-1] )
				{
					--i;
					while (i) GEOSGeom_destroy(geoms[--i]);
					free(geoms);
					GEOSGeom_destroy(shell);
					return NULL;
				}
				/*lwerror("LWGEOM2GEOS: exception during polygon hole conversion"); */
			}
			g = GEOSGeom_createPolygon(shell, geoms, ngeoms);
			if (geoms) free(geoms);
		}
		if ( ! g ) return NULL;
		break;
	case MULTIPOINTTYPE:
	case MULTILINETYPE:
	case MULTIPOLYGONTYPE:
	case COLLECTIONTYPE:
		if ( lwgeom->type == MULTIPOINTTYPE )
			geostype = GEOS_MULTIPOINT;
		else if ( lwgeom->type == MULTILINETYPE )
			geostype = GEOS_MULTILINESTRING;
		else if ( lwgeom->type == MULTIPOLYGONTYPE )
			geostype = GEOS_MULTIPOLYGON;
		else
			geostype = GEOS_GEOMETRYCOLLECTION;

		lwc = (LWCOLLECTION *)lwgeom;

		ngeoms = lwc->ngeoms;
		if ( ngeoms > 0 )
			geoms = malloc(sizeof(GEOSGeom)*ngeoms);

		for (i=0; i<ngeoms; ++i)
		{
			GEOSGeometry* g = LWGEOM2GEOS(lwc->geoms[i]);
			if ( ! g )
			{
				while (i) GEOSGeom_destroy(geoms[--i]);
				free(geoms);
				return NULL;
			}
			geoms[i] = g;
		}
		g = GEOSGeom_createCollection(geostype, geoms, ngeoms);
		if ( geoms ) free(geoms);
		if ( ! g ) return NULL;
		break;

	default:
		lwerror("Unknown geometry type: %d - %s", lwgeom->type, lwtype_name(lwgeom->type));
		return NULL;
	}

	GEOSSetSRID(g, lwgeom->srid);

#if LWDEBUG_LEVEL >= 4
	wkt = GEOSGeomToWKT(g);
	LWDEBUGF(4, "LWGEOM2GEOS: GEOSGeom: %s", wkt);
	free(wkt);
#endif

	return g;
}
예제 #6
0
/**
 * Find first linestring in serialized geometry and return
 * the number of points in it. If no linestrings are found
 * return -1.
 */
static int32
lwgeom_numpoints_linestring_recursive(const uchar *serialized)
{
	LWGEOM_INSPECTED *inspected = lwgeom_inspect(serialized);
	int i;

	LWDEBUG(2, "lwgeom_numpoints_linestring_recursive called.");

	/*
	 * CURVEPOLY and COMPOUND have no concept of numpoints but look like
	 * collections once inspected.  Fast-fail on these here.
	 */
	if (lwgeom_getType(inspected->type) == COMPOUNDTYPE ||
	        lwgeom_getType(inspected->type) == CURVEPOLYTYPE)
	{
		return -1;
	}

	for (i=0; i<inspected->ngeometries; i++)
	{
		int32 npoints;
		int type;
		LWGEOM *geom=NULL;
		uchar *subgeom;

		geom = lwgeom_getgeom_inspected(inspected, i);

		LWDEBUGF(3, "numpoints_recursive: type=%d", lwgeom_getType(geom->type));

		if (lwgeom_getType(geom->type) == LINETYPE)
		{
			return ((LWLINE *)geom)->points->npoints;
		}
		else if (lwgeom_getType(geom->type) == CIRCSTRINGTYPE)
		{
			return ((LWCIRCSTRING *)geom)->points->npoints;
		}

		subgeom = lwgeom_getsubgeometry_inspected(inspected, i);
		if ( subgeom == NULL )
		{
			elog(ERROR, "What ? lwgeom_getsubgeometry_inspected returned NULL??");
		}

		type = lwgeom_getType(subgeom[0]);

		/* MULTILINESTRING && GEOMETRYCOLLECTION are worth checking */
		if ( type != MULTILINETYPE && type != COLLECTIONTYPE ) continue;

		npoints = lwgeom_numpoints_linestring_recursive(subgeom);
		if ( npoints == -1 ) continue;

		lwinspected_release(inspected);

		return npoints;
	}

	lwinspected_release(inspected);

	return -1;
}
예제 #7
0
/**
* Force the dimensionality of a geometry to match the dimensionality
* of a set of flags (usually derived from a ZM WKT tag).
*/
static int wkt_parser_set_dims(LWGEOM *geom, uint8_t flags)
{
	int hasz = FLAGS_GET_Z(flags);
	int hasm = FLAGS_GET_M(flags);
	int i = 0;
	
	/* Error on junk */
	if( ! geom ) 
		return LW_FAILURE;

	FLAGS_SET_Z(geom->flags, hasz);
	FLAGS_SET_M(geom->flags, hasm);
		
	if( ! lwgeom_is_empty(geom) )
	{
		if( geom->type == POINTTYPE )
		{
			LWPOINT *pt = (LWPOINT*)geom;
			FLAGS_SET_Z(pt->point->flags, hasz);
			FLAGS_SET_M(pt->point->flags, hasm);
			return LW_SUCCESS;
		}
		else if ( (geom->type == TRIANGLETYPE) || 
		          (geom->type == CIRCSTRINGTYPE) || 
		          (geom->type == LINETYPE) )
		{
			LWLINE *ln = (LWLINE*)geom;
			FLAGS_SET_Z(ln->points->flags, hasz);
			FLAGS_SET_M(ln->points->flags, hasm);
			return LW_SUCCESS;
		}
		else if ( geom->type == POLYGONTYPE )
		{
			LWPOLY *poly = (LWPOLY*)geom;
			for ( i = 0; i < poly->nrings; i++ )
			{
				FLAGS_SET_Z(poly->rings[i]->flags, hasz);
				FLAGS_SET_M(poly->rings[i]->flags, hasm);
			}
			return LW_SUCCESS;
		}
		else if ( geom->type == CURVEPOLYTYPE )
		{
			LWCURVEPOLY *poly = (LWCURVEPOLY*)geom;
			for ( i = 0; i < poly->nrings; i++ )
				wkt_parser_set_dims(poly->rings[i], flags);
			return LW_SUCCESS;
		}
		else if ( lwtype_is_collection(geom->type) )
		{
			LWCOLLECTION *col = (LWCOLLECTION*)geom;
			for ( i = 0; i < col->ngeoms; i++ )
				wkt_parser_set_dims(col->geoms[i], flags);			
			return LW_SUCCESS;
		}
		else
		{
			LWDEBUGF(2,"Unknown geometry type: %d", geom->type);
			return LW_FAILURE;
		}	
	}
	return LW_SUCCESS;				
}
예제 #8
0
파일: lwutil.c 프로젝트: NianYue/pipelinedb
void *
lwrealloc(void *mem, size_t size)
{
	LWDEBUGF(5, "lwrealloc: %d@%p", size, mem);
	return lwrealloc_var(mem, size);
}
예제 #9
0
/**
 * @brief geom1 same as geom2
 *  	iff
 *      	+ have same type
 *			+ have same # objects
 *      	+ have same bvol
 *      	+ each object in geom1 has a corresponding object in geom2 (see above)
 *	@param lwgeom1
 *	@param lwgeom2
 */
char
lwgeom_same(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2)
{
	LWDEBUGF(2, "lwgeom_same(%s, %s) called",
	         lwtype_name(lwgeom1->type),
	         lwtype_name(lwgeom2->type));

	if ( lwgeom1->type != lwgeom2->type )
	{
		LWDEBUG(3, " type differ");

		return LW_FALSE;
	}

	if ( FLAGS_GET_ZM(lwgeom1->flags) != FLAGS_GET_ZM(lwgeom2->flags) )
	{
		LWDEBUG(3, " ZM flags differ");

		return LW_FALSE;
	}

	/* Check boxes if both already computed  */
	if ( lwgeom1->bbox && lwgeom2->bbox )
	{
		/*lwnotice("bbox1:%p, bbox2:%p", lwgeom1->bbox, lwgeom2->bbox);*/
		if ( ! gbox_same(lwgeom1->bbox, lwgeom2->bbox) )
		{
			LWDEBUG(3, " bounding boxes differ");

			return LW_FALSE;
		}
	}

	/* geoms have same type, invoke type-specific function */
	switch (lwgeom1->type)
	{
	case POINTTYPE:
		return lwpoint_same((LWPOINT *)lwgeom1,
		                    (LWPOINT *)lwgeom2);
	case LINETYPE:
		return lwline_same((LWLINE *)lwgeom1,
		                   (LWLINE *)lwgeom2);
	case POLYGONTYPE:
		return lwpoly_same((LWPOLY *)lwgeom1,
		                   (LWPOLY *)lwgeom2);
	case TRIANGLETYPE:
		return lwtriangle_same((LWTRIANGLE *)lwgeom1,
		                       (LWTRIANGLE *)lwgeom2);
	case CIRCSTRINGTYPE:
		return lwcircstring_same((LWCIRCSTRING *)lwgeom1,
					 (LWCIRCSTRING *)lwgeom2);
	case MULTIPOINTTYPE:
	case MULTILINETYPE:
	case MULTIPOLYGONTYPE:
	case MULTICURVETYPE:
	case MULTISURFACETYPE:
	case COMPOUNDTYPE:
	case CURVEPOLYTYPE:
	case POLYHEDRALSURFACETYPE:
	case TINTYPE:
	case COLLECTIONTYPE:
		return lwcollection_same((LWCOLLECTION *)lwgeom1,
		                         (LWCOLLECTION *)lwgeom2);
	default:
		lwerror("lwgeom_same: unsupported geometry type: %s",
		        lwtype_name(lwgeom1->type));
		return LW_FALSE;
	}

}
예제 #10
0
/**
* Take in a LINESTRING and return a MULTILINESTRING of those portions of the
* LINESTRING between the from/to range for the specified ordinate (XYZM)
*/
LWCOLLECTION*
lwline_clip_to_ordinate_range(const LWLINE *line, char ordinate, double from, double to)
{

	POINTARRAY *pa_in = NULL;
	LWCOLLECTION *lwgeom_out = NULL;
	POINTARRAY *dp = NULL;
	int i, rv;
	int added_last_point = 0;
	POINT4D *p = NULL, *q = NULL, *r = NULL;
	double ordinate_value_p = 0.0, ordinate_value_q = 0.0;
	char hasz = lwgeom_has_z(lwline_as_lwgeom(line));
	char hasm = lwgeom_has_m(lwline_as_lwgeom(line));
	char dims = FLAGS_NDIMS(line->flags);

	/* Null input, nothing we can do. */
	if ( ! line )
	{
		lwerror("Null input geometry.");
		return NULL;
	}

	/* Ensure 'from' is less than 'to'. */
	if ( to < from )
	{
		double t = from;
		from = to;
		to = t;
	}

	LWDEBUGF(4, "from = %g, to = %g, ordinate = %c", from, to, ordinate);
	LWDEBUGF(4, "%s", lwgeom_to_ewkt((LWGEOM*)line));

	/* Asking for an ordinate we don't have. Error. */
	if ( (ordinate == 'Z' && ! hasz) || (ordinate == 'M' && ! hasm) )
	{
		lwerror("Cannot clip on ordinate %d in a %d-d geometry.", ordinate, dims);
		return NULL;
	}

	/* Prepare our working point objects. */
	p = lwalloc(sizeof(POINT4D));
	q = lwalloc(sizeof(POINT4D));
	r = lwalloc(sizeof(POINT4D));

	/* Construct a collection to hold our outputs. */
	lwgeom_out = lwcollection_construct_empty(MULTILINETYPE, line->srid, hasz, hasm);

	/* Get our input point array */
	pa_in = line->points;

	for ( i = 0; i < pa_in->npoints; i++ )
	{
		LWDEBUGF(4, "Point #%d", i);
		LWDEBUGF(4, "added_last_point %d", added_last_point);
		if ( i > 0 )
		{
			*q = *p;
			ordinate_value_q = ordinate_value_p;
		}
		rv = getPoint4d_p(pa_in, i, p);
		ordinate_value_p = lwpoint_get_ordinate(p, ordinate);
		LWDEBUGF(4, " ordinate_value_p %g (current)", ordinate_value_p);
		LWDEBUGF(4, " ordinate_value_q %g (previous)", ordinate_value_q);

		/* Is this point inside the ordinate range? Yes. */
		if ( ordinate_value_p >= from && ordinate_value_p <= to )
		{
			LWDEBUGF(4, " inside ordinate range (%g, %g)", from, to);

			if ( ! added_last_point )
			{
				LWDEBUG(4,"  new ptarray required");
				/* We didn't add the previous point, so this is a new segment.
				*  Make a new point array. */
				dp = ptarray_construct_empty(hasz, hasm, 32);

				/* We're transiting into the range so add an interpolated
				*  point at the range boundary.
				*  If we're on a boundary and crossing from the far side,
				*  we also need an interpolated point. */
				if ( i > 0 && ( /* Don't try to interpolate if this is the first point */
				            ( ordinate_value_p > from && ordinate_value_p < to ) || /* Inside */
				            ( ordinate_value_p == from && ordinate_value_q > to ) || /* Hopping from above */
				            ( ordinate_value_p == to && ordinate_value_q < from ) ) ) /* Hopping from below */
				{
					double interpolation_value;
					(ordinate_value_q > to) ? (interpolation_value = to) : (interpolation_value = from);
					rv = point_interpolate(q, p, r, hasz, hasm, ordinate, interpolation_value);
					rv = ptarray_append_point(dp, r, LW_FALSE);
					LWDEBUGF(4, "[0] interpolating between (%g, %g) with interpolation point (%g)", ordinate_value_q, ordinate_value_p, interpolation_value);
				}
			}
			/* Add the current vertex to the point array. */
			rv = ptarray_append_point(dp, p, LW_FALSE);
			if ( ordinate_value_p == from || ordinate_value_p == to )
			{
				added_last_point = 2; /* Added on boundary. */
			}
			else
			{
				added_last_point = 1; /* Added inside range. */
			}
		}
		/* Is this point inside the ordinate range? No. */
		else
		{
			LWDEBUGF(4, "  added_last_point (%d)", added_last_point);
			if ( added_last_point == 1 )
			{
				/* We're transiting out of the range, so add an interpolated point
				*  to the point array at the range boundary. */
				double interpolation_value;
				(ordinate_value_p > to) ? (interpolation_value = to) : (interpolation_value = from);
				rv = point_interpolate(q, p, r, hasz, hasm, ordinate, interpolation_value);
				rv = ptarray_append_point(dp, r, LW_FALSE);
				LWDEBUGF(4, " [1] interpolating between (%g, %g) with interpolation point (%g)", ordinate_value_q, ordinate_value_p, interpolation_value);
			}
			else if ( added_last_point == 2 )
			{
				/* We're out and the last point was on the boundary.
				*  If the last point was the near boundary, nothing to do.
				*  If it was the far boundary, we need an interpolated point. */
				if ( from != to && (
				            (ordinate_value_q == from && ordinate_value_p > from) ||
				            (ordinate_value_q == to && ordinate_value_p < to) ) )
				{
					double interpolation_value;
					(ordinate_value_p > to) ? (interpolation_value = to) : (interpolation_value = from);
					rv = point_interpolate(q, p, r, hasz, hasm, ordinate, interpolation_value);
					rv = ptarray_append_point(dp, r, LW_FALSE);
					LWDEBUGF(4, " [2] interpolating between (%g, %g) with interpolation point (%g)", ordinate_value_q, ordinate_value_p, interpolation_value);
				}
			}
			else if ( i && ordinate_value_q < from && ordinate_value_p > to )
			{
				/* We just hopped over the whole range, from bottom to top,
				*  so we need to add *two* interpolated points! */
				dp = ptarray_construct(hasz, hasm, 2);
				/* Interpolate lower point. */
				rv = point_interpolate(p, q, r, hasz, hasm, ordinate, from);
				ptarray_set_point4d(dp, 0, r);
				/* Interpolate upper point. */
				rv = point_interpolate(p, q, r, hasz, hasm, ordinate, to);
				ptarray_set_point4d(dp, 1, r);
			}
			else if ( i && ordinate_value_q > to && ordinate_value_p < from )
			{
				/* We just hopped over the whole range, from top to bottom,
				*  so we need to add *two* interpolated points! */
				dp = ptarray_construct(hasz, hasm, 2);
				/* Interpolate upper point. */
				rv = point_interpolate(p, q, r, hasz, hasm, ordinate, to);
				ptarray_set_point4d(dp, 0, r);
				/* Interpolate lower point. */
				rv = point_interpolate(p, q, r, hasz, hasm, ordinate, from);
				ptarray_set_point4d(dp, 1, r);
			}
			/* We have an extant point-array, save it out to a multi-line. */
			if ( dp )
			{
				LWDEBUG(4, "saving pointarray to multi-line (1)");

				/* Only one point, so we have to make an lwpoint to hold this
				*  and set the overall output type to a generic collection. */
				if ( dp->npoints == 1 )
				{
					LWPOINT *opoint = lwpoint_construct(line->srid, NULL, dp);
					lwgeom_out->type = COLLECTIONTYPE;
					lwgeom_out = lwcollection_add_lwgeom(lwgeom_out, lwpoint_as_lwgeom(opoint));
					
				}
				else
				{
					LWLINE *oline = lwline_construct(line->srid, NULL, dp);
					lwgeom_out = lwcollection_add_lwgeom(lwgeom_out, lwline_as_lwgeom(oline));
				}

				/* Pointarray is now owned by lwgeom_out, so drop reference to it */
				dp = NULL;
			}
			added_last_point = 0;

		}
	}

	/* Still some points left to be saved out. */
	if ( dp && dp->npoints > 0 )
	{
		LWDEBUG(4, "saving pointarray to multi-line (2)");
		LWDEBUGF(4, "dp->npoints == %d", dp->npoints);
		LWDEBUGF(4, "lwgeom_out->ngeoms == %d", lwgeom_out->ngeoms);

		if ( dp->npoints == 1 )
		{
			LWPOINT *opoint = lwpoint_construct(line->srid, NULL, dp);
			lwgeom_out->type = COLLECTIONTYPE;
			lwgeom_out = lwcollection_add_lwgeom(lwgeom_out, lwpoint_as_lwgeom(opoint));
		}
		else
		{
			LWLINE *oline = lwline_construct(line->srid, NULL, dp);
			lwgeom_out = lwcollection_add_lwgeom(lwgeom_out, lwline_as_lwgeom(oline));
		}

		/* Pointarray is now owned by lwgeom_out, so drop reference to it */
		dp = NULL;
	}

	lwfree(p);
	lwfree(q);
	lwfree(r);

	if ( lwgeom_out->ngeoms > 0 )
	{
		lwgeom_drop_bbox((LWGEOM*)lwgeom_out);
		lwgeom_add_bbox((LWGEOM*)lwgeom_out);
	}

	return lwgeom_out;

}
예제 #11
0
LWGEOM*
lwgeom_union(const LWGEOM *geom1, const LWGEOM *geom2)
{
	int is3d;
	int srid;
	GEOSGeometry *g1, *g2, *g3;
	LWGEOM *result;

	LWDEBUG(2, "in geomunion");

	/* A.Union(empty) == A */
	if ( lwgeom_is_empty(geom1) )
		return lwgeom_clone(geom2);

	/* B.Union(empty) == B */
	if ( lwgeom_is_empty(geom2) )
		return lwgeom_clone(geom1);


	/* ensure srids are identical */
	srid = (int)(geom1->srid);
	error_if_srid_mismatch(srid, (int)(geom2->srid));

	is3d = (FLAGS_GET_Z(geom1->flags) || FLAGS_GET_Z(geom2->flags)) ;

	initGEOS(lwnotice, lwgeom_geos_error);

	g1 = LWGEOM2GEOS(geom1);

	if ( 0 == g1 )   /* exception thrown at construction */
	{
		lwerror("First argument geometry could not be converted to GEOS: %s", lwgeom_geos_errmsg);
		return NULL;
	}

	g2 = LWGEOM2GEOS(geom2);

	if ( 0 == g2 )   /* exception thrown at construction */
	{
		GEOSGeom_destroy(g1);
		lwerror("Second argument geometry could not be converted to GEOS: %s", lwgeom_geos_errmsg);
		return NULL;
	}

	LWDEBUGF(3, "g1=%s", GEOSGeomToWKT(g1));
	LWDEBUGF(3, "g2=%s", GEOSGeomToWKT(g2));

	g3 = GEOSUnion(g1,g2);

	LWDEBUGF(3, "g3=%s", GEOSGeomToWKT(g3));

	GEOSGeom_destroy(g1);
	GEOSGeom_destroy(g2);

	if (g3 == NULL)
	{
		lwerror("GEOSUnion: %s", lwgeom_geos_errmsg);
		return NULL; /* never get here */
	}


	GEOSSetSRID(g3, srid);

	result = GEOS2LWGEOM(g3, is3d);

	GEOSGeom_destroy(g3);

	if (result == NULL)
	{
	        lwerror("Error performing union: GEOS2LWGEOM: %s",
	                lwgeom_geos_errmsg);
		return NULL; /*never get here */
	}

	return result;
}
예제 #12
0
BOX3D *
lwcircle_compute_box3d(POINT4D *p1, POINT4D *p2, POINT4D *p3)
{
	double x1, x2, y1, y2, z1, z2;
	double angle, radius, sweep;
	/* angles from center */
	double a1, a2, a3;
	/* angles from center once a1 is rotated to zero */
	double r2, r3;
	double xe = 0.0, ye = 0.0;
	POINT4D *center;
	int i;
	BOX3D *box;

	LWDEBUG(2, "lwcircle_compute_box3d called.");

	radius = lwcircle_center(p1, p2, p3, &center);
	if (radius < 0.0) 
	{
		LWDEBUG(3, "lwcircle_compute_box3d: zero radius");

		/* 
		 * We've got a straight line here.  Look to the end points for extents. 
		 * It's worth noting that when lwcircle_center returns < 0, center hasn't been allocated.
		 */

		x1 = (FP_LT(p1->x, p3->x)) ? p1->x : p3->x;
		x2 = (FP_GT(p1->x, p3->x)) ? p1->x : p3->x;
		y1 = (FP_LT(p1->y, p3->y)) ? p1->y : p3->y;
		y2 = (FP_GT(p1->y, p3->y)) ? p1->y : p3->y;
		z1 = (FP_LT(p1->z, p2->z)) ? p1->z : p2->z;
		z1 = (FP_LT(z1, p3->z)) ? z1 : p3->z;
		z2 = (FP_GT(p1->z, p2->z)) ? p1->z : p2->z;
		z2 = (FP_GT(z2, p3->z)) ? z2 : p3->z;

		box = lwalloc(sizeof(BOX3D));
		box->xmin = x1;
		box->xmax = x2;
		box->ymin = y1;
		box->ymax = y2;
		box->zmin = z1;
		box->zmax = z2;

		LWDEBUGF(3, "lwcircle_compute_box3d: extents %.16f %.16f %.16f, %.16f %.16f %.16f", x1, y1, z1, x2, y2, z2);

		return box;
	}

	/*
	top = center->y + radius;
	left = center->x - radius;

	LWDEBUGF(3, "lwcircle_compute_box3d: center (%.16f, %.16f)", center->x, center->y);
	*/

	x1 = MAXFLOAT;
	x2 = -1 * MAXFLOAT;
	y1 = MAXFLOAT;
	y2 = -1 * MAXFLOAT;

	a1 = atan2(p1->y - center->y, p1->x - center->x);
	a2 = atan2(p2->y - center->y, p2->x - center->x);
	a3 = atan2(p3->y - center->y, p3->x - center->x);

	/* Rotate a2 and a3 such that a1 = 0 */
	r2 = a2 - a1;
	r3 = a3 - a1;

	LWDEBUGF(4, "a1 %.16f, a2 %.16f, a3 %.16f", a1, a2, a3);
	LWDEBUGF(4, "r2 %.16f, r3 %.16f", r2, r3);

	/*
	 * There are six cases here I'm interested in
	 * Clockwise:
	 *   1. a1-a2 < 180 == r2 < 0 && (r3 > 0 || r3 < r2)
	 *   2. a1-a2 > 180 == r2 > 0 && (r3 > 0 && r3 < r2)
	 *   3. a1-a2 > 180 == r2 > 0 && (r3 > r2 || r3 < 0)
	 * Counter-clockwise:
	 *   4. a1-a2 < 180 == r2 > 0 && (r3 < 0 || r3 > r2)
	 *   5. a1-a2 > 180 == r2 < 0 && (r3 < 0 && r3 > r2)
	 *   6. a1-a2 > 180 == r2 < 0 && (r3 < r2 || r3 > 0)
	 * 3 and 6 are invalid cases where a3 is the midpoint.
	 * BBOX is fundamental, so these cannot error out and will instead
	 * calculate the sweep using a3 as the middle point.
	 */

	/* clockwise 1 */
	if (FP_LT(r2, 0) && (FP_GT(r3, 0) || FP_LT(r3, r2)))
	{
		sweep = (FP_GT(r3, 0)) ? (r3 - 2 * M_PI) : r3;
	}
	/* clockwise 2 */
	else if (FP_GT(r2, 0) && FP_GT(r3, 0) && FP_LT(r3, r2))
	{
		sweep = (FP_GT(r3, 0)) ? (r3 - 2 * M_PI) : r3;
	}
	/* counter-clockwise 4 */
	else if (FP_GT(r2, 0) && (FP_LT(r3, 0) || FP_GT(r3, r2)))
	{
		sweep = (FP_LT(r3, 0)) ? (r3 + 2 * M_PI) : r3;
	}
	/* counter-clockwise 5 */
	else if (FP_LT(r2, 0) && FP_LT(r3, 0) && FP_GT(r3, r2))
	{
		sweep = (FP_LT(r3, 0)) ? (r3 + 2 * M_PI) : r3;
	}
	/* clockwise invalid 3 */
	else if (FP_GT(r2, 0) && (FP_GT(r3, r2) || FP_LT(r3, 0)))
	{
		sweep = (FP_GT(r2, 0)) ? (r2 - 2 * M_PI) : r2;
	}
	/* clockwise invalid 6 */
	else
	{
		sweep = (FP_LT(r2, 0)) ? (r2 + 2 * M_PI) : r2;
	}

	LWDEBUGF(3, "a1 %.16f, a2 %.16f, a3 %.16f, sweep %.16f", a1, a2, a3, sweep);

	angle = 0.0;
	for (i=0; i < 6; i++)
	{
		switch (i)
		{
			/* right extent */
		case 0:
			angle = 0.0;
			xe = center->x + radius;
			ye = center->y;
			break;
			/* top extent */
		case 1:
			angle = M_PI_2;
			xe = center->x;
			ye = center->y + radius;
			break;
			/* left extent */
		case 2:
			angle = M_PI;
			xe = center->x - radius;
			ye = center->y;
			break;
			/* bottom extent */
		case 3:
			angle = -1 * M_PI_2;
			xe = center->x;
			ye = center->y - radius;
			break;
			/* first point */
		case 4:
			angle = a1;
			xe = p1->x;
			ye = p1->y;
			break;
			/* last point */
		case 5:
			angle = a3;
			xe = p3->x;
			ye = p3->y;
			break;
		}
		/* determine if the extents are outside the arc */
		if (i < 4)
		{
			if (FP_GT(sweep, 0.0))
			{
				if (FP_LT(a3, a1))
				{
					if (FP_GT(angle, (a3 + 2 * M_PI)) || FP_LT(angle, a1)) continue;
				}
				else
				{
					if (FP_GT(angle, a3) || FP_LT(angle, a1)) continue;
				}
			}
			else
			{
				if (FP_GT(a3, a1))
				{
					if (FP_LT(angle, (a3 - 2 * M_PI)) || FP_GT(angle, a1)) continue;
				}
				else
				{
					if (FP_LT(angle, a3) || FP_GT(angle, a1)) continue;
				}
			}
		}

		LWDEBUGF(3, "lwcircle_compute_box3d: potential extreame %d (%.16f, %.16f)", i, xe, ye);

		x1 = (FP_LT(x1, xe)) ? x1 : xe;
		y1 = (FP_LT(y1, ye)) ? y1 : ye;
		x2 = (FP_GT(x2, xe)) ? x2 : xe;
		y2 = (FP_GT(y2, ye)) ? y2 : ye;
	}

	LWDEBUGF(3, "lwcircle_compute_box3d: extreames found (%.16f %.16f, %.16f %.16f)", x1, y1, x2, y2);

	/*
	x1 = center->x + x1 * radius;
	x2 = center->x + x2 * radius;
	y1 = center->y + y1 * radius;
	y2 = center->y + y2 * radius;
	*/
	z1 = (FP_LT(p1->z, p2->z)) ? p1->z : p2->z;
	z1 = (FP_LT(z1, p3->z)) ? z1 : p3->z;
	z2 = (FP_GT(p1->z, p2->z)) ? p1->z : p2->z;
	z2 = (FP_GT(z2, p3->z)) ? z2 : p3->z;

	box = lwalloc(sizeof(BOX3D));
	box->xmin = x1;
	box->xmax = x2;
	box->ymin = y1;
	box->ymax = y2;
	box->zmin = z1;
	box->zmax = z2;

	lwfree(center);

	return box;
}
예제 #13
0
/*
 * given the LWGEOM serialized form (or a point into a multi* one)
 * construct a proper LWCIRCSTRING.
 * serialized_form should point to the 8bit type format (with type = 8)
 * See serialized form doc
 */
LWCIRCSTRING *
lwcircstring_deserialize(uchar *serialized_form)
{
	uchar type;
	LWCIRCSTRING *result;
	uchar *loc=NULL;
	uint32 npoints;
	POINTARRAY *pa;

	type = (uchar)serialized_form[0];
	if (lwgeom_getType(type) != CIRCSTRINGTYPE)
	{
		lwerror("lwcircstring_deserialize: attempt to deserialize a circularstring which is really a %s", lwgeom_typename(type));
		return NULL;
	}

	result = (LWCIRCSTRING*) lwalloc(sizeof(LWCIRCSTRING));
	result->type = type;

	loc = serialized_form + 1;

	if (lwgeom_hasBBOX(type))
	{
		LWDEBUG(3, "lwcircstring_deserialize: input has bbox");

		result->bbox = lwalloc(sizeof(BOX2DFLOAT4));
		memcpy(result->bbox, loc, sizeof(BOX2DFLOAT4));
		loc += sizeof(BOX2DFLOAT4);
	}
	else
	{
		LWDEBUG(3, "lwcircstring_deserialize: input lacks bbox");

		result->bbox = NULL;
	}

	if (lwgeom_hasSRID(type))
	{
		LWDEBUG(3, "lwcircstring_deserialize: input has srid");

		result->SRID = lw_get_int32(loc);
		loc += 4; /* type + SRID */
	}
	else
	{
		LWDEBUG(3, "lwcircstring_deserialize: input lacks srid");

		result->SRID = -1;
	}

	/* we've read the type (1 byte) and SRID (4 bytes, if present) */

	npoints = lw_get_uint32(loc);

	LWDEBUGF(3, "circstring npoints = %d", npoints);

	loc += 4;
	pa = pointArray_construct(loc, TYPE_HASZ(type), TYPE_HASM(type), npoints);
	result->points = pa;
	return result;
}
예제 #14
0
/*
 * convert this circularstring into its serialized form writing it into
 * the given buffer, and returning number of bytes written into
 * the given int pointer.
 * result's first char will be the 8bit type.  See serialized form doc
 */
void lwcircstring_serialize_buf(LWCIRCSTRING *curve, uchar *buf, size_t *retsize)
{
	char hasSRID;
	uchar *loc;
	int ptsize;
	size_t size;

	LWDEBUGF(2, "lwcircstring_serialize_buf(%p, %p, %p) called",
	         curve, buf, retsize);

	if (curve == NULL)
	{
		lwerror("lwcircstring_serialize:: given null curve");
		return;
	}

	if (TYPE_GETZM(curve->type) != TYPE_GETZM(curve->points->dims))
	{
		lwerror("Dimensions mismatch in lwcircstring");
		return;
	}

	ptsize = pointArray_ptsize(curve->points);

	hasSRID = (curve->SRID != -1);

	buf[0] = (uchar)lwgeom_makeType_full(
	             TYPE_HASZ(curve->type), TYPE_HASM(curve->type),
	             hasSRID, CIRCSTRINGTYPE, curve->bbox ? 1 : 0);
	loc = buf+1;

	LWDEBUGF(3, "lwcircstring_serialize_buf added type (%d)", curve->type);

	if (curve->bbox)
	{
		memcpy(loc, curve->bbox, sizeof(BOX2DFLOAT4));
		loc += sizeof(BOX2DFLOAT4);

		LWDEBUG(3, "lwcircstring_serialize_buf added BBOX");
	}

	if (hasSRID)
	{
		memcpy(loc, &curve->SRID, sizeof(int32));
		loc += sizeof(int32);

		LWDEBUG(3, "lwcircstring_serialize_buf added SRID");
	}

	memcpy(loc, &curve->points->npoints, sizeof(uint32));
	loc += sizeof(uint32);

	LWDEBUGF(3, "lwcircstring_serialize_buf added npoints (%d)",
	         curve->points->npoints);

	/* copy in points */
	size = curve->points->npoints * ptsize;
	memcpy(loc, getPoint_internal(curve->points, 0), size);
	loc += size;

	LWDEBUGF(3, "lwcircstring_serialize_buf copied serialized_pointlist (%d bytes)",
	         ptsize * curve->points->npoints);

	if (retsize) *retsize = loc-buf;

	LWDEBUGF(3, "lwcircstring_serialize_buf returning (loc: %p, size: %d)",
	         loc, loc-buf);
}
예제 #15
0
파일: lwspheroid.c 프로젝트: Vlczech/vtapi
static double ptarray_area_spheroid(const POINTARRAY *pa, const SPHEROID *spheroid)
{
	GEOGRAPHIC_POINT a, b;
	POINT2D p;
	int i;
	double area = 0.0;
	GBOX gbox2d;
	int in_south = LW_FALSE;
	double delta_lon_tolerance;
	double latitude_min;

	gbox2d.flags = gflags(0, 0, 0);

	/* Return zero on non-sensical inputs */
	if ( ! pa || pa->npoints < 4 )
		return 0.0;

	/* Get the raw min/max values for the latitudes */
	ptarray_calculate_gbox(pa, &gbox2d);

	if ( signum(gbox2d.ymin) != signum(gbox2d.ymax) )
		lwerror("ptarray_area_spheroid: cannot handle ptarray that crosses equator");

	/* Geodetic bbox < 0.0 implies geometry is entirely in southern hemisphere */
	if ( gbox2d.ymax < 0.0 )
		in_south = LW_TRUE;

	LWDEBUGF(4, "gbox2d.ymax %.12g", gbox2d.ymax);

	/* Tolerance for strip area calculation */
	if ( in_south )
	{
		delta_lon_tolerance = (90.0 / (fabs(gbox2d.ymin) / 8.0) - 2.0) / 10000.0;
		latitude_min = deg2rad(fabs(gbox2d.ymax));
	}
	else
	{
		delta_lon_tolerance = (90.0 / (fabs(gbox2d.ymax) / 8.0) - 2.0) / 10000.0;
		latitude_min = deg2rad(gbox2d.ymin);
	}

	/* Initialize first point */
	getPoint2d_p(pa, 0, &p);
	geographic_point_init(p.x, p.y, &a);

	for ( i = 1; i < pa->npoints; i++ )
	{
		GEOGRAPHIC_POINT a1, b1;
		double strip_area = 0.0;
		double delta_lon = 0.0;
		LWDEBUGF(4, "edge #%d", i);

		getPoint2d_p(pa, i, &p);
		geographic_point_init(p.x, p.y, &b);

		a1 = a;
		b1 = b;

		/* Flip into north if in south */
		if ( in_south )
		{
			a1.lat = -1.0 * a1.lat;
			b1.lat = -1.0 * b1.lat;
		}

		LWDEBUGF(4, "in_south %d", in_south);

		LWDEBUGF(4, "crosses_dateline(a, b) %d", crosses_dateline(&a, &b) );

		if ( crosses_dateline(&a, &b) )
		{
			double shift;

			if ( a1.lon > 0.0 )
				shift = (M_PI - a1.lon) + 0.088; /* About 5deg more */
			else
				shift = (M_PI - b1.lon) + 0.088; /* About 5deg more */

			LWDEBUGF(4, "shift: %.8g", shift);
			LWDEBUGF(4, "before shift a1(%.8g %.8g) b1(%.8g %.8g)", a1.lat, a1.lon, b1.lat, b1.lon);
			point_shift(&a1, shift);
			point_shift(&b1, shift);
			LWDEBUGF(4, "after shift a1(%.8g %.8g) b1(%.8g %.8g)", a1.lat, a1.lon, b1.lat, b1.lon);
			
		}


		delta_lon = fabs(b1.lon - a1.lon);

		LWDEBUGF(4, "a1(%.18g %.18g) b1(%.18g %.18g)", a1.lat, a1.lon, b1.lat, b1.lon);
		LWDEBUGF(4, "delta_lon %.18g", delta_lon);
		LWDEBUGF(4, "delta_lon_tolerance %.18g", delta_lon_tolerance);

		if ( delta_lon > 0.0 )
		{
			if ( delta_lon < delta_lon_tolerance )
			{
				strip_area = spheroid_striparea(&a1, &b1, latitude_min, spheroid);
				LWDEBUGF(4, "strip_area %.12g", strip_area);
				area += strip_area;
			}
			else
			{
				GEOGRAPHIC_POINT p, q;
				double step = floor(delta_lon / delta_lon_tolerance);
				double distance = spheroid_distance(&a1, &b1, spheroid);
				double pDistance = 0.0;
				int j = 0;
				LWDEBUGF(4, "step %.18g", step);
				LWDEBUGF(4, "distance %.18g", distance);
				step = distance / step;
				LWDEBUGF(4, "step %.18g", step);
				p = a1;
				while (pDistance < (distance - step * 1.01))
				{
					double azimuth = spheroid_direction(&p, &b1, spheroid);
					j++;
					LWDEBUGF(4, "  iteration %d", j);
					LWDEBUGF(4, "  azimuth %.12g", azimuth);
					pDistance = pDistance + step;
					LWDEBUGF(4, "  pDistance %.12g", pDistance);
					spheroid_project(&p, spheroid, step, azimuth, &q);
					strip_area = spheroid_striparea(&p, &q, latitude_min, spheroid);
					LWDEBUGF(4, "  strip_area %.12g", strip_area);
					area += strip_area;
					LWDEBUGF(4, "  area %.12g", area);
					p.lat = q.lat;
					p.lon = q.lon;
				}
				strip_area = spheroid_striparea(&p, &b1, latitude_min, spheroid);
				area += strip_area;
			}
		}

		/* B gets incremented in the next loop, so we save the value here */
		a = b;
	}
	return fabs(area);
}
예제 #16
0
파일: ptarray.c 프로젝트: TesseractG/lwgeom
/*
 * Given a point, returns the location of closest point on pointarray
 * and, optionally, it's actual distance from the point array.
 */
double
ptarray_locate_point(const POINTARRAY *pa, const POINT4D *p4d, double *mindistout, POINT4D *proj4d)
{
	double mindist=-1;
	double tlen, plen;
	int t, seg=-1;
	POINT4D	start4d, end4d, projtmp;
	POINT2D start, end, proj, p;

	/* Initialize our 2D copy of the input parameter */
	p.x = p4d->x;
	p.y = p4d->y;
	
	if ( ! proj4d ) proj4d = &projtmp;

	getPoint2d_p(pa, 0, &start);
	for (t=1; t<pa->npoints; t++)
	{
		double dist;
		getPoint2d_p(pa, t, &end);
		dist = distance2d_pt_seg(&p, &start, &end);

		if (t==1 || dist < mindist )
		{
			mindist = dist;
			seg=t-1;
		}

		if ( mindist == 0 )
		{
			LWDEBUG(3, "Breaking on mindist=0");
			break;
		}

		start = end;
	}

	if ( mindistout ) *mindistout = mindist;

	LWDEBUGF(3, "Closest segment: %d", seg);
	LWDEBUGF(3, "mindist: %g", mindist);

	/*
	 * We need to project the
	 * point on the closest segment.
	 */
	getPoint4d_p(pa, seg, &start4d);
	getPoint4d_p(pa, seg+1, &end4d);
	closest_point_on_segment(p4d, &start4d, &end4d, proj4d);
	
	/* Copy 4D values into 2D holder */
	proj.x = proj4d->x;
	proj.y = proj4d->y;

	LWDEBUGF(3, "Closest segment:%d, npoints:%d", seg, pa->npoints);

	/* For robustness, force 1 when closest point == endpoint */
	if ( (seg >= (pa->npoints-2)) && p2d_same(&proj, &end) )
	{
		return 1.0;
	}

	LWDEBUGF(3, "Closest point on segment: %g,%g", proj.x, proj.y);

	tlen = ptarray_length_2d(pa);

	LWDEBUGF(3, "tlen %g", tlen);

	/* Location of any point on a zero-length line is 0 */
	/* See http://trac.osgeo.org/postgis/ticket/1772#comment:2 */
	if ( tlen == 0 ) return 0;

	plen=0;
	getPoint2d_p(pa, 0, &start);
	for (t=0; t<seg; t++, start=end)
	{
		getPoint2d_p(pa, t+1, &end);
		plen += distance2d_pt_pt(&start, &end);

		LWDEBUGF(4, "Segment %d made plen %g", t, plen);
	}

	plen+=distance2d_pt_pt(&proj, &start);

	LWDEBUGF(3, "plen %g, tlen %g", plen, tlen);

	return plen/tlen;
}
예제 #17
0
LWGEOM *
lwgeom_intersection(const LWGEOM *geom1, const LWGEOM *geom2)
{
	LWGEOM *result ;
	GEOSGeometry *g1, *g2, *g3 ;
	int is3d ;
	int srid ;

	/* A.Intersection(Empty) == Empty */
	if ( lwgeom_is_empty(geom2) )
		return lwgeom_clone(geom2);

	/* Empty.Intersection(A) == Empty */
	if ( lwgeom_is_empty(geom1) )
		return lwgeom_clone(geom1);

	/* ensure srids are identical */
	srid = (int)(geom1->srid);
	error_if_srid_mismatch(srid, (int)(geom2->srid));

	is3d = (FLAGS_GET_Z(geom1->flags) || FLAGS_GET_Z(geom2->flags)) ;

	initGEOS(lwnotice, lwgeom_geos_error);

	LWDEBUG(3, "intersection() START");

	g1 = LWGEOM2GEOS(geom1);
	if ( 0 == g1 )   /* exception thrown at construction */
	{
		lwerror("First argument geometry could not be converted to GEOS.");
		return NULL ;
	}

	g2 = LWGEOM2GEOS(geom2);
	if ( 0 == g2 )   /* exception thrown at construction */
	{
		lwerror("Second argument geometry could not be converted to GEOS.");
		GEOSGeom_destroy(g1);
		return NULL ;
	}

	LWDEBUG(3, " constructed geometrys - calling geos");
	LWDEBUGF(3, " g1 = %s", GEOSGeomToWKT(g1));
	LWDEBUGF(3, " g2 = %s", GEOSGeomToWKT(g2));
	/*LWDEBUGF(3, "g2 is valid = %i",GEOSisvalid(g2)); */
	/*LWDEBUGF(3, "g1 is valid = %i",GEOSisvalid(g1)); */

	g3 = GEOSIntersection(g1,g2);

	LWDEBUG(3, " intersection finished");

	if (g3 == NULL)
	{
		GEOSGeom_destroy(g1);
		GEOSGeom_destroy(g2);
	        lwerror("Error performing intersection: %s",
	                lwgeom_geos_errmsg);
		return NULL; /* never get here */
	}

	LWDEBUGF(3, "result: %s", GEOSGeomToWKT(g3) ) ;

	GEOSSetSRID(g3, srid);

	result = GEOS2LWGEOM(g3, is3d);

	if (result == NULL)
	{
		GEOSGeom_destroy(g1);
		GEOSGeom_destroy(g2);
		GEOSGeom_destroy(g3);
	        lwerror("Error performing intersection: GEOS2LWGEOM: %s",
	                lwgeom_geos_errmsg);
		return NULL ; /* never get here */
	}

	GEOSGeom_destroy(g1);
	GEOSGeom_destroy(g2);
	GEOSGeom_destroy(g3);

	return result ;
}
예제 #18
0
/**
 * pt_in_ring_3d(): crossing number test for a point in a polygon
 *      input:   p = a point,
 *               pa = vertex points of a ring V[n+1] with V[n]=V[0]
*		plane=the plane that the vertex points are lying on
 *      returns: 0 = outside, 1 = inside
 *
 *	Our polygons have first and last point the same,
 *
*	The difference in 3D variant is that we exclude the dimension that faces the plane least.
*	That is the dimension with the highest number in pv
 */
int
pt_in_ring_3d(const POINT3DZ *p, const POINTARRAY *ring,PLANE3D *plane)
{
	
	int cn = 0;    /* the crossing number counter */
	int i;
	POINT3DZ v1, v2;

	POINT3DZ	first, last;

	getPoint3dz_p(ring, 0, &first);
	getPoint3dz_p(ring, ring->npoints-1, &last);
	if ( memcmp(&first, &last, sizeof(POINT3DZ)) )
	{
		lwerror("pt_in_ring_3d: V[n] != V[0] (%g %g %g!= %g %g %g)",
		        first.x, first.y, first.z, last.x, last.y, last.z);
		return LW_FALSE;
	}

	LWDEBUGF(2, "pt_in_ring_3d called with point: %g %g %g", p->x, p->y, p->z);
	/* printPA(ring); */

	/* loop through all edges of the polygon */
	getPoint3dz_p(ring, 0, &v1);
	
	
	if(fabs(plane->pv.z)>=fabs(plane->pv.x)&&fabs(plane->pv.z)>=fabs(plane->pv.y))	/*If the z vector of the normal vector to the plane is larger than x and y vector we project the ring to the xy-plane*/
	{
		for (i=0; i<ring->npoints-1; i++)
		{
			double vt;
			getPoint3dz_p(ring, i+1, &v2);

			/* edge from vertex i to vertex i+1 */
			if
			(
			    /* an upward crossing */
			    ((v1.y <= p->y) && (v2.y > p->y))
			    /* a downward crossing */
			    || ((v1.y > p->y) && (v2.y <= p->y))
			)
			{

				vt = (double)(p->y - v1.y) / (v2.y - v1.y);

				/* P.x <intersect */
				if (p->x < v1.x + vt * (v2.x - v1.x))
				{
					/* a valid crossing of y=p.y right of p.x */
					++cn;
				}
			}
			v1 = v2;
		}
	}
	else if(fabs(plane->pv.y)>=fabs(plane->pv.x)&&fabs(plane->pv.y)>=fabs(plane->pv.z))	/*If the y vector of the normal vector to the plane is larger than x and z vector we project the ring to the xz-plane*/
	{
		for (i=0; i<ring->npoints-1; i++)
			{
				double vt;
				getPoint3dz_p(ring, i+1, &v2);

				/* edge from vertex i to vertex i+1 */
				if
				(
				    /* an upward crossing */
				    ((v1.z <= p->z) && (v2.z > p->z))
				    /* a downward crossing */
				    || ((v1.z > p->z) && (v2.z <= p->z))
				)
				{

					vt = (double)(p->z - v1.z) / (v2.z - v1.z);

					/* P.x <intersect */
					if (p->x < v1.x + vt * (v2.x - v1.x))
					{
						/* a valid crossing of y=p.y right of p.x */
						++cn;
					}
				}
				v1 = v2;
			}
	}
	else	/*Hopefully we only have the cases where x part of the normal vector is largest left*/
	{
		for (i=0; i<ring->npoints-1; i++)
			{
				double vt;
				getPoint3dz_p(ring, i+1, &v2);

				/* edge from vertex i to vertex i+1 */
				if
				(
				    /* an upward crossing */
				    ((v1.z <= p->z) && (v2.z > p->z))
				    /* a downward crossing */
				    || ((v1.z > p->z) && (v2.z <= p->z))
				)
				{

					vt = (double)(p->z - v1.z) / (v2.z - v1.z);

					/* P.x <intersect */
					if (p->y < v1.y + vt * (v2.y - v1.y))
					{
						/* a valid crossing of y=p.y right of p.x */
						++cn;
					}
				}
				v1 = v2;
			}
	}
	LWDEBUGF(3, "pt_in_ring_3d returning %d", cn&1);

	return (cn&1);    /* 0 if even (out), and 1 if odd (in) */
}
예제 #19
0
LWGEOM *
lwgeom_symdifference(const LWGEOM* geom1, const LWGEOM* geom2)
{
	GEOSGeometry *g1, *g2, *g3;
	LWGEOM *result;
	int is3d;
	int srid;

	/* A.SymDifference(Empty) == A */
	if ( lwgeom_is_empty(geom2) )
		return lwgeom_clone(geom1);

	/* Empty.DymDifference(B) == Empty */
	if ( lwgeom_is_empty(geom1) )
		return lwgeom_clone(geom1);

	/* ensure srids are identical */
	srid = (int)(geom1->srid);
	error_if_srid_mismatch(srid, (int)(geom2->srid));

	is3d = (FLAGS_GET_Z(geom1->flags) || FLAGS_GET_Z(geom2->flags)) ;

	initGEOS(lwnotice, lwgeom_geos_error);

	g1 = LWGEOM2GEOS(geom1);

	if ( 0 == g1 )   /* exception thrown at construction */
	{
		lwerror("First argument geometry could not be converted to GEOS: %s", lwgeom_geos_errmsg);
		return NULL;
	}

	g2 = LWGEOM2GEOS(geom2);

	if ( 0 == g2 )   /* exception thrown at construction */
	{
		lwerror("Second argument geometry could not be converted to GEOS: %s", lwgeom_geos_errmsg);
		GEOSGeom_destroy(g1);
		return NULL;
	}

	g3 = GEOSSymDifference(g1,g2);

	if (g3 == NULL)
	{
		GEOSGeom_destroy(g1);
		GEOSGeom_destroy(g2);
		lwerror("GEOSSymDifference: %s", lwgeom_geos_errmsg);
		return NULL; /*never get here */
	}

	LWDEBUGF(3, "result: %s", GEOSGeomToWKT(g3));

	GEOSSetSRID(g3, srid);

	result = GEOS2LWGEOM(g3, is3d);

	if (result == NULL)
	{
		GEOSGeom_destroy(g1);
		GEOSGeom_destroy(g2);
		GEOSGeom_destroy(g3);
		lwerror("GEOS symdifference() threw an error (result postgis geometry formation)!");
		return NULL ; /*never get here */
	}

	GEOSGeom_destroy(g1);
	GEOSGeom_destroy(g2);
	GEOSGeom_destroy(g3);

	return result;
}
예제 #20
0
/**
This is a recursive function delivering every possible combination of subgeometries
*/
int lw_dist3d_recursive(const LWGEOM *lwg1,const LWGEOM *lwg2, DISTPTS3D *dl)
{
	int i, j;
	int n1=1;
	int n2=1;
	LWGEOM *g1 = NULL;
	LWGEOM *g2 = NULL;
	LWCOLLECTION *c1 = NULL;
	LWCOLLECTION *c2 = NULL;

	LWDEBUGF(2, "lw_dist3d_recursive is called with type1=%d, type2=%d", lwg1->type, lwg2->type);

	if (lwgeom_is_collection(lwg1))
	{
		LWDEBUG(3, "First geometry is collection");
		c1 = lwgeom_as_lwcollection(lwg1);
		n1 = c1->ngeoms;
	}
	if (lwgeom_is_collection(lwg2))
	{
		LWDEBUG(3, "Second geometry is collection");
		c2 = lwgeom_as_lwcollection(lwg2);
		n2 = c2->ngeoms;
	}

	for ( i = 0; i < n1; i++ )
	{

		if (lwgeom_is_collection(lwg1))
		{
			g1 = c1->geoms[i];
		}
		else
		{
			g1 = (LWGEOM*)lwg1;
		}

		if (lwgeom_is_empty(g1)) return LW_TRUE;

		if (lwgeom_is_collection(g1))
		{
			LWDEBUG(3, "Found collection inside first geometry collection, recursing");
			if (!lw_dist3d_recursive(g1, lwg2, dl)) return LW_FALSE;
			continue;
		}
		for ( j = 0; j < n2; j++ )
		{
			if (lwgeom_is_collection(lwg2))
			{
				g2 = c2->geoms[j];
			}
			else
			{
				g2 = (LWGEOM*)lwg2;
			}
			if (lwgeom_is_collection(g2))
			{
				LWDEBUG(3, "Found collection inside second geometry collection, recursing");
				if (!lw_dist3d_recursive(g1, g2, dl)) return LW_FALSE;
				continue;
			}


			/*If one of geometries is empty, return. True here only means continue searching. False would have stoped the process*/
			if (lwgeom_is_empty(g1)||lwgeom_is_empty(g2)) return LW_TRUE;


			if (!lw_dist3d_distribute_bruteforce(g1, g2, dl)) return LW_FALSE;
			if (dl->distance<=dl->tolerance && dl->mode == DIST_MIN) return LW_TRUE; /*just a check if  the answer is already given*/
		}
	}
	return LW_TRUE;
}
예제 #21
0
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);

	vgeoms[0] = geom_in;
	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);

	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;
	}

	/*
	 * Iteratively invoke symdifference on outer rings
	 * as suggested by Carl Anderson:
	 * postgis-devel/2005-December/001805.html
	 */
	shp = NULL;
	for (i=0; i<ngeoms; ++i)
	{
		GEOSGeom extring;
		GEOSCoordSeq sq;

		/*
		 * Construct a Polygon from geometry i exterior ring
		 * We don't use GEOSGeom_clone on the ExteriorRing
		 * due to a bug in CAPI contained in GEOS 2.2 branch
		 * failing to properly return a LinearRing from
		 * a LinearRing clone.
		 */
		sq=GEOSCoordSeq_clone(GEOSGeom_getCoordSeq(
		                          GEOSGetExteriorRing(GEOSGetGeometryN( geos_result, i))
		                      ));
		extring = GEOSGeom_createPolygon(
		              GEOSGeom_createLinearRing(sq),
		              NULL, 0
		          );

		if ( extring == NULL ) /* exception */
		{
			lwerror("GEOSCreatePolygon threw an exception");
			return 0;
		}

		if ( shp == NULL )
		{
			shp = extring;
			LWDEBUGF(3, "GEOSpolygonize: shp:%s",
			               lwgeom_to_ewkt(GEOS2LWGEOM(shp, 0)));
		}
		else
		{
			tmp = GEOSSymDifference(shp, extring);
			LWDEBUGF(3, "GEOSpolygonize: SymDifference(%s, %s):%s",
			               lwgeom_to_ewkt(GEOS2LWGEOM(shp, 0)),
			               lwgeom_to_ewkt(GEOS2LWGEOM(extring, 0)),
			               lwgeom_to_ewkt(GEOS2LWGEOM(tmp, 0))
			              );
			GEOSGeom_destroy(shp);
			GEOSGeom_destroy(extring);
			shp = tmp;
		}
	}

	GEOSGeom_destroy(geos_result);

	GEOSSetSRID(shp, srid);

	return shp;
}
예제 #22
0
/**

This function distributes the brute-force for 3D so far the only type, tasks depending on type
*/
int
lw_dist3d_distribute_bruteforce(const LWGEOM *lwg1, const LWGEOM *lwg2, DISTPTS3D *dl)
{

	int	t1 = lwg1->type;
	int	t2 = lwg2->type;

	LWDEBUGF(2, "lw_dist3d_distribute_bruteforce is called with typ1=%d, type2=%d", lwg1->type, lwg2->type);

	if  ( t1 == POINTTYPE )
	{
		if  ( t2 == POINTTYPE )
		{
			dl->twisted=1;
			return lw_dist3d_point_point((LWPOINT *)lwg1, (LWPOINT *)lwg2, dl);
		}
		else if  ( t2 == LINETYPE )
		{
			dl->twisted=1;
			return lw_dist3d_point_line((LWPOINT *)lwg1, (LWLINE *)lwg2, dl);
		}
		else if  ( t2 == POLYGONTYPE )
		{
			dl->twisted=1;
			return lw_dist3d_point_poly((LWPOINT *)lwg1, (LWPOLY *)lwg2,dl);
		}
		else
		{
			lwerror("Unsupported geometry type: %s", lwtype_name(t2));
			return LW_FALSE;
		}
	}
	else if ( t1 == LINETYPE )
	{
		if ( t2 == POINTTYPE )
		{
			dl->twisted=(-1);
			return lw_dist3d_point_line((LWPOINT *)lwg2,(LWLINE *)lwg1,dl);
		}
		else if ( t2 == LINETYPE )
		{
			dl->twisted=1;
			return lw_dist3d_line_line((LWLINE *)lwg1,(LWLINE *)lwg2,dl);
		}
		else if ( t2 == POLYGONTYPE )
		{
			dl->twisted=1;
			return lw_dist3d_line_poly((LWLINE *)lwg1,(LWPOLY *)lwg2,dl);
		}
		else
		{
			lwerror("Unsupported geometry type: %s", lwtype_name(t2));
			return LW_FALSE;
		}
	}
	else if ( t1 == POLYGONTYPE )
	{
		if ( t2 == POLYGONTYPE )
		{
			dl->twisted=1;
			return lw_dist3d_poly_poly((LWPOLY *)lwg1, (LWPOLY *)lwg2,dl);
		}
		else if ( t2 == POINTTYPE )
		{
			dl->twisted=-1;
			return lw_dist3d_point_poly((LWPOINT *)lwg2, (LWPOLY *)lwg1,dl);
		}
		else if ( t2 == LINETYPE )
		{
			dl->twisted=-1;
			return lw_dist3d_line_poly((LWLINE *)lwg2,(LWPOLY *)lwg1,dl);
		}
		else
		{
			lwerror("Unsupported geometry type: %s", lwtype_name(t2));
			return LW_FALSE;
		}
	}
	else
	{
		lwerror("Unsupported geometry type: %s", lwtype_name(t1));
		return LW_FALSE;
	}
	/*You shouldn't being able to get here*/
	lwerror("unspecified error in function lw_dist3d_distribute_bruteforce");
	return LW_FALSE;
}
예제 #23
0
LWGEOM* lwgeom_flip_coordinates(LWGEOM *in)
{
	LWCOLLECTION *col;
	LWPOLY *poly;
	int i;

	if ( (!in) || lwgeom_is_empty(in) )
		return in;

	LWDEBUGF(4, "lwgeom_flip_coordinates, got type: %s",
	         lwtype_name(in->type));

	switch (in->type)
	{
	case POINTTYPE:
		ptarray_flip_coordinates(lwgeom_as_lwpoint(in)->point);
		break;

	case LINETYPE:
		ptarray_flip_coordinates(lwgeom_as_lwline(in)->points);
		break;

	case CIRCSTRINGTYPE:
		ptarray_flip_coordinates(lwgeom_as_lwcircstring(in)->points);
		break;

	case POLYGONTYPE:
		poly = (LWPOLY *) in;
		for (i=0; i<poly->nrings; i++)
		{
			ptarray_flip_coordinates(poly->rings[i]);
		}
		break;

	case TRIANGLETYPE:
		ptarray_flip_coordinates(lwgeom_as_lwtriangle(in)->points);
		break;

	case MULTIPOINTTYPE:
	case MULTILINETYPE:
	case MULTIPOLYGONTYPE:
	case COLLECTIONTYPE:
	case COMPOUNDTYPE:
	case CURVEPOLYTYPE:
	case MULTISURFACETYPE:
	case MULTICURVETYPE:
	case POLYHEDRALSURFACETYPE:
	case TINTYPE:
		col = (LWCOLLECTION *) in;
		for (i=0; i<col->ngeoms; i++)
		{
			lwgeom_flip_coordinates(col->geoms[i]);
		}
		break;

	default:
		lwerror("lwgeom_flip_coordinates: unsupported geometry type: %s",
		        lwtype_name(in->type));
		return NULL;
	}

	lwgeom_drop_bbox(in);
	lwgeom_add_bbox(in);
	return in;
}
예제 #24
0
/**
* Stores a pointarray as varints in the buffer
* @register_npoints, controls whether an npoints entry is added to the buffer (used to skip npoints for point types)
* @dimension, states the dimensionality of object this array is part of (0 = point, 1 = linear, 2 = areal)
*/
static int ptarray_to_twkb_buf(const POINTARRAY *pa, TWKB_GLOBALS *globals, TWKB_STATE *ts, int register_npoints, int minpoints)
{
	int ndims = FLAGS_NDIMS(pa->flags);
	int i, j;
	bytebuffer_t b;
	bytebuffer_t *b_p;
	int64_t nextdelta[MAX_N_DIMS];
	int npoints = 0;
	size_t npoints_offset = 0;

	LWDEBUGF(2, "Entered %s", __func__);

	/* Dispense with the empty case right away */
	if ( pa->npoints == 0 && register_npoints )	
	{		
		LWDEBUGF(4, "Register npoints:%d", pa->npoints);
		bytebuffer_append_uvarint(ts->geom_buf, pa->npoints);
		return 0;
	}

	/* If npoints is more than 127 it is unpredictable how many bytes npoints will need */
	/* Then we have to store the deltas in a temp buffer to later add them after npoints */
	/* If noints is below 128 we know 1 byte will be needed */
	/* Then we can make room for that 1 byte at once and write to */
	/* ordinary buffer */
	if( pa->npoints > 127 )
	{
		/* Independent buffer to hold the coordinates, so we can put the npoints */
		/* into the stream once we know how many points we actually have */
		bytebuffer_init_with_size(&b, 3 * ndims * pa->npoints);
		b_p = &b;
	}
	else
	{
		/* We give an alias to our ordinary buffer */
		b_p = ts->geom_buf;
		if ( register_npoints )		
		{		
			/* We do not store a pointer to the place where we want the npoints value */
			/* Instead we store how far from the beginning of the buffer we want the value */
			/* That is because we otherwise will get in trouble if the buffer is reallocated */			
			npoints_offset = b_p->writecursor - b_p->buf_start;
			
			/* We just move the cursor 1 step to make room for npoints byte */
			/* We use the function append_byte even if we have no value yet, */
			/* since that gives us the check for big enough buffer and moves the cursor */
			bytebuffer_append_byte(b_p, 0);
		}
	}
	
	for ( i = 0; i < pa->npoints; i++ )
	{
		double *dbl_ptr = (double*)getPoint_internal(pa, i);
		int diff = 0;

		/* Write this coordinate to the buffer as a varint */
		for ( j = 0; j < ndims; j++ )
		{
			/* To get the relative coordinate we don't get the distance */
			/* from the last point but instead the distance from our */
			/* last accumulated point. This is important to not build up an */
			/* accumulated error when rounding the coordinates */
			nextdelta[j] = (int64_t) llround(globals->factor[j] * dbl_ptr[j]) - ts->accum_rels[j];
			LWDEBUGF(4, "deltavalue: %d, ", nextdelta[j]);
			diff += llabs(nextdelta[j]);
		}
		
		/* Skipping the first point is not allowed */
		/* If the sum(abs()) of all the deltas was zero, */
		/* then this was a duplicate point, so we can ignore it */
		if ( i > minpoints && diff == 0 )
			continue;
		
		/* We really added a point, so... */
		npoints++;
		
		/* Write this vertex to the temporary buffer as varints */
		for ( j = 0; j < ndims; j++ )
		{
			ts->accum_rels[j] += nextdelta[j];
			bytebuffer_append_varint(b_p, nextdelta[j]);
		}

		/* See if this coordinate expands the bounding box */
		if( globals->variant & TWKB_BBOX )
		{
			for ( j = 0; j < ndims; j++ )
			{
				if( ts->accum_rels[j] > ts->bbox_max[j] )
					ts->bbox_max[j] = ts->accum_rels[j];

				if( ts->accum_rels[j] < ts->bbox_min[j] )
					ts->bbox_min[j] = ts->accum_rels[j];
			}
		}

	}	

	if ( pa->npoints > 127 )
	{		
		/* Now write the temporary results into the main buffer */
		/* First the npoints */
		if ( register_npoints )	
			bytebuffer_append_uvarint(ts->geom_buf, npoints);
		/* Now the coordinates */
		bytebuffer_append_bytebuffer(ts->geom_buf, b_p);
		
		/* Clear our temporary buffer */
		lwfree(b.buf_start);
	}
	else
	{
		/* If we didn't use a temp buffer, we just write that npoints value */
		/* to where it belongs*/
		if ( register_npoints )	
			varint_u64_encode_buf(npoints, b_p->buf_start + npoints_offset);
	}
	
	return 0;
}
예제 #25
0
/**

To get the effective area, we have to check what area a point results in when all smaller areas are eliminated
*/
static void tune_areas(EFFECTIVE_AREAS *ea, int avoid_collaps, int set_area, double trshld)
{
	LWDEBUG(2, "Entered  tune_areas");
	const double *P1;
	const double *P2;
	const double *P3;
	double area;
	int go_on=1;
	double check_order_min_area = 0;
	
	int npoints=ea->inpts->npoints;
	int i;
	int current, before_current, after_current;
	
	MINHEAP tree = initiate_minheap(npoints);
	
	int is3d = FLAGS_GET_Z(ea->inpts->flags);
	
	
	/*Add all keys (index in initial_arealist) into minheap array*/
	for (i=0;i<npoints;i++)
	{
		tree.key_array[i]=ea->initial_arealist+i;
		LWDEBUGF(2, "add nr %d, with area %lf, and %lf",i,ea->initial_arealist[i].area, tree.key_array[i]->area );
	}
	tree.usedSize=npoints;
	
	/*order the keys by area, small to big*/	
	qsort(tree.key_array, npoints, sizeof(void*), cmpfunc);
	
	/*We have to put references to our tree in our point-list*/
	for (i=0;i<npoints;i++)
	{
		 ((areanode*) tree.key_array[i])->treeindex=i;
		LWDEBUGF(4,"Check ordering qsort gives, area=%lf and belong to point %d",((areanode*) tree.key_array[i])->area, tree.key_array[i]-ea->initial_arealist);
	}
	/*Ok, now we have a minHeap, just need to keep it*/
	
	/*for (i=0;i<npoints-1;i++)*/
	i=0;
	while (go_on)
	{	
		/*Get a reference to the point with the currently smallest effective area*/
		current=minheap_pop(&tree, ea->initial_arealist)-ea->initial_arealist;
	
		/*We have found the smallest area. That is the resulting effective area for the "current" point*/
		if (i<npoints-avoid_collaps)
			ea->res_arealist[current]=ea->initial_arealist[current].area;
		else
			ea->res_arealist[current]=FLT_MAX;	
		
		if(ea->res_arealist[current]<check_order_min_area)
			lwerror("Oh no, this is a bug. For some reason the minHeap returned our points in the wrong order. Please file a ticket in PostGIS ticket system, or send a mial at the mailing list.Returned area = %lf, and last area = %lf",ea->res_arealist[current],check_order_min_area);
		
		check_order_min_area=ea->res_arealist[current];		
		
		/*The found smallest area point is now regarded as elimnated and we have to recalculate the area the adjacent (ignoring earlier elimnated points) points gives*/
		
		/*FInd point before and after*/
		before_current=ea->initial_arealist[current].prev;
		after_current=ea->initial_arealist[current].next;
		
		P2= (double*)getPoint_internal(ea->inpts, before_current);
		P3= (double*)getPoint_internal(ea->inpts, after_current);
		
		/*Check if point before current point is the first in the point array. */
		if(before_current>0)
		{		
					
			P1= (double*)getPoint_internal(ea->inpts, ea->initial_arealist[before_current].prev);
			if(is3d)
				area=triarea3d(P1, P2, P3);
			else
				area=triarea2d(P1, P2, P3);			
			
			ea->initial_arealist[before_current].area = FP_MAX(area,ea->res_arealist[current]);
			minheap_update(&tree, ea->initial_arealist, ea->initial_arealist[before_current].treeindex);
		}
		if(after_current<npoints-1)/*Check if point after current point is the last in the point array. */
		{
			P1=P2;
			P2=P3;	
			
			P3= (double*)getPoint_internal(ea->inpts, ea->initial_arealist[after_current].next);
			

			if(is3d)
				area=triarea3d(P1, P2, P3);
			else
				area=triarea2d(P1, P2, P3);	
		
				
			ea->initial_arealist[after_current].area = FP_MAX(area,ea->res_arealist[current]);
			minheap_update(&tree, ea->initial_arealist, ea->initial_arealist[after_current].treeindex);
		}
		
		/*rearrange the nodes so the eliminated point will be ingored on the next run*/
		ea->initial_arealist[before_current].next = ea->initial_arealist[current].next;
		ea->initial_arealist[after_current].prev = ea->initial_arealist[current].prev;
		
		/*Check if we are finnished*/
		if((!set_area && ea->res_arealist[current]>trshld) || (ea->initial_arealist[0].next==(npoints-1)))
			go_on=0;
		
		i++;
	};
	destroy_minheap(tree);
	return;	
}
예제 #26
0
/**
* GEOMETRY
* Generic handling for WKB geometries. The front of every WKB geometry
* (including those embedded in collections) is an endian byte, a type
* number and an optional srid number. We handle all those here, then pass
* to the appropriate handler for the specific type.
*/
LWGEOM* lwgeom_from_wkb_state(wkb_parse_state *s)
{
	char wkb_little_endian;
	uint32_t wkb_type;

	LWDEBUG(4,"Entered function");

	/* Fail when handed incorrect starting byte */
	wkb_little_endian = byte_from_wkb_state(s);
	if( wkb_little_endian != 1 && wkb_little_endian != 0 )
	{
		LWDEBUG(4,"Leaving due to bad first byte!");
		lwerror("Invalid endian flag value encountered.");
		return NULL;
	}

	/* Check the endianness of our input  */
	s->swap_bytes = LW_FALSE;
	if( getMachineEndian() == NDR ) /* Machine arch is little */
	{
		if ( ! wkb_little_endian )    /* Data is big! */
			s->swap_bytes = LW_TRUE;
	}
	else                              /* Machine arch is big */
	{
		if ( wkb_little_endian )      /* Data is little! */
			s->swap_bytes = LW_TRUE;
	}

	/* Read the type number */
	wkb_type = integer_from_wkb_state(s);
	LWDEBUGF(4,"Got WKB type number: 0x%X", wkb_type);
	lwtype_from_wkb_state(s, wkb_type);

	/* Read the SRID, if necessary */
	if( s->has_srid )
	{
		s->srid = clamp_srid(integer_from_wkb_state(s));
		/* TODO: warn on explicit UNKNOWN srid ? */
		LWDEBUGF(4,"Got SRID: %u", s->srid);
	}

	/* Do the right thing */
	switch( s->lwtype )
	{
		case POINTTYPE:
			return (LWGEOM*)lwpoint_from_wkb_state(s);
			break;
		case LINETYPE:
			return (LWGEOM*)lwline_from_wkb_state(s);
			break;
		case CIRCSTRINGTYPE:
			return (LWGEOM*)lwcircstring_from_wkb_state(s);
			break;
		case POLYGONTYPE:
			return (LWGEOM*)lwpoly_from_wkb_state(s);
			break;
		case TRIANGLETYPE:
			return (LWGEOM*)lwtriangle_from_wkb_state(s);
			break;
		case CURVEPOLYTYPE:
			return (LWGEOM*)lwcurvepoly_from_wkb_state(s);
			break;
		case MULTIPOINTTYPE:
		case MULTILINETYPE:
		case MULTIPOLYGONTYPE:
		case COMPOUNDTYPE:
		case MULTICURVETYPE:
		case MULTISURFACETYPE:
		case POLYHEDRALSURFACETYPE:
		case TINTYPE:
		case COLLECTIONTYPE:
			return (LWGEOM*)lwcollection_from_wkb_state(s);
			break;

		/* Unknown type! */
		default:
			lwerror("Unsupported geometry type: %s [%d]", lwtype_name(s->lwtype), s->lwtype);
	}

	/* Return value to keep compiler happy. */
	return NULL;

}
예제 #27
0
/**
 * @brief returns 0 for points, 1 for lines, 2 for polygons.
 * 			returns max dimension for a collection.
 * 		returns -1 for the empty geometry (TODO)
 * 		returns -2 on error
 */
static int32
lwgeom_dimension_recursive(const uchar *serialized)
{
	LWGEOM_INSPECTED *inspected;
	int ret = -1;
	int i;

	/** @todo
	 * 		This has the unfortunate habit of traversing the CURVEPOLYTYPe
	 * 		geoms and returning 1, as all contained geoms are linear.
	 * 		Here we preempt this problem.
	 * 		TODO: This should handle things a bit better.  Only
	 * 		GEOMETRYCOLLECTION should ever need to be traversed.
	 */
	if (lwgeom_getType(serialized[0]) == CURVEPOLYTYPE) return 2;

	inspected = lwgeom_inspect(serialized);
	for (i=0; i<inspected->ngeometries; i++)
	{
		uchar *subgeom;
		char typeflags = lwgeom_getsubtype_inspected(inspected, i);
		int type = lwgeom_getType(typeflags);
		int dims=-1;

		LWDEBUGF(3, "lwgeom_dimension_recursive: type %d", type);

		if ( type == POINTTYPE ) dims = 0;
		else if ( type == MULTIPOINTTYPE ) dims=0;
		else if ( type == LINETYPE ) dims=1;
		else if ( type == CIRCSTRINGTYPE ) dims=1;
		else if ( type == COMPOUNDTYPE ) dims=1;
		else if ( type == MULTILINETYPE ) dims=1;
		else if ( type == MULTICURVETYPE ) dims=1;
		else if ( type == POLYGONTYPE ) dims=2;
		else if ( type == CURVEPOLYTYPE ) dims=2;
		else if ( type == MULTIPOLYGONTYPE ) dims=2;
		else if ( type == MULTISURFACETYPE ) dims=2;
		else if ( type == COLLECTIONTYPE )
		{
			subgeom = lwgeom_getsubgeometry_inspected(inspected, i);
			if ( subgeom == NULL )
			{
				lwinspected_release(inspected);
				return -2;
			}

			dims = lwgeom_dimension_recursive(subgeom);
		}

		if ( dims == 2 )
		{ /* nothing can be higher */
			lwinspected_release(inspected);
			return 2;
		}
		if ( dims > ret ) ret = dims;
	}

	lwinspected_release(inspected);

	return ret;
}
예제 #28
0
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);
}
예제 #29
0
int
lwline_split_by_point_to(const LWLINE* lwline_in, const LWPOINT* blade_in,
                         LWMLINE* v)
{
	double mindist = -1;
	POINT4D pt, pt_projected;
	POINT4D p1, p2;
	POINTARRAY *ipa = lwline_in->points;
	POINTARRAY* pa1;
	POINTARRAY* pa2;
	int i, nsegs, seg = -1;

	/* Possible outcomes:
	 *
	 *  1. The point is not on the line or on the boundary
	 *      -> Leave collection untouched, return 0
	 *  2. The point is on the boundary
	 *      -> Leave collection untouched, return 1
	 *  3. The point is in the line
	 *      -> Push 2 elements on the collection:
	 *         o start_point - cut_point
	 *         o cut_point - last_point
	 *      -> Return 2
	 */

	getPoint4d_p(blade_in->point, 0, &pt);

	/* Find closest segment */
	getPoint4d_p(ipa, 0, &p1);
	nsegs = ipa->npoints - 1;
	for ( i = 0; i < nsegs; i++ )
	{
		getPoint4d_p(ipa, i+1, &p2);
		double dist;
		dist = distance2d_pt_seg((POINT2D*)&pt, (POINT2D*)&p1, (POINT2D*)&p2);
		LWDEBUGF(4, " Distance of point %g %g to segment %g %g, %g %g: %g", pt.x, pt.y, p1.x, p1.y, p2.x, p2.y, dist);
		if (i==0 || dist < mindist )
		{
			mindist = dist;
			seg=i;
			if ( mindist == 0.0 ) break; /* can't be closer than ON line */
		}
		p1 = p2;
	}

	LWDEBUGF(3, "Closest segment: %d", seg);
	LWDEBUGF(3, "mindist: %g", mindist);

	/* No intersection */
	if ( mindist > 0 ) return 0;

	/* empty or single-point line, intersection on boundary */
	if ( seg < 0 ) return 1;

	/*
	 * We need to project the
	 * point on the closest segment,
	 * to interpolate Z and M if needed
	 */
	getPoint4d_p(ipa, seg, &p1);
	getPoint4d_p(ipa, seg+1, &p2);
	closest_point_on_segment(&pt, &p1, &p2, &pt_projected);
	/* But X and Y we want the ones of the input point,
	 * as on some architectures the interpolation math moves the
	 * coordinates (see #3422)
	 */
	pt_projected.x = pt.x;
	pt_projected.y = pt.y;

	LWDEBUGF(3, "Projected point:(%g %g), seg:%d, p1:(%g %g), p2:(%g %g)", pt_projected.x, pt_projected.y, seg, p1.x, p1.y, p2.x, p2.y);

	/* When closest point == an endpoint, this is a boundary intersection */
	if ( ( (seg == nsegs-1) && p4d_same(&pt_projected, &p2) ) ||
	     ( (seg == 0)       && p4d_same(&pt_projected, &p1) ) )
	{
		return 1;
	}

	/* This is an internal intersection, let's build the two new pointarrays */

	pa1 = ptarray_construct_empty(FLAGS_GET_Z(ipa->flags), FLAGS_GET_M(ipa->flags), seg+2);
	/* TODO: replace with a memcpy ? */
	for (i=0; i<=seg; ++i)
	{
		getPoint4d_p(ipa, i, &p1);
		ptarray_append_point(pa1, &p1, LW_FALSE);
	}
	ptarray_append_point(pa1, &pt_projected, LW_FALSE);

	pa2 = ptarray_construct_empty(FLAGS_GET_Z(ipa->flags), FLAGS_GET_M(ipa->flags), ipa->npoints-seg);
	ptarray_append_point(pa2, &pt_projected, LW_FALSE);
	/* TODO: replace with a memcpy (if so need to check for duplicated point) ? */
	for (i=seg+1; i<ipa->npoints; ++i)
	{
		getPoint4d_p(ipa, i, &p1);
		ptarray_append_point(pa2, &p1, LW_FALSE);
	}

	/* NOTE: I've seen empty pointarrays with loc != 0 and loc != 1 */
	if ( pa1->npoints == 0 || pa2->npoints == 0 ) {
		ptarray_free(pa1);
		ptarray_free(pa2);
		/* Intersection is on the boundary */
		return 1;
	}

	lwmline_add_lwline(v, lwline_construct(SRID_UNKNOWN, NULL, pa1));
	lwmline_add_lwline(v, lwline_construct(SRID_UNKNOWN, NULL, pa2));
	return 2;
}
예제 #30
0
파일: ptarray.c 프로젝트: gbroccolo/postgis
/*
 * 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;
}