📄 geo_ops.c
字号:
}Datumline_horizontal(PG_FUNCTION_ARGS){ LINE *line = PG_GETARG_LINE_P(0); PG_RETURN_BOOL(FPzero(line->A));}Datumline_eq(PG_FUNCTION_ARGS){ LINE *l1 = PG_GETARG_LINE_P(0); LINE *l2 = PG_GETARG_LINE_P(1); double k; if (!FPzero(l2->A)) k = l1->A / l2->A; else if (!FPzero(l2->B)) k = l1->B / l2->B; else if (!FPzero(l2->C)) k = l1->C / l2->C; else k = 1.0; PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) && FPeq(l1->B, k * l2->B) && FPeq(l1->C, k * l2->C));}/*---------------------------------------------------------- * Line arithmetic routines. *---------------------------------------------------------*//* line_distance() * Distance between two lines. */Datumline_distance(PG_FUNCTION_ARGS){ LINE *l1 = PG_GETARG_LINE_P(0); LINE *l2 = PG_GETARG_LINE_P(1); float8 result; Point *tmp; if (!DatumGetBool(DirectFunctionCall2(line_parallel, LinePGetDatum(l1), LinePGetDatum(l2)))) PG_RETURN_FLOAT8(0.0); if (FPzero(l1->B)) /* vertical? */ PG_RETURN_FLOAT8(fabs(l1->C - l2->C)); tmp = point_construct(0.0, l1->C); result = dist_pl_internal(tmp, l2); PG_RETURN_FLOAT8(result);}/* line_interpt() * Point where two lines l1, l2 intersect (if any) */Datumline_interpt(PG_FUNCTION_ARGS){ LINE *l1 = PG_GETARG_LINE_P(0); LINE *l2 = PG_GETARG_LINE_P(1); Point *result; result = line_interpt_internal(l1, l2); if (result == NULL) PG_RETURN_NULL(); PG_RETURN_POINT_P(result);}/* * Internal version of line_interpt * * returns a NULL pointer if no intersection point */static Point *line_interpt_internal(LINE *l1, LINE *l2){ Point *result; double x, y; /* * NOTE: if the lines are identical then we will find they are parallel * and report "no intersection". This is a little weird, but since * there's no *unique* intersection, maybe it's appropriate behavior. */ if (DatumGetBool(DirectFunctionCall2(line_parallel, LinePGetDatum(l1), LinePGetDatum(l2)))) return NULL;#ifdef NOT_USED if (FPzero(l1->B)) /* l1 vertical? */ result = point_construct(l2->m * l1->C + l2->C, l1->C); else if (FPzero(l2->B)) /* l2 vertical? */ result = point_construct(l1->m * l2->C + l1->C, l2->C); else { x = (l1->C - l2->C) / (l2->A - l1->A); result = point_construct(x, l1->m * x + l1->C); }#endif if (FPzero(l1->B)) /* l1 vertical? */ { x = l1->C; y = (l2->A * x + l2->C); } else if (FPzero(l2->B)) /* l2 vertical? */ { x = l2->C; y = (l1->A * x + l1->C); } else { x = (l1->C - l2->C) / (l2->A - l1->A); y = (l1->A * x + l1->C); } result = point_construct(x, y);#ifdef GEODEBUG printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n", DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C); printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);#endif return result;}/*********************************************************************** ** ** Routines for 2D paths (sequences of line segments, also ** called `polylines'). ** ** This is not a general package for geometric paths, ** which of course include polygons; the emphasis here ** is on (for example) usefulness in wire layout. ** ***********************************************************************//*---------------------------------------------------------- * String to path / path to string conversion. * External format: * "((xcoord, ycoord),... )" * "[(xcoord, ycoord),... ]" * "(xcoord, ycoord),... " * "[xcoord, ycoord,... ]" * Also support older format: * "(closed, npts, xcoord, ycoord,... )" *---------------------------------------------------------*/Datumpath_area(PG_FUNCTION_ARGS){ PATH *path = PG_GETARG_PATH_P(0); double area = 0.0; int i, j; if (!path->closed) PG_RETURN_NULL(); for (i = 0; i < path->npts; i++) { j = (i + 1) % path->npts; area += path->p[i].x * path->p[j].y; area -= path->p[i].y * path->p[j].x; } area *= 0.5; PG_RETURN_FLOAT8(area < 0.0 ? -area : area);}Datumpath_in(PG_FUNCTION_ARGS){ char *str = PG_GETARG_CSTRING(0); PATH *path; int isopen; char *s; int npts; int size; int depth = 0; if ((npts = pair_count(str, ',')) <= 0) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type path: \"%s\"", str))); s = str; while (isspace((unsigned char) *s)) s++; /* skip single leading paren */ if ((*s == LDELIM) && (strrchr(s, LDELIM) == s)) { s++; depth++; } size = offsetof(PATH, p[0]) +sizeof(path->p[0]) * npts; path = (PATH *) palloc(size); path->size = size; path->npts = npts; if ((!path_decode(TRUE, npts, s, &isopen, &s, &(path->p[0]))) && (!((depth == 0) && (*s == '\0'))) && !((depth >= 1) && (*s == RDELIM))) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type path: \"%s\"", str))); path->closed = (!isopen); PG_RETURN_PATH_P(path);}Datumpath_out(PG_FUNCTION_ARGS){ PATH *path = PG_GETARG_PATH_P(0); PG_RETURN_CSTRING(path_encode(path->closed, path->npts, path->p));}/* * path_recv - converts external binary format to path * * External representation is closed flag (a boolean byte), int32 number * of points, and the points. */Datumpath_recv(PG_FUNCTION_ARGS){ StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); PATH *path; int closed; int32 npts; int32 i; int size; closed = pq_getmsgbyte(buf); npts = pq_getmsgint(buf, sizeof(int32)); if (npts < 0 || npts >= (int32) ((INT_MAX - offsetof(PATH, p[0])) / sizeof(Point))) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid number of points in external \"path\" value"))); size = offsetof(PATH, p[0]) +sizeof(path->p[0]) * npts; path = (PATH *) palloc(size); path->size = size; path->npts = npts; path->closed = (closed ? 1 : 0); for (i = 0; i < npts; i++) { path->p[i].x = pq_getmsgfloat8(buf); path->p[i].y = pq_getmsgfloat8(buf); } PG_RETURN_PATH_P(path);}/* * path_send - converts path to binary format */Datumpath_send(PG_FUNCTION_ARGS){ PATH *path = PG_GETARG_PATH_P(0); StringInfoData buf; int32 i; pq_begintypsend(&buf); pq_sendbyte(&buf, path->closed ? 1 : 0); pq_sendint(&buf, path->npts, sizeof(int32)); for (i = 0; i < path->npts; i++) { pq_sendfloat8(&buf, path->p[i].x); pq_sendfloat8(&buf, path->p[i].y); } PG_RETURN_BYTEA_P(pq_endtypsend(&buf));}/*---------------------------------------------------------- * Relational operators. * These are based on the path cardinality, * as stupid as that sounds. * * Better relops and access methods coming soon. *---------------------------------------------------------*/Datumpath_n_lt(PG_FUNCTION_ARGS){ PATH *p1 = PG_GETARG_PATH_P(0); PATH *p2 = PG_GETARG_PATH_P(1); PG_RETURN_BOOL(p1->npts < p2->npts);}Datumpath_n_gt(PG_FUNCTION_ARGS){ PATH *p1 = PG_GETARG_PATH_P(0); PATH *p2 = PG_GETARG_PATH_P(1); PG_RETURN_BOOL(p1->npts > p2->npts);}Datumpath_n_eq(PG_FUNCTION_ARGS){ PATH *p1 = PG_GETARG_PATH_P(0); PATH *p2 = PG_GETARG_PATH_P(1); PG_RETURN_BOOL(p1->npts == p2->npts);}Datumpath_n_le(PG_FUNCTION_ARGS){ PATH *p1 = PG_GETARG_PATH_P(0); PATH *p2 = PG_GETARG_PATH_P(1); PG_RETURN_BOOL(p1->npts <= p2->npts);}Datumpath_n_ge(PG_FUNCTION_ARGS){ PATH *p1 = PG_GETARG_PATH_P(0); PATH *p2 = PG_GETARG_PATH_P(1); PG_RETURN_BOOL(p1->npts >= p2->npts);}/*---------------------------------------------------------- * Conversion operators. *---------------------------------------------------------*/Datumpath_isclosed(PG_FUNCTION_ARGS){ PATH *path = PG_GETARG_PATH_P(0); PG_RETURN_BOOL(path->closed);}Datumpath_isopen(PG_FUNCTION_ARGS){ PATH *path = PG_GETARG_PATH_P(0); PG_RETURN_BOOL(!path->closed);}Datumpath_npoints(PG_FUNCTION_ARGS){ PATH *path = PG_GETARG_PATH_P(0); PG_RETURN_INT32(path->npts);}Datumpath_close(PG_FUNCTION_ARGS){ PATH *path = PG_GETARG_PATH_P_COPY(0); path->closed = TRUE; PG_RETURN_PATH_P(path);}Datumpath_open(PG_FUNCTION_ARGS){ PATH *path = PG_GETARG_PATH_P_COPY(0); path->closed = FALSE; PG_RETURN_PATH_P(path);}/* path_inter - * Does p1 intersect p2 at any point? * Use bounding boxes for a quick (O(n)) check, then do a * O(n^2) iterative edge check. */Datumpath_inter(PG_FUNCTION_ARGS){ PATH *p1 = PG_GETARG_PATH_P(0); PATH *p2 = PG_GETARG_PATH_P(1); BOX b1, b2; int i, j; LSEG seg1, seg2; if (p1->npts <= 0 || p2->npts <= 0) PG_RETURN_BOOL(false); b1.high.x = b1.low.x = p1->p[0].x; b1.high.y = b1.low.y = p1->p[0].y; for (i = 1; i < p1->npts; i++) { b1.high.x = Max(p1->p[i].x, b1.high.x); b1.high.y = Max(p1->p[i].y, b1.high.y); b1.low.x = Min(p1->p[i].x, b1.low.x); b1.low.y = Min(p1->p[i].y, b1.low.y); } b2.high.x = b2.low.x = p2->p[0].x; b2.high.y = b2.low.y = p2->p[0].y; for (i = 1; i < p2->npts; i++) { b2.high.x = Max(p2->p[i].x, b2.high.x); b2.high.y = Max(p2->p[i].y, b2.high.y); b2.low.x = Min(p2->p[i].x, b2.low.x); b2.low.y = Min(p2->p[i].y, b2.low.y); } if (!box_ov(&b1, &b2)) PG_RETURN_BOOL(false); /* pairwise check lseg intersections */ for (i = 0; i < p1->npts; i++) { int iprev; if (i > 0) iprev = i - 1; else { if (!p1->closed) continue; iprev = p1->npts - 1; /* include the closure segment */ } for (j = 0; j < p2->npts; j++) { int jprev; if (j > 0) jprev = j - 1; else { if (!p2->closed) continue; jprev = p2->npts - 1; /* include the closure segment */ } statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]); statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]); if (lseg_intersect_internal(&seg1, &seg2)) PG_RETURN_BOOL(true); } } /* if we dropped through, no two segs intersected */ PG_RETURN_BOOL(false);}/* path_distance() * This essentially does a cartesian product of the lsegs in the * two paths, and finds the min distance between any two lsegs */Datumpath_distance(PG_FUNCTION_ARGS){ PATH *p1 = PG_GETARG_PATH_P(0); PATH *p2 = PG_GETARG_PATH_P(1); float8 min = 0.0; /* initialize to keep compiler quiet */ bool have_min = false; float8 tmp; int i, j; LSEG seg1, seg2; for (i = 0; i < p1->npts; i++) { int iprev; if (i > 0) iprev = i - 1; else { if (!p1->closed) continue; iprev = p1->npts - 1; /* include the closure segment */ } for (j = 0; j < p2->npts; j++) { int jprev; if (j > 0) jprev = j - 1; else { if (!p2->closed) continue; jprev = p2->npts - 1; /* include the closure segment */ } statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]); statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]); tmp = DatumGetFloat8(DirectFunctionCall2(lseg_distance, LsegPGetDatum(&seg1), LsegPGetDatum(&seg2))); if (!have_min || tmp < min) { min = tmp; have_min = true; } } } if (!have_min) PG_RETURN_NULL(); PG_RETURN_FLOAT8(min);}/*---------------------------------------------------------- * "Arithmetic" operations. *---------------------------------------------------------*/Datumpath_length(PG_FUNCTION_ARGS){ PATH *path = PG_GETARG_PATH_P(0); float8 result = 0.0; int i; for (i = 0; i < path->npts; i++) { int iprev; if (i > 0) iprev = i - 1; else { if (!path->closed) continue; iprev = path->npts - 1; /* include the closure segment */ } result += point_dt(&path->p[iprev], &path->p[i]); } PG_RETURN_FLOAT8(result);}/*********************************************************************** ** ** Routines for 2D points. ** ***********************************************************************//*---------------------------------------------------------- * String to point, point to string conversion. * External format: * "(x,y)" * "x,y" *---------------------------------------------------------*/Datumpoint_in(PG_FUNCTION_ARGS){ char *str = PG_GETARG_CSTRING(0); Point *point; double x, y; char *s; if (!pair_decode(str, &x, &y, &s) || (*s != '\0')) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type point: \"%s\"", str))); point = (Point *) palloc(sizeof(Point)); point->x = x; point->y = y;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -