📄 geo_ops.c
字号:
/*------------------------------------------------------------------------- * * geo_ops.c * 2D geometric operations * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/utils/adt/geo_ops.c,v 1.91 2005/10/15 02:49:28 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <math.h>#include <limits.h>#include <float.h>#include <ctype.h>#include "libpq/pqformat.h"#include "utils/builtins.h"#include "utils/geo_decls.h"#ifndef M_PI#define M_PI 3.14159265358979323846#endif/* * Internal routines */static int point_inside(Point *p, int npts, Point *plist);static int lseg_crossing(double x, double y, double px, double py);static BOX *box_construct(double x1, double x2, double y1, double y2);static BOX *box_copy(BOX *box);static BOX *box_fill(BOX *result, double x1, double x2, double y1, double y2);static bool box_ov(BOX *box1, BOX *box2);static double box_ht(BOX *box);static double box_wd(BOX *box);static double circle_ar(CIRCLE *circle);static CIRCLE *circle_copy(CIRCLE *circle);static LINE *line_construct_pm(Point *pt, double m);static void line_construct_pts(LINE *line, Point *pt1, Point *pt2);static bool lseg_intersect_internal(LSEG *l1, LSEG *l2);static double lseg_dt(LSEG *l1, LSEG *l2);static bool on_ps_internal(Point *pt, LSEG *lseg);static void make_bound_box(POLYGON *poly);static bool plist_same(int npts, Point *p1, Point *p2);static Point *point_construct(double x, double y);static Point *point_copy(Point *pt);static int single_decode(char *str, float8 *x, char **ss);static int single_encode(float8 x, char *str);static int pair_decode(char *str, float8 *x, float8 *y, char **s);static int pair_encode(float8 x, float8 y, char *str);static int pair_count(char *s, char delim);static int path_decode(int opentype, int npts, char *str, int *isopen, char **ss, Point *p);static char *path_encode(bool closed, int npts, Point *pt);static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);static double box_ar(BOX *box);static void box_cn(Point *center, BOX *box);static Point *interpt_sl(LSEG *lseg, LINE *line);static bool has_interpt_sl(LSEG *lseg, LINE *line);static double dist_pl_internal(Point *pt, LINE *line);static double dist_ps_internal(Point *pt, LSEG *lseg);static Point *line_interpt_internal(LINE *l1, LINE *l2);/* * Delimiters for input and output strings. * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively. * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints. */#define LDELIM '('#define RDELIM ')'#define DELIM ','#define LDELIM_EP '['#define RDELIM_EP ']'#define LDELIM_C '<'#define RDELIM_C '>'/* Maximum number of characters printed by pair_encode() *//* ...+2+7 : 2 accounts for extra_float_digits max value */#define P_MAXLEN (2*(DBL_DIG+2+7)+1)/* * Geometric data types are composed of points. * This code tries to support a common format throughout the data types, * to allow for more predictable usage and data type conversion. * The fundamental unit is the point. Other units are line segments, * open paths, boxes, closed paths, and polygons (which should be considered * non-intersecting closed paths). * * Data representation is as follows: * point: (x,y) * line segment: [(x1,y1),(x2,y2)] * box: (x1,y1),(x2,y2) * open path: [(x1,y1),...,(xn,yn)] * closed path: ((x1,y1),...,(xn,yn)) * polygon: ((x1,y1),...,(xn,yn)) * * For boxes, the points are opposite corners with the first point at the top right. * For closed paths and polygons, the points should be reordered to allow * fast and correct equality comparisons. * * XXX perhaps points in complex shapes should be reordered internally * to allow faster internal operations, but should keep track of input order * and restore that order for text output - tgl 97/01/16 */static intsingle_decode(char *str, float8 *x, char **s){ char *cp; if (!PointerIsValid(str)) return FALSE; while (isspace((unsigned char) *str)) str++; *x = strtod(str, &cp);#ifdef GEODEBUG printf("single_decode- (%x) try decoding %s to %g\n", (cp - str), str, *x);#endif if (cp <= str) return FALSE; while (isspace((unsigned char) *cp)) cp++; if (s != NULL) *s = cp; return TRUE;} /* single_decode() */static intsingle_encode(float8 x, char *str){ int ndig = DBL_DIG + extra_float_digits; if (ndig < 1) ndig = 1; sprintf(str, "%.*g", ndig, x); return TRUE;} /* single_encode() */static intpair_decode(char *str, float8 *x, float8 *y, char **s){ int has_delim; char *cp; if (!PointerIsValid(str)) return FALSE; while (isspace((unsigned char) *str)) str++; if ((has_delim = (*str == LDELIM))) str++; while (isspace((unsigned char) *str)) str++; *x = strtod(str, &cp); if (cp <= str) return FALSE; while (isspace((unsigned char) *cp)) cp++; if (*cp++ != DELIM) return FALSE; while (isspace((unsigned char) *cp)) cp++; *y = strtod(cp, &str); if (str <= cp) return FALSE; while (isspace((unsigned char) *str)) str++; if (has_delim) { if (*str != RDELIM) return FALSE; str++; while (isspace((unsigned char) *str)) str++; } if (s != NULL) *s = str; return TRUE;}static intpair_encode(float8 x, float8 y, char *str){ int ndig = DBL_DIG + extra_float_digits; if (ndig < 1) ndig = 1; sprintf(str, "%.*g,%.*g", ndig, x, ndig, y); return TRUE;}static intpath_decode(int opentype, int npts, char *str, int *isopen, char **ss, Point *p){ int depth = 0; char *s, *cp; int i; s = str; while (isspace((unsigned char) *s)) s++; if ((*isopen = (*s == LDELIM_EP))) { /* no open delimiter allowed? */ if (!opentype) return FALSE; depth++; s++; while (isspace((unsigned char) *s)) s++; } else if (*s == LDELIM) { cp = (s + 1); while (isspace((unsigned char) *cp)) cp++; if (*cp == LDELIM) {#ifdef NOT_USED /* nested delimiters with only one point? */ if (npts <= 1) return FALSE;#endif depth++; s = cp; } else if (strrchr(s, LDELIM) == s) { depth++; s = cp; } } for (i = 0; i < npts; i++) { if (!pair_decode(s, &(p->x), &(p->y), &s)) return FALSE; if (*s == DELIM) s++; p++; } while (depth > 0) { if ((*s == RDELIM) || ((*s == RDELIM_EP) && (*isopen) && (depth == 1))) { depth--; s++; while (isspace((unsigned char) *s)) s++; } else return FALSE; } *ss = s; return TRUE;} /* path_decode() */static char *path_encode(bool closed, int npts, Point *pt){ int size = npts * (P_MAXLEN + 3) + 2; char *result; char *cp; int i; /* Check for integer overflow */ if ((size - 2) / npts != (P_MAXLEN + 3)) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("too many points requested"))); result = palloc(size); cp = result; switch (closed) { case TRUE: *cp++ = LDELIM; break; case FALSE: *cp++ = LDELIM_EP; break; default: break; } for (i = 0; i < npts; i++) { *cp++ = LDELIM; if (!pair_encode(pt->x, pt->y, cp)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not format \"path\" value"))); cp += strlen(cp); *cp++ = RDELIM; *cp++ = DELIM; pt++; } cp--; switch (closed) { case TRUE: *cp++ = RDELIM; break; case FALSE: *cp++ = RDELIM_EP; break; default: break; } *cp = '\0'; return result;} /* path_encode() *//*------------------------------------------------------------- * pair_count - count the number of points * allow the following notation: * '((1,2),(3,4))' * '(1,3,2,4)' * require an odd number of delim characters in the string *-------------------------------------------------------------*/static intpair_count(char *s, char delim){ int ndelim = 0; while ((s = strchr(s, delim)) != NULL) { ndelim++; s++; } return (ndelim % 2) ? ((ndelim + 1) / 2) : -1;}/*********************************************************************** ** ** Routines for two-dimensional boxes. ** ***********************************************************************//*---------------------------------------------------------- * Formatting and conversion routines. *---------------------------------------------------------*//* box_in - convert a string to internal form. * * External format: (two corners of box) * "(f8, f8), (f8, f8)" * also supports the older style "(f8, f8, f8, f8)" */Datumbox_in(PG_FUNCTION_ARGS){ char *str = PG_GETARG_CSTRING(0); BOX *box = (BOX *) palloc(sizeof(BOX)); int isopen; char *s; double x, y; if ((!path_decode(FALSE, 2, str, &isopen, &s, &(box->high))) || (*s != '\0')) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type box: \"%s\"", str))); /* reorder corners if necessary... */ if (box->high.x < box->low.x) { x = box->high.x; box->high.x = box->low.x; box->low.x = x; } if (box->high.y < box->low.y) { y = box->high.y; box->high.y = box->low.y; box->low.y = y; } PG_RETURN_BOX_P(box);}/* box_out - convert a box to external form. */Datumbox_out(PG_FUNCTION_ARGS){ BOX *box = PG_GETARG_BOX_P(0); PG_RETURN_CSTRING(path_encode(-1, 2, &(box->high)));}/* * box_recv - converts external binary format to box */Datumbox_recv(PG_FUNCTION_ARGS){ StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); BOX *box; double x, y; box = (BOX *) palloc(sizeof(BOX)); box->high.x = pq_getmsgfloat8(buf); box->high.y = pq_getmsgfloat8(buf); box->low.x = pq_getmsgfloat8(buf); box->low.y = pq_getmsgfloat8(buf); /* reorder corners if necessary... */ if (box->high.x < box->low.x) { x = box->high.x; box->high.x = box->low.x; box->low.x = x; } if (box->high.y < box->low.y) { y = box->high.y; box->high.y = box->low.y; box->low.y = y; } PG_RETURN_BOX_P(box);}/* * box_send - converts box to binary format */Datumbox_send(PG_FUNCTION_ARGS){ BOX *box = PG_GETARG_BOX_P(0); StringInfoData buf; pq_begintypsend(&buf); pq_sendfloat8(&buf, box->high.x); pq_sendfloat8(&buf, box->high.y); pq_sendfloat8(&buf, box->low.x); pq_sendfloat8(&buf, box->low.y); PG_RETURN_BYTEA_P(pq_endtypsend(&buf));}/* box_construct - fill in a new box. */static BOX *box_construct(double x1, double x2, double y1, double y2){ BOX *result = (BOX *) palloc(sizeof(BOX)); return box_fill(result, x1, x2, y1, y2);}/* box_fill - fill in a given box struct */static BOX *box_fill(BOX *result, double x1, double x2, double y1, double y2){ if (x1 > x2) { result->high.x = x1; result->low.x = x2; } else { result->high.x = x2; result->low.x = x1; } if (y1 > y2) { result->high.y = y1; result->low.y = y2; } else { result->high.y = y2; result->low.y = y1; } return result;}/* box_copy - copy a box */static BOX *box_copy(BOX *box){ BOX *result = (BOX *) palloc(sizeof(BOX)); memcpy((char *) result, (char *) box, sizeof(BOX)); return result;}/*---------------------------------------------------------- * Relational operators for BOXes. * <, >, <=, >=, and == are based on box area. *---------------------------------------------------------*//* box_same - are two boxes identical? */Datumbox_same(PG_FUNCTION_ARGS){ BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); PG_RETURN_BOOL(FPeq(box1->high.x, box2->high.x) && FPeq(box1->low.x, box2->low.x) && FPeq(box1->high.y, box2->high.y) && FPeq(box1->low.y, box2->low.y));}/* box_overlap - does box1 overlap box2? */Datumbox_overlap(PG_FUNCTION_ARGS){ BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); PG_RETURN_BOOL(box_ov(box1, box2));}static boolbox_ov(BOX *box1, BOX *box2){ return ((FPge(box1->high.x, box2->high.x) && FPle(box1->low.x, box2->high.x)) || (FPge(box2->high.x, box1->high.x) && FPle(box2->low.x, box1->high.x))) && ((FPge(box1->high.y, box2->high.y) && FPle(box1->low.y, box2->high.y)) || (FPge(box2->high.y, box1->high.y) && FPle(box2->low.y, box1->high.y)));}/* box_left - is box1 strictly left of box2? */Datumbox_left(PG_FUNCTION_ARGS){ BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); PG_RETURN_BOOL(FPlt(box1->high.x, box2->low.x));}/* box_overleft - is the right edge of box1 at or left of * the right edge of box2? * * This is "less than or equal" for the end of a time range, * when time ranges are stored as rectangles. */Datumbox_overleft(PG_FUNCTION_ARGS){ BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1); PG_RETURN_BOOL(FPle(box1->high.x, box2->high.x));}/* box_right - is box1 strictly right of box2? */Datumbox_right(PG_FUNCTION_ARGS){ BOX *box1 = PG_GETARG_BOX_P(0); BOX *box2 = PG_GETARG_BOX_P(1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -