Exemple #1
0
int gbox_union(const GBOX *g1, const GBOX *g2, GBOX *gout)
{
	if ( ( ! g1 ) && ( ! g2 ) )
		return LW_FALSE;

	if  ( ! g1 )
	{
		memcpy(gout, g2, sizeof(GBOX));
		return LW_TRUE;
	}
	if ( ! g2 )
	{
		memcpy(gout, g1, sizeof(GBOX));
		return LW_TRUE;
	}
	
	gout->flags = g1->flags;

	gout->xmin = FP_MIN(g1->xmin, g2->xmin);
	gout->xmax = FP_MAX(g1->xmax, g2->xmax);

	gout->ymin = FP_MIN(g1->ymin, g2->ymin);
	gout->ymax = FP_MAX(g1->ymax, g2->ymax);
	
	gout->zmin = FP_MIN(g1->zmin, g2->zmin);
	gout->zmax = FP_MAX(g1->zmax, g2->zmax);

	return LW_TRUE;
}
Exemple #2
0
static int lw_arc_calculate_gbox_cartesian(const POINT4D *p1, const POINT4D *p2, const POINT4D *p3, GBOX *gbox)
{
	int rv;

	LWDEBUG(2, "lw_arc_calculate_gbox_cartesian called.");

	rv = lw_arc_calculate_gbox_cartesian_2d((POINT2D*)p1, (POINT2D*)p2, (POINT2D*)p3, gbox);
    gbox->zmin = FP_MIN(p1->z, p3->z);
    gbox->mmin = FP_MIN(p1->m, p3->m);
    gbox->zmax = FP_MAX(p1->z, p3->z);
    gbox->mmax = FP_MAX(p1->m, p3->m);
	return rv;
}
Exemple #3
0
int ptarray_calculate_gbox_cartesian(const POINTARRAY *pa, GBOX *gbox )
{
	int i;
	POINT4D p;
	int has_z, has_m;

	if ( ! pa ) return LW_FAILURE;
	if ( ! gbox ) return LW_FAILURE;
	if ( pa->npoints < 1 ) return LW_FAILURE;

	has_z = FLAGS_GET_Z(pa->flags);
	has_m = FLAGS_GET_M(pa->flags);
	gbox->flags = gflags(has_z, has_m, 0);
	LWDEBUGF(4, "ptarray_calculate_gbox Z: %d M: %d", has_z, has_m);

	getPoint4d_p(pa, 0, &p);
	gbox->xmin = gbox->xmax = p.x;
	gbox->ymin = gbox->ymax = p.y;
	if ( has_z )
		gbox->zmin = gbox->zmax = p.z;
	if ( has_m )
		gbox->mmin = gbox->mmax = p.m;

	for ( i = 1 ; i < pa->npoints; i++ )
	{
		getPoint4d_p(pa, i, &p);
		gbox->xmin = FP_MIN(gbox->xmin, p.x);
		gbox->xmax = FP_MAX(gbox->xmax, p.x);
		gbox->ymin = FP_MIN(gbox->ymin, p.y);
		gbox->ymax = FP_MAX(gbox->ymax, p.y);
		if ( has_z )
		{
			gbox->zmin = FP_MIN(gbox->zmin, p.z);
			gbox->zmax = FP_MAX(gbox->zmax, p.z);
		}
		if ( has_m )
		{
			gbox->mmin = FP_MIN(gbox->mmin, p.m);
			gbox->mmax = FP_MAX(gbox->mmax, p.m);
		}
	}
	return LW_SUCCESS;
}
int lw_segment_envelope_intersects(const POINT2D *p1, const POINT2D *p2, const POINT2D *q1, const POINT2D *q2)
{
    double minq=FP_MIN(q1->x,q2->x);
    double maxq=FP_MAX(q1->x,q2->x);
    double minp=FP_MIN(p1->x,p2->x);
    double maxp=FP_MAX(p1->x,p2->x);

    if (FP_GT(minp,maxq) || FP_LT(maxp,minq))
        return LW_FALSE;

    minq=FP_MIN(q1->y,q2->y);
    maxq=FP_MAX(q1->y,q2->y);
    minp=FP_MIN(p1->y,p2->y);
    maxp=FP_MAX(p1->y,p2->y);

    if (FP_GT(minp,maxq) || FP_LT(maxp,minq))
        return LW_FALSE;

    return LW_TRUE;
}
Exemple #5
0
/**
* This function doesn't work for edges crossing the dateline or in the southern
* hemisphere. Points are pre-conditioned in ptarray_area_spheroid.
*/
static double spheroid_striparea(const GEOGRAPHIC_POINT *a, const GEOGRAPHIC_POINT *b, double latitude_min, const SPHEROID *spheroid)
{
	GEOGRAPHIC_POINT A, B, mL, nR;
	double deltaLng, baseArea, topArea;
	double bE, tE, ratio, sign;

	A = *a;
	B = *b;

	mL.lat = latitude_min;
	mL.lon = FP_MIN(A.lon, B.lon);
	nR.lat = FP_MIN(A.lat, B.lat);
	nR.lon = FP_MAX(A.lon, B.lon);
	LWDEBUGF(4, "mL (%.12g %.12g)", mL.lat, mL.lon);
	LWDEBUGF(4, "nR (%.12g %.12g)", nR.lat, nR.lon);
	baseArea = spheroid_boundingbox_area(&mL, &nR, spheroid);
	LWDEBUGF(4, "baseArea %.12g", baseArea);

	mL.lat = FP_MIN(A.lat, B.lat);
	mL.lon = FP_MIN(A.lon, B.lon);
	nR.lat = FP_MAX(A.lat, B.lat);
	nR.lon = FP_MAX(A.lon, B.lon);
	LWDEBUGF(4, "mL (%.12g %.12g)", mL.lat, mL.lon);
	LWDEBUGF(4, "nR (%.12g %.12g)", nR.lat, nR.lon);
	topArea = spheroid_boundingbox_area(&mL, &nR, spheroid);
	LWDEBUGF(4, "topArea %.12g", topArea);

	deltaLng = B.lon - A.lon;
	LWDEBUGF(4, "deltaLng %.12g", deltaLng);
	bE = spheroid_parallel_arc_length(A.lat, deltaLng, spheroid);
	tE = spheroid_parallel_arc_length(B.lat, deltaLng, spheroid);
	LWDEBUGF(4, "bE %.12g", bE);
	LWDEBUGF(4, "tE %.12g", tE);

	ratio = (bE + tE)/tE;
	sign = signum(B.lon - A.lon);
	return (baseArea + topArea / ratio) * sign;
}
Exemple #6
0
int ptarray_calculate_gbox(const POINTARRAY *pa, GBOX *gbox )
{
	int i;
	POINT4D p;
	int has_z = FLAGS_GET_Z(gbox->flags);
	int has_m = FLAGS_GET_M(gbox->flags);

	if ( ! pa ) return G_FAILURE;
	if ( pa->npoints < 1 ) return G_FAILURE;

	getPoint4d_p(pa, 0, &p);
	gbox->xmin = gbox->xmax = p.x;
	gbox->ymin = gbox->ymax = p.y;
	if ( has_z )
		gbox->zmin = gbox->zmax = p.z;
	if ( has_m )
		gbox->mmin = gbox->mmax = p.m;

	for ( i = 1 ; i < pa->npoints; i++ )
	{
		getPoint4d_p(pa, i, &p);
		gbox->xmin = FP_MIN(gbox->xmin, p.x);
		gbox->xmax = FP_MAX(gbox->xmax, p.x);
		gbox->ymin = FP_MIN(gbox->ymin, p.y);
		gbox->ymax = FP_MAX(gbox->ymax, p.y);
		if ( has_z )
		{
			gbox->zmin = FP_MIN(gbox->zmin, p.z);
			gbox->zmax = FP_MAX(gbox->zmax, p.z);
		}
		if ( has_m )
		{
			gbox->mmin = FP_MIN(gbox->mmin, p.m);
			gbox->mmax = FP_MAX(gbox->mmax, p.m);
		}
	}
	return G_SUCCESS;
}
static int 
segment_locate_along(const POINT4D *p1, const POINT4D *p2, double m, double offset, POINT4D *pn)
{
	double m1 = p1->m;
	double m2 = p2->m;
	double mprop;

	/* M is out of range, no new point generated. */
	if ( (m < FP_MIN(m1,m2)) || (m > FP_MAX(m1,m2)) )
	{
		return LW_FALSE;
	}

	/* We'll just can out on this degenerate case for now. 
	   Correct behavior is probably an mprop of 0.5? 
	   Still would have to deal with case of true p1==p2. */
	if( m1 == m2 ) 
	{
		lwerror("Zero measure-length line encountered!");
	}

	/* M is in range, new point to be generated. */
	mprop = (m - m1) / (m2 - m1);
	pn->x = p1->x + (p2->x - p1->x) * mprop;
	pn->y = p1->y + (p2->y - p1->y) * mprop;
	pn->z = p1->z + (p2->z - p1->z) * mprop;
	pn->m = m;

	/* Offset to the left or right, if necessary. */
	if ( offset != 0.0 )
	{
		double theta = atan2(p2->y - p1->y, p2->x - p1->x);
		pn->x -= sin(theta) * offset;
		pn->y += cos(theta) * offset;
	}

	return LW_TRUE;	
}
/**
* Given two points, a dimensionality, an ordinate, and an interpolation value
* generate a new point that is proportionally between the input points,
* using the values in the provided dimension as the scaling factors.
*/
int point_interpolate(const POINT4D *p1, const POINT4D *p2, POINT4D *p, int hasz, int hasm, char ordinate, double interpolation_value)
{
	static char* dims = "XYZM";
	double p1_value = lwpoint_get_ordinate(p1, ordinate);
	double p2_value = lwpoint_get_ordinate(p2, ordinate);
	double proportion;
	int i = 0;

	if ( ! ( ordinate == 'X' || ordinate == 'Y' || ordinate == 'Z' || ordinate == 'M' ) )
	{
		lwerror("Cannot set %c ordinate.", ordinate);
		return 0;
	}

	if ( FP_MIN(p1_value, p2_value) > interpolation_value ||
	     FP_MAX(p1_value, p2_value) < interpolation_value )
	{
		lwerror("Cannot interpolate to a value (%g) not between the input points (%g, %g).", interpolation_value, p1_value, p2_value);
		return 0;
	}

	proportion = fabs((interpolation_value - p1_value) / (p2_value - p1_value));

	for ( i = 0; i < 4; i++ )
	{
		double newordinate = 0.0;
		if ( dims[i] == 'Z' && ! hasz ) continue;
		if ( dims[i] == 'M' && ! hasm ) continue;
		p1_value = lwpoint_get_ordinate(p1, dims[i]);
		p2_value = lwpoint_get_ordinate(p2, dims[i]);
		newordinate = p1_value + proportion * (p2_value - p1_value);
		lwpoint_set_ordinate(p, dims[i], newordinate);
		LWDEBUGF(4, "   clip ordinate(%c) p1_value(%g) p2_value(%g) proportion(%g) newordinate(%g) ", dims[i], p1_value, p2_value, proportion, newordinate );
	}

	return 1;
}
Exemple #9
0
int lw_arc_calculate_gbox_cartesian_2d(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, GBOX *gbox)
{
	POINT2D xmin, ymin, xmax, ymax;
	POINT2D C;
	int A2_side;
	double radius_A;

	LWDEBUG(2, "lw_arc_calculate_gbox_cartesian_2d called.");

	radius_A = lw_arc_center(A1, A2, A3, &C);

	/* Negative radius signals straight line, p1/p2/p3 are colinear */
	if (radius_A < 0.0)
	{
        gbox->xmin = FP_MIN(A1->x, A3->x);
        gbox->ymin = FP_MIN(A1->y, A3->y);
        gbox->xmax = FP_MAX(A1->x, A3->x);
        gbox->ymax = FP_MAX(A1->y, A3->y);
	    return LW_SUCCESS;
	}

	/* Matched start/end points imply circle */
	if ( A1->x == A3->x && A1->y == A3->y )
	{
		gbox->xmin = C.x - radius_A;
		gbox->ymin = C.y - radius_A;
		gbox->xmax = C.x + radius_A;
		gbox->ymax = C.y + radius_A;
		return LW_SUCCESS;
	}

	/* First approximation, bounds of start/end points */
    gbox->xmin = FP_MIN(A1->x, A3->x);
    gbox->ymin = FP_MIN(A1->y, A3->y);
    gbox->xmax = FP_MAX(A1->x, A3->x);
    gbox->ymax = FP_MAX(A1->y, A3->y);

	/* Create points for the possible extrema */
	xmin.x = C.x - radius_A;
	xmin.y = C.y;
	ymin.x = C.x;
	ymin.y = C.y - radius_A;
	xmax.x = C.x + radius_A;
	xmax.y = C.y;
	ymax.x = C.x;
	ymax.y = C.y + radius_A;

	/* Divide the circle into two parts, one on each side of a line
	   joining p1 and p3. The circle extrema on the same side of that line
	   as p2 is on, are also the extrema of the bbox. */

	A2_side = lw_segment_side(A1, A3, A2);

	if ( A2_side == lw_segment_side(A1, A3, &xmin) )
		gbox->xmin = xmin.x;

	if ( A2_side == lw_segment_side(A1, A3, &ymin) )
		gbox->ymin = ymin.y;

	if ( A2_side == lw_segment_side(A1, A3, &xmax) )
		gbox->xmax = xmax.x;

	if ( A2_side == lw_segment_side(A1, A3, &ymax) )
		gbox->ymax = ymax.y;

	return LW_SUCCESS;
}
Exemple #10
0
/*
static int lwcircle_calculate_gbox_cartesian(const POINT4D *p1, const POINT4D *p2, const POINT4D *p3, GBOX *gbox)
*/
BOX3D *
lwcircle_compute_box3d(POINT4D *p1, POINT4D *p2, POINT4D *p3)
{
	POINT2D xmin, ymin, xmax, ymax;
	POINT4D *center = NULL;
	int p2_side = 0;
	double radius = 0.0;

	LWDEBUG(2, "lwcircle_compute_box3d called.");

	radius = lwcircle_center(p1, p2, p3, &center);
	BOX3D *box = lwalloc(sizeof(BOX3D));
	
	/* Negative radius signals straight line, p1/p2/p3 are colinear */
	if (radius < 0.0)
	{
		if ( center ) lwfree(center);
        box->xmin = FP_MIN(p1->x, p3->x);
        box->ymin = FP_MIN(p1->y, p3->y);
        box->zmin = FP_MIN(p1->z, p3->z);
        box->xmax = FP_MAX(p1->x, p3->x);
        box->ymax = FP_MAX(p1->y, p3->y);
        box->zmax = FP_MAX(p1->z, p3->z);
	    return box;
	}
	
	/* Matched start/end points imply circle */
	if ( p1->x == p3->x && p1->y == p3->y )
	{
		box->xmin = center->x - radius;
		box->ymin = center->y - radius;
		box->zmin = FP_MIN(p1->z,p2->z);
		box->xmax = center->x + radius;
		box->ymax = center->y + radius;
		box->zmax = FP_MAX(p1->z,p2->z);
		lwfree(center);
		return box;
	}

	/* First approximation, bounds of start/end points */
    box->xmin = FP_MIN(p1->x, p3->x);
    box->ymin = FP_MIN(p1->y, p3->y);
    box->zmin = FP_MIN(p1->z, p3->z);
    box->xmax = FP_MAX(p1->x, p3->x);
    box->ymax = FP_MAX(p1->y, p3->y);
    box->zmax = FP_MAX(p1->z, p3->z);

	/* Create points for the possible extrema */
	xmin.x = center->x - radius;
	xmin.y = center->y;
	ymin.x = center->x;
	ymin.y = center->y - radius;
	xmax.x = center->x + radius;
	xmax.y = center->y;
	ymax.x = center->x;
	ymax.y = center->y + radius;
	
	/* Divide the circle into two parts, one on each side of a line
	   joining p1 and p3. The circle extrema on the same side of that line
	   as p2 is on, are also the extrema of the bbox. */
	
	p2_side = signum(lw_segment_side((POINT2D*)p1, (POINT2D*)p3, (POINT2D*)p2));

	if ( p2_side == signum(lw_segment_side((POINT2D*)p1, (POINT2D*)p3, &xmin)) )
		box->xmin = xmin.x;

	if ( p2_side == signum(lw_segment_side((POINT2D*)p1, (POINT2D*)p3, &ymin)) )
		box->ymin = ymin.y;

	if ( p2_side == signum(lw_segment_side((POINT2D*)p1, (POINT2D*)p3, &xmax)) )
		box->xmax = xmax.x;

	if ( p2_side == signum(lw_segment_side((POINT2D*)p1, (POINT2D*)p3, &ymax)) )
		box->ymax = ymax.y;

	lwfree(center);
	return box;
}
Exemple #11
0
int 
ptarrayarc_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number)
{
	int wn = 0;
	int i, side;
	const POINT2D *seg1;
	const POINT2D *seg2;
	const POINT2D *seg3;
	GBOX gbox;

	/* Check for not an arc ring (always have odd # of points) */
	if ( (pa->npoints % 2) == 0 )
	{
		lwerror("ptarrayarc_contains_point called with even number of points");
		return LW_OUTSIDE;
	}

	/* Check for not an arc ring (always have >= 3 points) */
	if ( pa->npoints < 3 )
	{
		lwerror("ptarrayarc_contains_point called too-short pointarray");
		return LW_OUTSIDE;
	}

	/* Check for unclosed case */
	seg1 = getPoint2d_cp(pa, 0);
	seg3 = getPoint2d_cp(pa, pa->npoints-1);
	if ( check_closed && ! p2d_same(seg1, seg3) )
	{
		lwerror("ptarrayarc_contains_point called on unclosed ring");
		return LW_OUTSIDE;
	} 
	/* OK, it's closed. Is it just one circle? */
	else if ( p2d_same(seg1, seg3) && pa->npoints == 3 )
	{
		double radius, d;
		POINT2D c;
		seg2 = getPoint2d_cp(pa, 1);
		
		/* Wait, it's just a point, so it can't contain anything */
		if ( lw_arc_is_pt(seg1, seg2, seg3) )
			return LW_OUTSIDE;
			
		/* See if the point is within the circle radius */
		radius = lw_arc_center(seg1, seg2, seg3, &c);
		d = distance2d_pt_pt(pt, &c);
		if ( FP_EQUALS(d, radius) )
			return LW_BOUNDARY; /* Boundary of circle */
		else if ( d < radius ) 
			return LW_INSIDE; /* Inside circle */
		else 
			return LW_OUTSIDE; /* Outside circle */
	} 
	else if ( p2d_same(seg1, pt) || p2d_same(seg3, pt) )
	{
		return LW_BOUNDARY; /* Boundary case */
	}

	/* Start on the ring */
	seg1 = getPoint2d_cp(pa, 0);
	for ( i=1; i < pa->npoints; i += 2 )
	{
		seg2 = getPoint2d_cp(pa, i);
		seg3 = getPoint2d_cp(pa, i+1);
		
		/* Catch an easy boundary case */
		if( p2d_same(seg3, pt) )
			return LW_BOUNDARY;
		
		/* Skip arcs that have no size */
		if ( lw_arc_is_pt(seg1, seg2, seg3) )
		{
			seg1 = seg3;
			continue;
		}
		
		/* Only test segments in our vertical range */
		lw_arc_calculate_gbox_cartesian_2d(seg1, seg2, seg3, &gbox);
		if ( pt->y > gbox.ymax || pt->y < gbox.ymin ) 
		{
			seg1 = seg3;
			continue;
		}

		/* Outside of horizontal range, and not between end points we also skip */
		if ( (pt->x > gbox.xmax || pt->x < gbox.xmin) && 
			 (pt->y > FP_MAX(seg1->y, seg3->y) || pt->y < FP_MIN(seg1->y, seg3->y)) ) 
		{
			seg1 = seg3;
			continue;
		}		
		
		side = lw_arc_side(seg1, seg2, seg3, pt);
		
		/* On the boundary */
		if ( (side == 0) && lw_pt_in_arc(pt, seg1, seg2, seg3) )
		{
			return LW_BOUNDARY;
		}
		
		/* Going "up"! Point to left of arc. */
		if ( side < 0 && (seg1->y <= pt->y) && (pt->y < seg3->y) )
		{
			wn++;
		}

		/* Going "down"! */
		if ( side > 0 && (seg2->y <= pt->y) && (pt->y < seg1->y) )
		{
			wn--;
		}
		
		/* Inside the arc! */
		if ( pt->x <= gbox.xmax && pt->x >= gbox.xmin ) 
		{
			POINT2D C;
			double radius = lw_arc_center(seg1, seg2, seg3, &C);
			double d = distance2d_pt_pt(pt, &C);

			/* On the boundary! */
			if ( d == radius )
				return LW_BOUNDARY;
			
			/* Within the arc! */
			if ( d  < radius )
			{
				/* Left side, increment winding number */
				if ( side < 0 )
					wn++;
				/* Right side, decrement winding number */
				if ( side > 0 ) 
					wn--;
			}
		}

		seg1 = seg3;
	}

	/* Sent out the winding number for calls that are building on this as a primitive */
	if ( winding_number )
		*winding_number = wn;

	/* Outside */
	if (wn == 0)
	{
		return LW_OUTSIDE;
	}
	
	/* Inside */
	return LW_INSIDE;
}
Exemple #12
0
int 
ptarray_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number)
{
	int wn = 0;
	int i;
	double side;
	const POINT2D *seg1;
	const POINT2D *seg2;
	double ymin, ymax;

	seg1 = getPoint2d_cp(pa, 0);
	seg2 = getPoint2d_cp(pa, pa->npoints-1);
	if ( check_closed && ! p2d_same(seg1, seg2) )
		lwerror("ptarray_contains_point called on unclosed ring");
	
	for ( i=1; i < pa->npoints; i++ )
	{
		seg2 = getPoint2d_cp(pa, i);
		
		/* Zero length segments are ignored. */
		if ( seg1->x == seg2->x && seg1->y == seg2->y )
		{
			seg1 = seg2;
			continue;
		}
			
		ymin = FP_MIN(seg1->y, seg2->y);
		ymax = FP_MAX(seg1->y, seg2->y);
		
		/* Only test segments in our vertical range */
		if ( pt->y > ymax || pt->y < ymin ) 
		{
			seg1 = seg2;
			continue;
		}

		side = lw_segment_side(seg1, seg2, pt);

		/* 
		* A point on the boundary of a ring is not contained. 
		* WAS: if (fabs(side) < 1e-12), see #852 
		*/
		if ( (side == 0) && lw_pt_in_seg(pt, seg1, seg2) )
		{
			return LW_BOUNDARY;
		}

		/*
		* If the point is to the left of the line, and it's rising,
		* then the line is to the right of the point and
		* circling counter-clockwise, so incremement.
		*/
		if ( (side < 0) && (seg1->y <= pt->y) && (pt->y < seg2->y) )
		{
			wn++;
		}
		
		/*
		* If the point is to the right of the line, and it's falling,
		* then the line is to the right of the point and circling
		* clockwise, so decrement.
		*/
		else if ( (side > 0) && (seg2->y <= pt->y) && (pt->y < seg1->y) )
		{
			wn--;
		}
		
		seg1 = seg2;
	}

	/* Sent out the winding number for calls that are building on this as a primitive */
	if ( winding_number )
		*winding_number = wn;

	/* Outside */
	if (wn == 0)
	{
		return LW_OUTSIDE;
	}
	
	/* Inside */
	return LW_INSIDE;
}
Exemple #13
0
static int lwcircle_calculate_gbox(POINT4D p1, POINT4D p2, POINT4D p3, GBOX *gbox)
{
	double x1, x2, y1, y2, z1, z2, m1, m2;
	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;

	LWDEBUG(2, "lwcircle_calculate_gbox called.");

	radius = lwcircle_center(&p1, &p2, &p3, &center);
	if (radius < 0.0) return G_FAILURE;

	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;

	/*
	 * 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_calculate_gbox: 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_calculate_gbox: extreames found (%.16f %.16f, %.16f %.16f)", x1, y1, x2, y2);

	z1 = FP_MIN(p1.z, p2.z);
	z1 = FP_MIN(z1, p3.z);
	z2 = FP_MAX(p1.z, p2.z);
	z2 = FP_MAX(z2, p3.z);

	m1 = FP_MIN(p1.m, p2.m);
	m1 = FP_MIN(m1, p3.m);
	m2 = FP_MAX(p1.m, p2.m);
	m2 = FP_MAX(m2, p3.m);

	gbox->xmin = x1;
	gbox->xmax = x2;
	gbox->ymin = y1;
	gbox->ymax = y2;

	if ( FLAGS_GET_Z(gbox->flags) )
	{
		gbox->zmin = z1;
		gbox->zmax = z2;
	}
	if ( FLAGS_GET_M(gbox->flags) )
	{
		gbox->mmin = m1;
		gbox->mmax = m2;
	}

	return G_SUCCESS;
}
Exemple #14
0
/*
* Populate a bounding box *without* allocating an LWGEOM. Useful
* for some performance purposes.
*/
static int gserialized_peek_gbox_p(const GSERIALIZED *g, GBOX *gbox)
{
	uint32_t type = gserialized_get_type(g);

	/* Peeking doesn't help if you already have a box or are geodetic */
	if ( FLAGS_GET_GEODETIC(g->flags) || FLAGS_GET_BBOX(g->flags) )
	{
		return LW_FAILURE;
	}
	
	/* Boxes of points are easy peasy */
	if ( type == POINTTYPE )
	{
		int i = 1; /* Start past <pointtype><padding> */
		double *dptr = (double*)(g->data);

		/* Read the empty flag */
		int *iptr = (int*)(g->data);
		int isempty = (iptr[1] == 0);

		/* EMPTY point has no box */
		if ( isempty ) return LW_FAILURE;

		gbox->xmin = gbox->xmax = dptr[i++];
		gbox->ymin = gbox->ymax = dptr[i++];
		if ( FLAGS_GET_Z(g->flags) )
		{
			gbox->zmin = gbox->zmax = dptr[i++];
		}
		if ( FLAGS_GET_M(g->flags) )
		{
			gbox->mmin = gbox->mmax = dptr[i++];
		}
		gbox_float_round(gbox);
		return LW_SUCCESS;
	}
	/* We can calculate the box of a two-point cartesian line trivially */
	else if ( type == LINETYPE )
	{
		int ndims = FLAGS_NDIMS(g->flags);
		int i = 0; /* Start at <linetype><npoints> */
		double *dptr = (double*)(g->data);
		int *iptr = (int*)(g->data);
		int npoints = iptr[1]; /* Read the npoints */
	
		/* This only works with 2-point lines */
		if ( npoints != 2 )
			return LW_FAILURE;
		
		/* Advance to X */
		/* Past <linetype><npoints> */
		i++;
		gbox->xmin = FP_MIN(dptr[i], dptr[i+ndims]);
		gbox->xmax = FP_MAX(dptr[i], dptr[i+ndims]);
	
		/* Advance to Y */
		i++;
		gbox->ymin = FP_MIN(dptr[i], dptr[i+ndims]);
		gbox->ymax = FP_MAX(dptr[i], dptr[i+ndims]);
	
		if ( FLAGS_GET_Z(g->flags) )
		{
			/* Advance to Z */
			i++;
			gbox->zmin = FP_MIN(dptr[i], dptr[i+ndims]);
			gbox->zmax = FP_MAX(dptr[i], dptr[i+ndims]);
		}
		if ( FLAGS_GET_M(g->flags) )
		{
			/* Advance to M */
			i++;
			gbox->mmin = FP_MIN(dptr[i], dptr[i+ndims]);
			gbox->mmax = FP_MAX(dptr[i], dptr[i+ndims]);
		}
		gbox_float_round(gbox);
		return LW_SUCCESS;
	}
	/* We can also do single-entry multi-points */
	else if ( type == MULTIPOINTTYPE )
	{
		int i = 0; /* Start at <multipointtype><ngeoms> */
		double *dptr = (double*)(g->data);
		int *iptr = (int*)(g->data);
		int ngeoms = iptr[1]; /* Read the ngeoms */
	
		/* This only works with single-entry multipoints */
		if ( ngeoms != 1 )
			return LW_FAILURE;

		/* Move forward two doubles (four ints) */
		/* Past <multipointtype><ngeoms> */
		/* Past <pointtype><emtpyflat> */
		i += 2;

		/* Read the doubles from the one point */
		gbox->xmin = gbox->xmax = dptr[i++];
		gbox->ymin = gbox->ymax = dptr[i++];
		if ( FLAGS_GET_Z(g->flags) )
		{
			gbox->zmin = gbox->zmax = dptr[i++];
		}
		if ( FLAGS_GET_M(g->flags) )
		{
			gbox->mmin = gbox->mmax = dptr[i++];
		}
		gbox_float_round(gbox);
		return LW_SUCCESS;
	}
	/* And we can do single-entry multi-lines with two vertices (!!!) */
	else if ( type == MULTILINETYPE )
	{
		int ndims = FLAGS_NDIMS(g->flags);
		int i = 0; /* Start at <multilinetype><ngeoms> */
		double *dptr = (double*)(g->data);
		int *iptr = (int*)(g->data);
		int ngeoms = iptr[1]; /* Read the ngeoms */
		int npoints;
	
		/* This only works with 1-line multilines */
		if ( ngeoms != 1 )
			return LW_FAILURE;

		/* Npoints is at <multilinetype><ngeoms><linetype><npoints> */
		npoints = iptr[3];

		if ( npoints != 2 )
			return LW_FAILURE;

		/* Advance to X */
		/* Move forward two doubles (four ints) */
		/* Past <multilinetype><ngeoms> */
		/* Past <linetype><npoints> */
		i += 2;
		gbox->xmin = FP_MIN(dptr[i], dptr[i+ndims]);
		gbox->xmax = FP_MAX(dptr[i], dptr[i+ndims]);
	
		/* Advance to Y */
		i++;
		gbox->ymin = FP_MIN(dptr[i], dptr[i+ndims]);
		gbox->ymax = FP_MAX(dptr[i], dptr[i+ndims]);
	
		if ( FLAGS_GET_Z(g->flags) )
		{
			/* Advance to Z */
			i++;
			gbox->zmin = FP_MIN(dptr[i], dptr[i+ndims]);
			gbox->zmax = FP_MAX(dptr[i], dptr[i+ndims]);
		}
		if ( FLAGS_GET_M(g->flags) )
		{
			/* Advance to M */
			i++;
			gbox->mmin = FP_MIN(dptr[i], dptr[i+ndims]);
			gbox->mmax = FP_MAX(dptr[i], dptr[i+ndims]);
		}
		gbox_float_round(gbox);
		return LW_SUCCESS;
	}
	
	return LW_FAILURE;
}
Exemple #15
0
static int lwcircle_calculate_gbox_cartesian(const POINT4D *p1, const POINT4D *p2, const POINT4D *p3, GBOX *gbox)
{
	POINT2D xmin, ymin, xmax, ymax;
	POINT4D center;
	int p2_side;
	double radius;

	LWDEBUG(2, "lwcircle_calculate_gbox called.");

	radius = lwcircle_center(p1, p2, p3, &center);
	
	/* Negative radius signals straight line, p1/p2/p3 are colinear */
	if (radius < 0.0)
	{
        gbox->xmin = FP_MIN(p1->x, p3->x);
        gbox->ymin = FP_MIN(p1->y, p3->y);
        gbox->zmin = FP_MIN(p1->z, p3->z);
        gbox->xmax = FP_MAX(p1->x, p3->x);
        gbox->ymax = FP_MAX(p1->y, p3->y);
        gbox->zmax = FP_MAX(p1->z, p3->z);
	    return LW_SUCCESS;
	}
	
	/* Matched start/end points imply circle */
	if ( p1->x == p3->x && p1->y == p3->y )
	{
		gbox->xmin = center.x - radius;
		gbox->ymin = center.y - radius;
		gbox->zmin = FP_MIN(p1->z,p2->z);
		gbox->mmin = FP_MIN(p1->m,p2->m);
		gbox->xmax = center.x + radius;
		gbox->ymax = center.y + radius;
		gbox->zmax = FP_MAX(p1->z,p2->z);
		gbox->mmax = FP_MAX(p1->m,p2->m);
		return LW_SUCCESS;
	}

	/* First approximation, bounds of start/end points */
    gbox->xmin = FP_MIN(p1->x, p3->x);
    gbox->ymin = FP_MIN(p1->y, p3->y);
    gbox->zmin = FP_MIN(p1->z, p3->z);
    gbox->mmin = FP_MIN(p1->m, p3->m);
    gbox->xmax = FP_MAX(p1->x, p3->x);
    gbox->ymax = FP_MAX(p1->y, p3->y);
    gbox->zmax = FP_MAX(p1->z, p3->z);
    gbox->mmax = FP_MAX(p1->m, p3->m);

	/* Create points for the possible extrema */
	xmin.x = center.x - radius;
	xmin.y = center.y;
	ymin.x = center.x;
	ymin.y = center.y - radius;
	xmax.x = center.x + radius;
	xmax.y = center.y;
	ymax.x = center.x;
	ymax.y = center.y + radius;
	
	
	/* Divide the circle into two parts, one on each side of a line
	   joining p1 and p3. The circle extrema on the same side of that line
	   as p2 is on, are also the extrema of the bbox. */
	
	p2_side = signum(lw_segment_side((POINT2D*)p1, (POINT2D*)p3, (POINT2D*)p2));

	if ( p2_side == signum(lw_segment_side((POINT2D*)p1, (POINT2D*)p3, &xmin)) )
		gbox->xmin = xmin.x;

	if ( p2_side == signum(lw_segment_side((POINT2D*)p1, (POINT2D*)p3, &ymin)) )
		gbox->ymin = ymin.y;

	if ( p2_side == signum(lw_segment_side((POINT2D*)p1, (POINT2D*)p3, &xmax)) )
		gbox->xmax = xmax.x;

	if ( p2_side == signum(lw_segment_side((POINT2D*)p1, (POINT2D*)p3, &ymax)) )
		gbox->ymax = ymax.y;

	return LW_SUCCESS;
}
Exemple #16
0
static double 
circ_tree_distance_tree_internal(const CIRC_NODE* n1, const CIRC_NODE* n2, double threshold, double* min_dist, double* max_dist, GEOGRAPHIC_POINT* closest1, GEOGRAPHIC_POINT* closest2)
{	
	double max;
	double d, d_min;
	int i;
	
	LWDEBUGF(4, "entered, min_dist %.8g max_dist %.8g", *min_dist, *max_dist);
//	circ_tree_print(n1, 0);
//	circ_tree_print(n2, 0);
	
	/* Short circuit if we've already hit the minimum */
	if( FP_LT(*min_dist, threshold) )
		return *min_dist;
	
	/* If your minimum is greater than anyone's maximum, you can't hold the winner */
	if( circ_node_min_distance(n1, n2) > *max_dist )
	{
		LWDEBUGF(4, "pruning pair %p, %p", n1, n2);		
		return MAXFLOAT;
	}
	
	/* If your maximum is a new low, we'll use that as our new global tolerance */
	max = circ_node_max_distance(n1, n2);
	LWDEBUGF(5, "max %.8g", max);
	if( max < *max_dist )
		*max_dist = max;

	/* Both leaf nodes, do a real distance calculation */
	if( circ_node_is_leaf(n1) )
	{
		if( circ_node_is_leaf(n2) )
		{
			double d;
			GEOGRAPHIC_POINT close1, close2;
			LWDEBUGF(4, "testing leaf pair [%d], [%d]", n1->edge_num, n2->edge_num);		
			/* One of the nodes is a point */
			if ( n1->p1 == n1->p2 || n2->p1 == n2->p2 )
			{
				GEOGRAPHIC_EDGE e;
				GEOGRAPHIC_POINT gp1, gp2;

				/* Both nodes are points! */
				if ( n1->p1 == n1->p2 && n2->p1 == n2->p2 )
				{
					geographic_point_init(n1->p1->x, n1->p1->y, &gp1);
					geographic_point_init(n2->p1->x, n2->p1->y, &gp2);
					close1 = gp1; close2 = gp2;
					d = sphere_distance(&gp1, &gp2);
				}				
				/* Node 1 is a point */
				else if ( n1->p1 == n1->p2 )
				{
					geographic_point_init(n1->p1->x, n1->p1->y, &gp1);
					geographic_point_init(n2->p1->x, n2->p1->y, &(e.start));
					geographic_point_init(n2->p2->x, n2->p2->y, &(e.end));
					close1 = gp1;
					d = edge_distance_to_point(&e, &gp1, &close2);
				}
				/* Node 2 is a point */
				else
				{
					geographic_point_init(n2->p1->x, n2->p1->y, &gp1);
					geographic_point_init(n1->p1->x, n1->p1->y, &(e.start));
					geographic_point_init(n1->p2->x, n1->p2->y, &(e.end));
					close1 = gp1;
					d = edge_distance_to_point(&e, &gp1, &close2);
				}
				LWDEBUGF(4, "  got distance %g", d);		
			}
			/* Both nodes are edges */
			else
			{
				GEOGRAPHIC_EDGE e1, e2;
				GEOGRAPHIC_POINT g;
				POINT3D A1, A2, B1, B2;
				geographic_point_init(n1->p1->x, n1->p1->y, &(e1.start));
				geographic_point_init(n1->p2->x, n1->p2->y, &(e1.end));
				geographic_point_init(n2->p1->x, n2->p1->y, &(e2.start));
				geographic_point_init(n2->p2->x, n2->p2->y, &(e2.end));
				geog2cart(&(e1.start), &A1);
				geog2cart(&(e1.end), &A2);
				geog2cart(&(e2.start), &B1);
				geog2cart(&(e2.end), &B2);
				if ( edge_intersects(&A1, &A2, &B1, &B2) )
				{
					d = 0.0;
					edge_intersection(&e1, &e2, &g);
					close1 = close2 = g;
				}
				else
				{
					d = edge_distance_to_edge(&e1, &e2, &close1, &close2);
				}
				LWDEBUGF(4, "edge_distance_to_edge returned %g", d);		
			}
			if ( d < *min_dist )
			{
				*min_dist = d;
				*closest1 = close1;
				*closest2 = close2;
			}
			return d;
		}
		else
		{
			d_min = MAXFLOAT;
			for ( i = 0; i < n2->num_nodes; i++ )
			{
				d = circ_tree_distance_tree_internal(n1, n2->nodes[i], threshold, min_dist, max_dist, closest1, closest2);
				d_min = FP_MIN(d_min, d);
			}
			return d_min;
		}
	}
	else
	{
		d_min = MAXFLOAT;
		for ( i = 0; i < n1->num_nodes; i++ )
		{
			d = circ_tree_distance_tree_internal(n2, n1->nodes[i], threshold, min_dist, max_dist, closest1, closest2);
			d_min = FP_MIN(d_min, d);
		}
		return d_min;
	}
}