geo_ops.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 3,017 行 · 第 1/5 页

C
3,017
字号
 *---------------------------------------------------------*/Datumpoint_left(PG_FUNCTION_ARGS){	Point	   *pt1 = PG_GETARG_POINT_P(0);	Point	   *pt2 = PG_GETARG_POINT_P(1);	PG_RETURN_BOOL(FPlt(pt1->x, pt2->x));}Datumpoint_right(PG_FUNCTION_ARGS){	Point	   *pt1 = PG_GETARG_POINT_P(0);	Point	   *pt2 = PG_GETARG_POINT_P(1);	PG_RETURN_BOOL(FPgt(pt1->x, pt2->x));}Datumpoint_above(PG_FUNCTION_ARGS){	Point	   *pt1 = PG_GETARG_POINT_P(0);	Point	   *pt2 = PG_GETARG_POINT_P(1);	PG_RETURN_BOOL(FPgt(pt1->y, pt2->y));}Datumpoint_below(PG_FUNCTION_ARGS){	Point	   *pt1 = PG_GETARG_POINT_P(0);	Point	   *pt2 = PG_GETARG_POINT_P(1);	PG_RETURN_BOOL(FPlt(pt1->y, pt2->y));}Datumpoint_vert(PG_FUNCTION_ARGS){	Point	   *pt1 = PG_GETARG_POINT_P(0);	Point	   *pt2 = PG_GETARG_POINT_P(1);	PG_RETURN_BOOL(FPeq(pt1->x, pt2->x));}Datumpoint_horiz(PG_FUNCTION_ARGS){	Point	   *pt1 = PG_GETARG_POINT_P(0);	Point	   *pt2 = PG_GETARG_POINT_P(1);	PG_RETURN_BOOL(FPeq(pt1->y, pt2->y));}Datumpoint_eq(PG_FUNCTION_ARGS){	Point	   *pt1 = PG_GETARG_POINT_P(0);	Point	   *pt2 = PG_GETARG_POINT_P(1);	PG_RETURN_BOOL(FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y));}Datumpoint_ne(PG_FUNCTION_ARGS){	Point	   *pt1 = PG_GETARG_POINT_P(0);	Point	   *pt2 = PG_GETARG_POINT_P(1);	PG_RETURN_BOOL(FPne(pt1->x, pt2->x) || FPne(pt1->y, pt2->y));}/*---------------------------------------------------------- *	"Arithmetic" operators on points. *---------------------------------------------------------*/Datumpoint_distance(PG_FUNCTION_ARGS){	Point	   *pt1 = PG_GETARG_POINT_P(0);	Point	   *pt2 = PG_GETARG_POINT_P(1);	PG_RETURN_FLOAT8(HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));}doublepoint_dt(Point *pt1, Point *pt2){#ifdef GEODEBUG	printf("point_dt- segment (%f,%f),(%f,%f) length is %f\n",		   pt1->x, pt1->y, pt2->x, pt2->y, HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));#endif	return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);}Datumpoint_slope(PG_FUNCTION_ARGS){	Point	   *pt1 = PG_GETARG_POINT_P(0);	Point	   *pt2 = PG_GETARG_POINT_P(1);	PG_RETURN_FLOAT8(point_sl(pt1, pt2));}doublepoint_sl(Point *pt1, Point *pt2){	return (FPeq(pt1->x, pt2->x)			? (double) DBL_MAX			: (pt1->y - pt2->y) / (pt1->x - pt2->x));}/*********************************************************************** ** **		Routines for 2D line segments. ** ***********************************************************************//*---------------------------------------------------------- *	String to lseg, lseg to string conversion. *		External forms: "[(x1, y1), (x2, y2)]" *						"(x1, y1), (x2, y2)" *						"x1, y1, x2, y2" *		closed form ok	"((x1, y1), (x2, y2))" *		(old form)		"(x1, y1, x2, y2)" *---------------------------------------------------------*/Datumlseg_in(PG_FUNCTION_ARGS){	char	   *str = PG_GETARG_CSTRING(0);	LSEG	   *lseg;	int			isopen;	char	   *s;	lseg = (LSEG *) palloc(sizeof(LSEG));	if ((!path_decode(TRUE, 2, str, &isopen, &s, &(lseg->p[0])))		|| (*s != '\0'))		ereport(ERROR,				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),				 errmsg("invalid input syntax for type lseg: \"%s\"", str)));#ifdef NOT_USED	lseg->m = point_sl(&lseg->p[0], &lseg->p[1]);#endif	PG_RETURN_LSEG_P(lseg);}Datumlseg_out(PG_FUNCTION_ARGS){	LSEG	   *ls = PG_GETARG_LSEG_P(0);	PG_RETURN_CSTRING(path_encode(FALSE, 2, (Point *) &(ls->p[0])));}/* *		lseg_recv			- converts external binary format to lseg */Datumlseg_recv(PG_FUNCTION_ARGS){	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);	LSEG	   *lseg;	lseg = (LSEG *) palloc(sizeof(LSEG));	lseg->p[0].x = pq_getmsgfloat8(buf);	lseg->p[0].y = pq_getmsgfloat8(buf);	lseg->p[1].x = pq_getmsgfloat8(buf);	lseg->p[1].y = pq_getmsgfloat8(buf);#ifdef NOT_USED	lseg->m = point_sl(&lseg->p[0], &lseg->p[1]);#endif	PG_RETURN_LSEG_P(lseg);}/* *		lseg_send			- converts lseg to binary format */Datumlseg_send(PG_FUNCTION_ARGS){	LSEG	   *ls = PG_GETARG_LSEG_P(0);	StringInfoData buf;	pq_begintypsend(&buf);	pq_sendfloat8(&buf, ls->p[0].x);	pq_sendfloat8(&buf, ls->p[0].y);	pq_sendfloat8(&buf, ls->p[1].x);	pq_sendfloat8(&buf, ls->p[1].y);	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));}/* lseg_construct - *		form a LSEG from two Points. */Datumlseg_construct(PG_FUNCTION_ARGS){	Point	   *pt1 = PG_GETARG_POINT_P(0);	Point	   *pt2 = PG_GETARG_POINT_P(1);	LSEG	   *result = (LSEG *) palloc(sizeof(LSEG));	result->p[0].x = pt1->x;	result->p[0].y = pt1->y;	result->p[1].x = pt2->x;	result->p[1].y = pt2->y;#ifdef NOT_USED	result->m = point_sl(pt1, pt2);#endif	PG_RETURN_LSEG_P(result);}/* like lseg_construct, but assume space already allocated */static voidstatlseg_construct(LSEG *lseg, Point *pt1, Point *pt2){	lseg->p[0].x = pt1->x;	lseg->p[0].y = pt1->y;	lseg->p[1].x = pt2->x;	lseg->p[1].y = pt2->y;#ifdef NOT_USED	lseg->m = point_sl(pt1, pt2);#endif}Datumlseg_length(PG_FUNCTION_ARGS){	LSEG	   *lseg = PG_GETARG_LSEG_P(0);	PG_RETURN_FLOAT8(point_dt(&lseg->p[0], &lseg->p[1]));}/*---------------------------------------------------------- *	Relative position routines. *---------------------------------------------------------*//* **  find intersection of the two lines, and see if it falls on **  both segments. */Datumlseg_intersect(PG_FUNCTION_ARGS){	LSEG	   *l1 = PG_GETARG_LSEG_P(0);	LSEG	   *l2 = PG_GETARG_LSEG_P(1);	PG_RETURN_BOOL(lseg_intersect_internal(l1, l2));}static boollseg_intersect_internal(LSEG *l1, LSEG *l2){	LINE		ln;	Point	   *interpt;	bool		retval;	line_construct_pts(&ln, &l2->p[0], &l2->p[1]);	interpt = interpt_sl(l1, &ln);	if (interpt != NULL && on_ps_internal(interpt, l2))		retval = true;			/* interpt on l1 and l2 */	else		retval = false;	return retval;}Datumlseg_parallel(PG_FUNCTION_ARGS){	LSEG	   *l1 = PG_GETARG_LSEG_P(0);	LSEG	   *l2 = PG_GETARG_LSEG_P(1);#ifdef NOT_USED	PG_RETURN_BOOL(FPeq(l1->m, l2->m));#endif	PG_RETURN_BOOL(FPeq(point_sl(&l1->p[0], &l1->p[1]),						point_sl(&l2->p[0], &l2->p[1])));}/* lseg_perp() * Determine if two line segments are perpendicular. * * This code did not get the correct answer for *	'((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg * So, modified it to check explicitly for slope of vertical line *	returned by point_sl() and the results seem better. * - thomas 1998-01-31 */Datumlseg_perp(PG_FUNCTION_ARGS){	LSEG	   *l1 = PG_GETARG_LSEG_P(0);	LSEG	   *l2 = PG_GETARG_LSEG_P(1);	double		m1,				m2;	m1 = point_sl(&(l1->p[0]), &(l1->p[1]));	m2 = point_sl(&(l2->p[0]), &(l2->p[1]));#ifdef GEODEBUG	printf("lseg_perp- slopes are %g and %g\n", m1, m2);#endif	if (FPzero(m1))		PG_RETURN_BOOL(FPeq(m2, DBL_MAX));	else if (FPzero(m2))		PG_RETURN_BOOL(FPeq(m1, DBL_MAX));	PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));}Datumlseg_vertical(PG_FUNCTION_ARGS){	LSEG	   *lseg = PG_GETARG_LSEG_P(0);	PG_RETURN_BOOL(FPeq(lseg->p[0].x, lseg->p[1].x));}Datumlseg_horizontal(PG_FUNCTION_ARGS){	LSEG	   *lseg = PG_GETARG_LSEG_P(0);	PG_RETURN_BOOL(FPeq(lseg->p[0].y, lseg->p[1].y));}Datumlseg_eq(PG_FUNCTION_ARGS){	LSEG	   *l1 = PG_GETARG_LSEG_P(0);	LSEG	   *l2 = PG_GETARG_LSEG_P(1);	PG_RETURN_BOOL(FPeq(l1->p[0].x, l2->p[0].x) &&				   FPeq(l1->p[0].y, l2->p[0].y) &&				   FPeq(l1->p[1].x, l2->p[1].x) &&				   FPeq(l1->p[1].y, l2->p[1].y));}Datumlseg_ne(PG_FUNCTION_ARGS){	LSEG	   *l1 = PG_GETARG_LSEG_P(0);	LSEG	   *l2 = PG_GETARG_LSEG_P(1);	PG_RETURN_BOOL(!FPeq(l1->p[0].x, l2->p[0].x) ||				   !FPeq(l1->p[0].y, l2->p[0].y) ||				   !FPeq(l1->p[1].x, l2->p[1].x) ||				   !FPeq(l1->p[1].y, l2->p[1].y));}Datumlseg_lt(PG_FUNCTION_ARGS){	LSEG	   *l1 = PG_GETARG_LSEG_P(0);	LSEG	   *l2 = PG_GETARG_LSEG_P(1);	PG_RETURN_BOOL(FPlt(point_dt(&l1->p[0], &l1->p[1]),						point_dt(&l2->p[0], &l2->p[1])));}Datumlseg_le(PG_FUNCTION_ARGS){	LSEG	   *l1 = PG_GETARG_LSEG_P(0);	LSEG	   *l2 = PG_GETARG_LSEG_P(1);	PG_RETURN_BOOL(FPle(point_dt(&l1->p[0], &l1->p[1]),						point_dt(&l2->p[0], &l2->p[1])));}Datumlseg_gt(PG_FUNCTION_ARGS){	LSEG	   *l1 = PG_GETARG_LSEG_P(0);	LSEG	   *l2 = PG_GETARG_LSEG_P(1);	PG_RETURN_BOOL(FPgt(point_dt(&l1->p[0], &l1->p[1]),						point_dt(&l2->p[0], &l2->p[1])));}Datumlseg_ge(PG_FUNCTION_ARGS){	LSEG	   *l1 = PG_GETARG_LSEG_P(0);	LSEG	   *l2 = PG_GETARG_LSEG_P(1);	PG_RETURN_BOOL(FPge(point_dt(&l1->p[0], &l1->p[1]),						point_dt(&l2->p[0], &l2->p[1])));}/*---------------------------------------------------------- *	Line arithmetic routines. *---------------------------------------------------------*//* lseg_distance - *		If two segments don't intersect, then the closest *		point will be from one of the endpoints to the other *		segment. */Datumlseg_distance(PG_FUNCTION_ARGS){	LSEG	   *l1 = PG_GETARG_LSEG_P(0);	LSEG	   *l2 = PG_GETARG_LSEG_P(1);	PG_RETURN_FLOAT8(lseg_dt(l1, l2));}/* lseg_dt() * Distance between two line segments. * Must check both sets of endpoints to ensure minimum distance is found. * - thomas 1998-02-01 */static doublelseg_dt(LSEG *l1, LSEG *l2){	double		result,				d;	if (lseg_intersect_internal(l1, l2))		return 0.0;	d = dist_ps_internal(&l1->p[0], l2);	result = d;	d = dist_ps_internal(&l1->p[1], l2);	result = Min(result, d);	d = dist_ps_internal(&l2->p[0], l1);	result = Min(result, d);	d = dist_ps_internal(&l2->p[1], l1);	result = Min(result, d);	return result;}Datumlseg_center(PG_FUNCTION_ARGS){	LSEG	   *lseg = PG_GETARG_LSEG_P(0);	Point	   *result;	result = (Point *) palloc(sizeof(Point));	result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;	result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;	PG_RETURN_POINT_P(result);}/* lseg_interpt - *		Find the intersection point of two segments (if any). */Datumlseg_interpt(PG_FUNCTION_ARGS){	LSEG	   *l1 = PG_GETARG_LSEG_P(0);	LSEG	   *l2 = PG_GETARG_LSEG_P(1);	Point	   *result;	LINE		tmp1,				tmp2;	/*	 * Find the intersection of the appropriate lines, if any.	 */	line_construct_pts(&tmp1, &l1->p[0], &l1->p[1]);	line_construct_pts(&tmp2, &l2->p[0], &l2->p[1]);	result = line_interpt_internal(&tmp1, &tmp2);	if (!PointerIsValid(result))		PG_RETURN_NULL();	/*	 * If the line intersection point isn't within l1 (or equivalently	 * l2), there is no valid segment intersection point at all.	 */	if (!on_ps_internal(result, l1) ||		!on_ps_internal(result, l2))		PG_RETURN_NULL();	/*	 * If there is an intersection, then check explicitly for matching	 * endpoints since there may be rounding effects with annoying lsb	 * residue. - tgl 1997-07-09	 */	if ((FPeq(l1->p[0].x, l2->p[0].x) && FPeq(l1->p[0].y, l2->p[0].y)) ||		(FPeq(l1->p[0].x, l2->p[1].x) && FPeq(l1->p[0].y, l2->p[1].y)))	{		result->x = l1->p[0].x;		result->y = l1->p[0].y;	}	else if ((FPeq(l1->p[1].x, l2->p[0].x) && FPeq(l1->p[1].y, l2->p[0].y)) ||		  (FPeq(l1->p[1].x, l2->p[1].x) && FPeq(l1->p[1].y, l2->p[1].y)))	{		result->x = l1->p[1].x;		result->y = l1->p[1].y;	}	PG_RETURN_POINT_P(result);}/*********************************************************************** ** **		Routines for position comparisons of differently-typed **				2D objects. ** ***********************************************************************//*--------------------------------------------------------------------- *		dist_ *				Minimum distance from one object to another. *-------------------------------------------------------------------*/Datumdist_pl(PG_FUNCTION_ARGS){	Point	   *pt = PG_GETARG_POINT_P(0);	LINE	   *line = PG_GETARG_LINE_P(1);	PG_RETURN_FLOAT8(dist_pl_internal(pt, line));}static doubledist_pl_internal(Point *pt, LINE *line){	return (line->A * pt->x + line->B * pt->y + line->C) /		HYPOT(line->A, line->B);}Datumdist_ps(PG_FUNCTION_ARGS){	Point	   *pt = PG_GETARG_POINT_P(0);	LSEG	   *lseg = PG_GETARG_LSEG_P(1);	PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg));}static doubledist_ps_internal(Point *pt, LSEG *lseg){	double		m;				/* slope of perp. */	LINE	   *ln;	double		result,				tmpdist;	Point	   *ip;/* * Construct a line perpendicular to the input segment * and through the input point */	if (lseg->p[1].x == lseg->p[0].x)		m = 0;	else if (lseg->p[1].y == lseg->p[0].y)	{							/* slope is infinite */		m = (double) DBL_MAX;	}	else		m = ((lseg->p[0].y - lseg->p[1].y) / (lseg->p[1].x - lseg->p[0].x));	ln = line_construct_pm(pt, m);#ifdef GEODEBUG	printf("dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %g\n",		   ln->A, ln->B, ln->C, pt->x, pt->y, m);#endif	/*	 * Calculate distance to the line segment or to the endpoints of the	 * segment.	 */	/* intersection is on the line segment? */	if ((ip = interpt_sl(lseg, ln)) != NULL)	{		result = point_dt(pt, ip);#ifdef GEODEBUG		printf("dist_ps- distance is %f to intersection point is (%f,%f)\n",			   result, ip->x, ip->y);#endif	}	else	{		/* intersection is not on line segment */		result = point_dt(pt, &lseg->p[0]);		tmpdist = point_dt(pt, &lseg->p[1]);		if (tmpdist < result)			result = tmpdist;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?