コード例 #1
0
ファイル: lwalgorithm.c プロジェクト: NianYue/pipelinedb
/**
* Returns the length of a circular arc segment
*/
double
lw_arc_length(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3)
{
	POINT2D C;
	double radius_A, circumference_A;
	int a2_side, clockwise;
	double a1, a3;
	double angle;
	
	if ( lw_arc_is_pt(A1, A2, A3) )
		return 0.0;
	
	radius_A = lw_arc_center(A1, A2, A3, &C);

	/* Co-linear! Return linear distance! */
	if ( radius_A < 0 ) 
	{
        double dx = A1->x - A3->x;
        double dy = A1->y - A3->y;
		return sqrt(dx*dx + dy*dy);
	}
	
	/* Closed circle! Return the circumference! */
	circumference_A = M_PI * 2 * radius_A;
	if ( p2d_same(A1, A3) )
		return circumference_A;
	
	/* Determine the orientation of the arc */
	a2_side = lw_segment_side(A1, A3, A2);

	/* The side of the A1/A3 line that A2 falls on dictates the sweep  
	   direction from A1 to A3. */
	if ( a2_side == -1 ) 
		clockwise = LW_TRUE;
	else 
		clockwise = LW_FALSE;
		
	/* Angles of each point that defines the arc section */
	a1 = atan2(A1->y - C.y, A1->x - C.x);
	a3 = atan2(A3->y - C.y, A3->x - C.x);

	/* What's the sweep from A1 to A3? */
	if ( clockwise )
	{
		if ( a1 > a3 )
			angle = a1 - a3;
		else
			angle = 2*M_PI + a1 - a3; 
	}
	else
	{
		if ( a3 > a1 )
			angle = a3 - a1;
		else
			angle = 2*M_PI + a3 - a1; 			
	}

	/* Length as proportion of circumference */
	return circumference_A * (angle / (2*M_PI));
}
コード例 #2
0
ファイル: ptarray.c プロジェクト: gbroccolo/postgis
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;
}