Exemple #1
0
void lwtriangle_free(LWTRIANGLE  *triangle)
{
	if ( ! triangle ) return;
	
	if (triangle->bbox)
		lwfree(triangle->bbox);
		
	if (triangle->points)
		ptarray_free(triangle->points);
		
	lwfree(triangle);
}
Exemple #2
0
char
lwtriangle_is_repeated_points(LWTRIANGLE *triangle)
{
	char ret;
	POINTARRAY *pa;

	pa = ptarray_remove_repeated_points(triangle->points);
	ret = ptarray_same(pa, triangle->points);
	ptarray_free(pa);

	return ret;
}
Exemple #3
0
/*
 * @param icurve input curve
 * @param tol tolerance, semantic driven by tolerance_type
 * @param tolerance_type see LW_LINEARIZE_TOLERANCE_TYPE
 * @param flags see flags in lwarc_linearize
 *
 * @return a newly allocated LWLINE
 */
static LWLINE *
lwcircstring_linearize(const LWCIRCSTRING *icurve, double tol,
                        LW_LINEARIZE_TOLERANCE_TYPE tolerance_type,
                        int flags)
{
	LWLINE *oline;
	POINTARRAY *ptarray;
	uint32_t i, j;
	POINT4D p1, p2, p3, p4;
	int ret;

	LWDEBUGF(2, "lwcircstring_linearize called., dim = %d", icurve->points->flags);

	ptarray = ptarray_construct_empty(FLAGS_GET_Z(icurve->points->flags), FLAGS_GET_M(icurve->points->flags), 64);

	for (i = 2; i < icurve->points->npoints; i+=2)
	{
		LWDEBUGF(3, "lwcircstring_linearize: arc ending at point %d", i);

		getPoint4d_p(icurve->points, i - 2, &p1);
		getPoint4d_p(icurve->points, i - 1, &p2);
		getPoint4d_p(icurve->points, i, &p3);

		ret = lwarc_linearize(ptarray, &p1, &p2, &p3, tol, tolerance_type, flags);
		if ( ret > 0 )
		{
			LWDEBUGF(3, "lwcircstring_linearize: generated %d points", ptarray->npoints);
		}
		else if ( ret == 0 )
		{
			LWDEBUG(3, "lwcircstring_linearize: points are colinear, returning curve points as line");

			for (j = i - 2 ; j < i ; j++)
			{
				getPoint4d_p(icurve->points, j, &p4);
				ptarray_append_point(ptarray, &p4, LW_TRUE);
			}
		}
		else
		{
			/* An error occurred, lwerror should have been called by now */
			ptarray_free(ptarray);
			return NULL;
		}
	}
	getPoint4d_p(icurve->points, icurve->points->npoints-1, &p1);
	ptarray_append_point(ptarray, &p1, LW_TRUE);

	oline = lwline_construct(icurve->srid, NULL, ptarray);
	return oline;
}
Exemple #4
0
LWLINE *
lwcircstring_segmentize(const LWCIRCSTRING *icurve, uint32_t perQuad)
{
	LWLINE *oline;
	POINTARRAY *ptarray;
	POINTARRAY *tmp;
	uint32_t i, j;
	POINT4D p1, p2, p3, p4;

	LWDEBUGF(2, "lwcircstring_segmentize called., dim = %d", icurve->points->flags);

	ptarray = ptarray_construct_empty(FLAGS_GET_Z(icurve->points->flags), FLAGS_GET_M(icurve->points->flags), 64);

	for (i = 2; i < icurve->points->npoints; i+=2)
	{
		LWDEBUGF(3, "lwcircstring_segmentize: arc ending at point %d", i);

		getPoint4d_p(icurve->points, i - 2, &p1);
		getPoint4d_p(icurve->points, i - 1, &p2);
		getPoint4d_p(icurve->points, i, &p3);
		tmp = lwcircle_segmentize(&p1, &p2, &p3, perQuad);

		if (tmp)
		{
			LWDEBUGF(3, "lwcircstring_segmentize: generated %d points", tmp->npoints);

			for (j = 0; j < tmp->npoints; j++)
			{
				getPoint4d_p(tmp, j, &p4);
				ptarray_append_point(ptarray, &p4, LW_TRUE);
			}
			ptarray_free(tmp);
		}
		else
		{
			LWDEBUG(3, "lwcircstring_segmentize: points are colinear, returning curve points as line");

			for (j = i - 1 ; j <= i ; j++)
			{
				getPoint4d_p(icurve->points, j, &p4);
				ptarray_append_point(ptarray, &p4, LW_TRUE);
			}
		}

	}
	getPoint4d_p(icurve->points, icurve->points->npoints-1, &p1);
	ptarray_append_point(ptarray, &p1, LW_TRUE);
		
	oline = lwline_construct(icurve->srid, NULL, ptarray);
	return oline;
}
Exemple #5
0
/**
* TRIANGLE
* Read a WKB triangle, starting just after the endian byte, 
* type number and optional srid number. Advance the parse state 
* forward appropriately. 
* Triangles are encoded like polygons in WKB, but more like linestrings
* as lwgeometries.
*/
static LWTRIANGLE* lwtriangle_from_wkb_state(wkb_parse_state *s)
{
	uint32_t nrings = integer_from_wkb_state(s);
	LWTRIANGLE *tri = lwtriangle_construct_empty(s->srid, s->has_z, s->has_m);
	POINTARRAY *pa = NULL;

	/* Empty triangle? */
	if( nrings == 0 )
		return tri;

	/* Should be only one ring. */
	if ( nrings != 1 )
		lwerror("Triangle has wrong number of rings: %d", nrings);

	/* There's only one ring, we hope? */	
	pa = ptarray_from_wkb_state(s);

	/* If there's no points, return an empty triangle. */
	if( pa == NULL )
		return tri;

	/* Check for at least four points. */
	if( s->check & LW_PARSER_CHECK_MINPOINTS && pa->npoints < 4 )
	{
		LWDEBUGF(2, "%s must have at least four points", lwtype_name(s->lwtype));
		lwerror("%s must have at least four points", lwtype_name(s->lwtype));
		return NULL;
	}

	if( s->check & LW_PARSER_CHECK_CLOSURE && ! ptarray_is_closed(pa) )
	{
		lwerror("%s must have closed rings", lwtype_name(s->lwtype));
		return NULL;
	}

	if( s->check & LW_PARSER_CHECK_ZCLOSURE && ! ptarray_is_closed_z(pa) )
	{
		lwerror("%s must have closed rings", lwtype_name(s->lwtype));
		return NULL;
	}

	/* Empty TRIANGLE starts w/ empty POINTARRAY, free it first */
	if (tri->points)
		ptarray_free(tri->points);
	
	tri->points = pa;	
	return tri;
}
Exemple #6
0
/*
 * @param icompound input compound curve
 * @param tol tolerance, semantic driven by tolerance_type
 * @param tolerance_type see LW_LINEARIZE_TOLERANCE_TYPE
 * @param flags see flags in lwarc_linearize
 *
 * @return a newly allocated LWLINE
 */
static LWLINE *
lwcompound_linearize(const LWCOMPOUND *icompound, double tol,
                      LW_LINEARIZE_TOLERANCE_TYPE tolerance_type,
                      int flags)
{
	LWGEOM *geom;
	POINTARRAY *ptarray = NULL, *ptarray_out = NULL;
	LWLINE *tmp = NULL;
	uint32_t i, j;
	POINT4D p;

	LWDEBUG(2, "lwcompound_stroke called.");

	ptarray = ptarray_construct_empty(FLAGS_GET_Z(icompound->flags), FLAGS_GET_M(icompound->flags), 64);

	for (i = 0; i < icompound->ngeoms; i++)
	{
		geom = icompound->geoms[i];
		if (geom->type == CIRCSTRINGTYPE)
		{
			tmp = lwcircstring_linearize((LWCIRCSTRING *)geom, tol, tolerance_type, flags);
			for (j = 0; j < tmp->points->npoints; j++)
			{
				getPoint4d_p(tmp->points, j, &p);
				ptarray_append_point(ptarray, &p, LW_TRUE);
			}
			lwline_free(tmp);
		}
		else if (geom->type == LINETYPE)
		{
			tmp = (LWLINE *)geom;
			for (j = 0; j < tmp->points->npoints; j++)
			{
				getPoint4d_p(tmp->points, j, &p);
				ptarray_append_point(ptarray, &p, LW_TRUE);
			}
		}
		else
		{
			lwerror("Unsupported geometry type %d found.",
			        geom->type, lwtype_name(geom->type));
			return NULL;
		}
	}
	ptarray_out = ptarray_remove_repeated_points(ptarray, 0.0);
	ptarray_free(ptarray);
	return lwline_construct(icompound->srid, NULL, ptarray_out);
}
Exemple #7
0
/**
* POINT
* Read a WKB point, starting just after the endian byte,
* type number and optional srid number.
* Advance the parse state forward appropriately.
* WKB point has just a set of doubles, with the quantity depending on the
* dimension of the point, so this looks like a special case of the above
* with only one point.
*/
static LWPOINT* lwpoint_from_wkb_state(wkb_parse_state *s)
{
	static uint32_t npoints = 1;
	POINTARRAY *pa = NULL;
	size_t pa_size;
	uint32_t ndims = 2;
	const POINT2D *pt;

	/* Count the dimensions. */
	if( s->has_z ) ndims++;
	if( s->has_m ) ndims++;
	pa_size = ndims * WKB_DOUBLE_SIZE;

	/* Does the data we want to read exist? */
	wkb_parse_state_check(s, pa_size);

	/* If we're in a native endianness, we can just copy the data directly! */
	if( ! s->swap_bytes )
	{
		pa = ptarray_construct_copy_data(s->has_z, s->has_m, npoints, (uint8_t*)s->pos);
		s->pos += pa_size;
	}
	/* Otherwise we have to read each double, separately */
	else
	{
		int i = 0;
		double *dlist;
		pa = ptarray_construct(s->has_z, s->has_m, npoints);
		dlist = (double*)(pa->serialized_pointlist);
		for( i = 0; i < ndims; i++ )
		{
			dlist[i] = double_from_wkb_state(s);
		}
	}

	/* Check for POINT(NaN NaN) ==> POINT EMPTY */
	pt = getPoint2d_cp(pa, 0);
	if ( isnan(pt->x) && isnan(pt->y) )
	{
		ptarray_free(pa);
		return lwpoint_construct_empty(s->srid, s->has_z, s->has_m);
	}
	else
	{
		return lwpoint_construct(s->srid, NULL, pa);
	}
}
Exemple #8
0
/**
* LINESTRING
* Read a WKB linestring, starting just after the endian byte,
* type number and optional srid number. Advance the parse state
* forward appropriately.
* There is only one pointarray in a linestring. Optionally
* check for minimal following of rules (two point minimum).
*/
static LWLINE* lwline_from_wkb_state(wkb_parse_state *s)
{
	POINTARRAY *pa = ptarray_from_wkb_state(s);

	if( pa == NULL || pa->npoints == 0 )
	{
		ptarray_free(pa);
		return lwline_construct_empty(s->srid, s->has_z, s->has_m);
	}

	if( s->check & LW_PARSER_CHECK_MINPOINTS && pa->npoints < 2 )
	{
		lwerror("%s must have at least two points", lwtype_name(s->lwtype));
		return NULL;
	}

	return lwline_construct(s->srid, NULL, pa);
}
Exemple #9
0
LWPOLY *
lwpoly_segmentize2d(LWPOLY *poly, double dist)
{
	POINTARRAY **newrings;
	uint32_t i;

	newrings = lwalloc(sizeof(POINTARRAY *)*poly->nrings);
	for (i=0; i<poly->nrings; i++)
	{
		newrings[i] = ptarray_segmentize2d(poly->rings[i], dist);
		if ( ! newrings[i] ) {
			while (i--) ptarray_free(newrings[i]);
			lwfree(newrings);
			return NULL;
		}
	}
	return lwpoly_construct(poly->srid, NULL,
	                        poly->nrings, newrings);
}
Exemple #10
0
void lwpoly_free(LWPOLY  *poly)
{
	int t;

	if( ! poly ) return;

	if ( poly->bbox )
		lwfree(poly->bbox);

	for (t=0; t<poly->nrings; t++)
	{
		if ( poly->rings[t] )
			ptarray_free(poly->rings[t]);
	}

	if ( poly->rings )
		lwfree(poly->rings);

	lwfree(poly);
}
Exemple #11
0
LWPOLY* lwpoly_simplify(const LWPOLY *ipoly, double dist)
{
	int i;
	LWPOLY *opoly = lwpoly_construct_empty(ipoly->srid, FLAGS_GET_Z(ipoly->flags), FLAGS_GET_M(ipoly->flags));

	LWDEBUGF(2, "simplify_polygon3d: simplifying polygon with %d rings", ipoly->nrings);

	if( lwpoly_is_empty(ipoly) )
		return opoly; /* should we return NULL instead ? */

	for (i = 0; i < ipoly->nrings; i++)
	{
		static const int minvertices = 0; /* TODO: allow setting this */
		POINTARRAY *opts = ptarray_simplify(ipoly->rings[i], dist, minvertices);

		LWDEBUGF(3, "ring%d simplified from %d to %d points", i, ipoly->rings[i]->npoints, opts->npoints);

		/* Less points than are needed to form a closed ring, we can't use this */
		if ( opts->npoints < 4 )
		{
			LWDEBUGF(3, "ring%d skipped (% pts)", i, opts->npoints);
			ptarray_free(opts);
			if ( i ) continue;
			else break; /* Don't scan holes if shell is collapsed */
		}

		/* Add ring to simplified polygon */
		if( lwpoly_add_ring(opoly, opts) == LW_FAILURE )
			return NULL;
	}

	LWDEBUGF(3, "simplified polygon with %d rings", ipoly->nrings);
	opoly->type = ipoly->type;

	if( lwpoly_is_empty(opoly) )
		return NULL;

	return opoly;
}
Exemple #12
0
/*
 * Free a tgeom struct
 * and even the geometries inside
 */
void
tgeom_free(TGEOM *tgeom)
{
	int i, j;

	assert(tgeom);

	/* bbox */
	if (tgeom->bbox) lwfree(tgeom->bbox);

	/* edges */
	for (i=1 ; i <= tgeom->nedges ; i++)
	{
		lwfree(tgeom->edges[i]->e);
		lwfree(tgeom->edges[i]->s);
		lwfree(tgeom->edges[i]);
	}
	if (tgeom->edges) lwfree(tgeom->edges);

	/* faces */
	for (i=0 ; i < tgeom->nfaces ; i++)
	{
		/* edges array */
		if (tgeom->faces[i]->edges)
			lwfree(tgeom->faces[i]->edges);

		/* rings */
		for (j=0 ; j < tgeom->faces[i]->nrings ; j++)
			ptarray_free(tgeom->faces[i]->rings[j]);
		if (tgeom->faces[i]->rings)
			lwfree(tgeom->faces[i]->rings);

		lwfree(tgeom->faces[i]);
	}
	if (tgeom->faces) lwfree(tgeom->faces);

	lwfree(tgeom);
}
static LWMPOINT*
lwline_locate_along(const LWLINE *lwline, double m, double offset)
{
	POINTARRAY *opa = NULL;
	LWMPOINT *mp = NULL;
	LWGEOM *lwg = lwline_as_lwgeom(lwline);
	int hasz, hasm, srid;

	/* Return degenerates upwards */
	if ( ! lwline ) return NULL;
	
	/* Create empty return shell */
	srid = lwgeom_get_srid(lwg);
	hasz = lwgeom_has_z(lwg);
	hasm = lwgeom_has_m(lwg);

	if ( hasm )
	{
		/* Find points along */
		opa = ptarray_locate_along(lwline->points, m, offset);
	}
	else 
	{
		LWLINE *lwline_measured = lwline_measured_from_lwline(lwline, 0.0, 1.0);
		opa = ptarray_locate_along(lwline_measured->points, m, offset);
		lwline_free(lwline_measured);
	}

	/* Return NULL as EMPTY */
	if ( ! opa ) 
		return lwmpoint_construct_empty(srid, hasz, hasm);
	
	/* Convert pointarray into a multipoint */
	mp = lwmpoint_construct(srid, opa);
	ptarray_free(opa);
	return mp;
}
Exemple #14
0
/**
 * @brief Returns a modified #POINTARRAY so that no segment is
 * 		longer than the given distance (computed using 2d).
 *
 * Every input point is kept.
 * Z and M values for added points (if needed) are set to 0.
 */
POINTARRAY *
ptarray_segmentize2d(const POINTARRAY *ipa, double dist)
{
	double	segdist;
	POINT4D	p1, p2;
	POINT4D pbuf;
	POINTARRAY *opa;
	int ipoff=0; /* input point offset */
	int hasz = FLAGS_GET_Z(ipa->flags);
	int hasm = FLAGS_GET_M(ipa->flags);

	pbuf.x = pbuf.y = pbuf.z = pbuf.m = 0;

	/* Initial storage */
	opa = ptarray_construct_empty(hasz, hasm, ipa->npoints);
	
	/* Add first point */
	getPoint4d_p(ipa, ipoff, &p1);
	ptarray_append_point(opa, &p1, LW_FALSE);

	ipoff++;

	while (ipoff<ipa->npoints)
	{
		/*
		 * We use these pointers to avoid
		 * "strict-aliasing rules break" warning raised
		 * by gcc (3.3 and up).
		 *
		 * It looks that casting a variable address (also
		 * referred to as "type-punned pointer")
		 * breaks those "strict" rules.
		 *
		 */
		POINT4D *p1ptr=&p1, *p2ptr=&p2;

		getPoint4d_p(ipa, ipoff, &p2);

		segdist = distance2d_pt_pt((POINT2D *)p1ptr, (POINT2D *)p2ptr);

		if (segdist > dist) /* add an intermediate point */
		{
			pbuf.x = p1.x + (p2.x-p1.x)/segdist * dist;
			pbuf.y = p1.y + (p2.y-p1.y)/segdist * dist;
			if( hasz ) 
				pbuf.z = p1.z + (p2.z-p1.z)/segdist * dist;
			if( hasm )
				pbuf.m = p1.m + (p2.m-p1.m)/segdist * dist;
			ptarray_append_point(opa, &pbuf, LW_FALSE);
			p1 = pbuf;
		}
		else /* copy second point */
		{
			ptarray_append_point(opa, &p2, (ipa->npoints==2)?LW_TRUE:LW_FALSE);
			p1 = p2;
			ipoff++;
		}

		LW_ON_INTERRUPT(ptarray_free(opa); return NULL);
	}

	return opa;
}
Exemple #15
0
/**
 * Segmentize an arc
 *
 * Does not add the final vertex
 *
 * @param to POINTARRAY to append segmentized vertices to
 * @param p1 first point defining the arc
 * @param p2 second point defining the arc
 * @param p3 third point defining the arc
 * @param tol tolerance, semantic driven by tolerance_type
 * @param tolerance_type see LW_LINEARIZE_TOLERANCE_TYPE
 * @param flags LW_LINEARIZE_FLAGS
 *
 * @return number of points appended (0 if collinear),
 *         or -1 on error (lwerror would be called).
 *
 */
static int
lwarc_linearize(POINTARRAY *to,
                 const POINT4D *p1, const POINT4D *p2, const POINT4D *p3,
                 double tol, LW_LINEARIZE_TOLERANCE_TYPE tolerance_type,
                 int flags)
{
	POINT2D center;
	POINT2D *t1 = (POINT2D*)p1;
	POINT2D *t2 = (POINT2D*)p2;
	POINT2D *t3 = (POINT2D*)p3;
	POINT4D pt;
	int p2_side = 0;
	int clockwise = LW_TRUE;
	double radius; /* Arc radius */
	double increment; /* Angle per segment */
	double angle_shift = 0;
	double a1, a2, a3, angle;
	POINTARRAY *pa = to;
	int is_circle = LW_FALSE;
	int points_added = 0;
	int reverse = 0;

	LWDEBUG(2, "lwarc_linearize called.");

	p2_side = lw_segment_side(t1, t3, t2);

	/* Force counterclockwise scan if SYMMETRIC operation is requsested */
	if ( p2_side == -1 && flags & LW_LINEARIZE_FLAG_SYMMETRIC )
	{
		/* swap p1-p3 */
		t1 = (POINT2D*)p3;
		t3 = (POINT2D*)p1;
		p1 = (POINT4D*)t1;
		p3 = (POINT4D*)t3;
		p2_side = 1;
		reverse = 1;
	}

	radius = lw_arc_center(t1, t2, t3, &center);
	LWDEBUGF(2, " center is POINT(%.15g %.15g) - radius:%g", center.x, center.y, radius);

	/* Matched start/end points imply circle */
	if ( p1->x == p3->x && p1->y == p3->y )
		is_circle = LW_TRUE;

	/* Negative radius signals straight line, p1/p2/p3 are colinear */
	if ( (radius < 0.0 || p2_side == 0) && ! is_circle )
	    return 0;

	/* The side of the p1/p3 line that p2 falls on dictates the sweep
	   direction from p1 to p3. */
	if ( p2_side == -1 )
		clockwise = LW_TRUE;
	else
		clockwise = LW_FALSE;

	if ( tolerance_type == LW_LINEARIZE_TOLERANCE_TYPE_SEGS_PER_QUAD )
	{{
		int perQuad = rint(tol);
		// error out if tol != perQuad ? (not-round)
		if ( perQuad != tol )
		{
			lwerror("lwarc_linearize: segments per quadrant must be an integer value, got %.15g", tol, perQuad);
			return -1;
		}
		if ( perQuad < 1 )
		{
			lwerror("lwarc_linearize: segments per quadrant must be at least 1, got %d", perQuad);
			return -1;
		}
		increment = fabs(M_PI_2 / perQuad);
		LWDEBUGF(2, "lwarc_linearize: perQuad:%d, increment:%g (%g degrees)", perQuad, increment, increment*180/M_PI);

	}}
	else if ( tolerance_type == LW_LINEARIZE_TOLERANCE_TYPE_MAX_DEVIATION )
	{{
		double halfAngle;
		if ( tol <= 0 )
		{
			lwerror("lwarc_linearize: max deviation must be bigger than 0, got %.15g", tol);
			return -1;
		}
		halfAngle = acos( -tol / radius + 1 );
		increment = 2 * halfAngle;
		LWDEBUGF(2, "lwarc_linearize: maxDiff:%g, radius:%g, halfAngle:%g, increment:%g (%g degrees)", tol, radius, halfAngle, increment, increment*180/M_PI);
	}}
	else if ( tolerance_type == LW_LINEARIZE_TOLERANCE_TYPE_MAX_ANGLE )
	{
		increment = tol;
		if ( increment <= 0 )
		{
			lwerror("lwarc_linearize: max angle must be bigger than 0, got %.15g", tol);
			return -1;
		}
	}
	else
	{
		lwerror("lwarc_linearize: unsupported tolerance type %d", tolerance_type);
		return LW_FALSE;
	}

	/* Angles of each point that defines the arc section */
	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);

	LWDEBUGF(2, "lwarc_linearize A1:%g (%g) A2:%g (%g) A3:%g (%g)",
		a1, a1*180/M_PI, a2, a2*180/M_PI, a3, a3*180/M_PI);

	if ( flags & LW_LINEARIZE_FLAG_SYMMETRIC )
	{{
		/* Calculate total arc angle, in radians */
		double angle = clockwise ? a1 - a3 : a3 - a1;
		if ( angle < 0 ) angle += M_PI * 2;
		LWDEBUGF(2, "lwarc_linearize SYMMETRIC requested - total angle %g deg",
			         angle * 180 / M_PI);
		if ( flags & LW_LINEARIZE_FLAG_RETAIN_ANGLE )
		{{
			/* Number of steps */
			int steps = trunc(angle / increment);
			/* Angle reminder */
			double angle_reminder = angle - ( increment * steps );
			angle_shift = angle_reminder / 2.0;

			LWDEBUGF(2, "lwarc_linearize RETAIN_ANGLE operation requested - "
			         "total angle %g, steps %d, increment %g, reminder %g",
			         angle * 180 / M_PI, steps, increment * 180 / M_PI,
			         angle_reminder * 180 / M_PI);
		}}
		else
		{{
			/* Number of segments in output */
			int segs = ceil(angle / increment);
			/* Tweak increment to be regular for all the arc */
			increment = angle/segs;

			LWDEBUGF(2, "lwarc_linearize SYMMETRIC operation requested - "
							"total angle %g degrees - LINESTRING(%g %g,%g %g,%g %g) - S:%d -   I:%g",
							angle*180/M_PI, p1->x, p1->y, center.x, center.y, p3->x, p3->y,
							segs, increment*180/M_PI);
		}}
	}}

	/* p2 on left side => clockwise sweep */
	if ( clockwise )
	{
		LWDEBUG(2, " Clockwise sweep");
		increment *= -1;
		angle_shift *= -1;
		/* Adjust a3 down so we can decrement from a1 to a3 cleanly */
		if ( a3 > a1 )
			a3 -= 2.0 * M_PI;
		if ( a2 > a1 )
			a2 -= 2.0 * M_PI;
	}
	/* p2 on right side => counter-clockwise sweep */
	else
	{
		LWDEBUG(2, " Counterclockwise sweep");
		/* Adjust a3 up so we can increment from a1 to a3 cleanly */
		if ( a3 < a1 )
			a3 += 2.0 * M_PI;
		if ( a2 < a1 )
			a2 += 2.0 * M_PI;
	}

	/* Override angles for circle case */
	if( is_circle )
	{
		a3 = a1 + 2.0 * M_PI;
		a2 = a1 + M_PI;
		increment = fabs(increment);
		clockwise = LW_FALSE;
	}

	LWDEBUGF(2, "lwarc_linearize angle_shift:%g, increment:%g",
		angle_shift * 180/M_PI, increment * 180/M_PI);

	if ( reverse ) {{
		const int capacity = 8; /* TODO: compute exactly ? */
		pa = ptarray_construct_empty(ptarray_has_z(to), ptarray_has_m(to), capacity);
	}}

	/* Sweep from a1 to a3 */
	if ( ! reverse )
	{
		ptarray_append_point(pa, p1, LW_FALSE);
	}
	++points_added;
	if ( angle_shift ) angle_shift -= increment;
	LWDEBUGF(2, "a1:%g (%g deg), a3:%g (%g deg), inc:%g, shi:%g, cw:%d",
		a1, a1 * 180 / M_PI, a3, a3 * 180 / M_PI, increment, angle_shift, clockwise);
	for ( angle = a1 + increment + angle_shift; clockwise ? angle > a3 : angle < a3; angle += increment )
	{
		LWDEBUGF(2, " SA: %g ( %g deg )", angle, angle*180/M_PI);
		pt.x = center.x + radius * cos(angle);
		pt.y = center.y + radius * sin(angle);
		pt.z = interpolate_arc(angle, a1, a2, a3, p1->z, p2->z, p3->z);
		pt.m = interpolate_arc(angle, a1, a2, a3, p1->m, p2->m, p3->m);
		ptarray_append_point(pa, &pt, LW_FALSE);
		++points_added;
		angle_shift = 0;
	}

	if ( reverse ) {{
		int i;
		ptarray_append_point(to, p3, LW_FALSE);
		for ( i=pa->npoints; i>0; i-- ) {
			getPoint4d_p(pa, i-1, &pt);
			ptarray_append_point(to, &pt, LW_FALSE);
		}
		ptarray_free(pa);
	}}

	return points_added;
}
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;
}
Exemple #17
0
void lwpoint_free(LWPOINT *pt)
{
	if(pt->point)
		ptarray_free(pt->point);
	lwfree(pt);
}
int
lwline_split_by_point_to(const LWLINE* lwline_in, const LWPOINT* blade_in,
                         LWMLINE* v)
{
	double loc, dist;
	POINT4D pt, pt_projected;
	POINTARRAY* pa1;
	POINTARRAY* pa2;
	double vstol; /* vertex snap tolerance */

	/* 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
	 *      -> Push 1 element on the collection:
	 *         o the original line
	 *      -> 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);
	loc = ptarray_locate_point(lwline_in->points, &pt, &dist, &pt_projected);

	/* lwnotice("Location: %g -- Distance: %g", loc, dist); */

	if ( dist > 0 )   /* TODO: accept a tolerance ? */
	{
		/* No intersection */
		return 0;
	}

	if ( loc == 0 || loc == 1 )
	{
		/* Intersection is on the boundary */
		return 1;
	}

	/* There is a real intersection, let's get two substrings */

	/* Compute vertex snap tolerance based on line length
	 * TODO: take as parameter ? */
	vstol = ptarray_length_2d(lwline_in->points) / 1e14;

	pa1 = ptarray_substring(lwline_in->points, 0, loc, vstol);
	pa2 = ptarray_substring(lwline_in->points, loc, 1, vstol);

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