summaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/geo_ops.c
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2014-12-15 17:02:49 +0200
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2014-12-15 17:06:21 +0200
commit4520ba67691fc13bb8be2cc47dd0bf8c7ab94205 (patch)
treec940b9142808d6329b17fc8923d214c8bc01f8ac /src/backend/utils/adt/geo_ops.c
parentee3bec5e22f7aed4d9086bec45a8d1821a9e236c (diff)
downloadpostgresql-4520ba67691fc13bb8be2cc47dd0bf8c7ab94205.tar.gz
Add point <-> polygon distance operator.
Alexander Korotkov, reviewed by Emre Hasegeli.
Diffstat (limited to 'src/backend/utils/adt/geo_ops.c')
-rw-r--r--src/backend/utils/adt/geo_ops.c76
1 files changed, 60 insertions, 16 deletions
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 54391fd7ab..946dc2893d 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -73,6 +73,7 @@ static double dist_ps_internal(Point *pt, LSEG *lseg);
static Point *line_interpt_internal(LINE *l1, LINE *l2);
static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
static Point *lseg_interpt_internal(LSEG *l1, LSEG *l2);
+static double dist_ppoly_internal(Point *pt, POLYGON *poly);
/*
@@ -2415,6 +2416,9 @@ lseg_interpt(PG_FUNCTION_ARGS)
* Minimum distance from one object to another.
*-------------------------------------------------------------------*/
+/*
+ * Distance from a point to a line
+ */
Datum
dist_pl(PG_FUNCTION_ARGS)
{
@@ -2431,6 +2435,9 @@ dist_pl_internal(Point *pt, LINE *line)
HYPOT(line->A, line->B));
}
+/*
+ * Distance from a point to a lseg
+ */
Datum
dist_ps(PG_FUNCTION_ARGS)
{
@@ -2494,7 +2501,7 @@ dist_ps_internal(Point *pt, LSEG *lseg)
}
/*
- ** Distance from a point to a path
+ * Distance from a point to a path
*/
Datum
dist_ppath(PG_FUNCTION_ARGS)
@@ -2550,6 +2557,9 @@ dist_ppath(PG_FUNCTION_ARGS)
PG_RETURN_FLOAT8(result);
}
+/*
+ * Distance from a point to a box
+ */
Datum
dist_pb(PG_FUNCTION_ARGS)
{
@@ -2566,7 +2576,9 @@ dist_pb(PG_FUNCTION_ARGS)
PG_RETURN_FLOAT8(result);
}
-
+/*
+ * Distance from a lseg to a line
+ */
Datum
dist_sl(PG_FUNCTION_ARGS)
{
@@ -2589,7 +2601,9 @@ dist_sl(PG_FUNCTION_ARGS)
PG_RETURN_FLOAT8(result);
}
-
+/*
+ * Distance from a lseg to a box
+ */
Datum
dist_sb(PG_FUNCTION_ARGS)
{
@@ -2608,7 +2622,9 @@ dist_sb(PG_FUNCTION_ARGS)
PG_RETURN_DATUM(result);
}
-
+/*
+ * Distance from a line to a box
+ */
Datum
dist_lb(PG_FUNCTION_ARGS)
{
@@ -2625,21 +2641,53 @@ dist_lb(PG_FUNCTION_ARGS)
PG_RETURN_NULL();
}
-
+/*
+ * Distance from a circle to a polygon
+ */
Datum
dist_cpoly(PG_FUNCTION_ARGS)
{
CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
POLYGON *poly = PG_GETARG_POLYGON_P(1);
float8 result;
+
+ /* calculate distance to center, and subtract radius */
+ result = dist_ppoly_internal(&circle->center, poly);
+
+ result -= circle->radius;
+ if (result < 0)
+ result = 0;
+
+ PG_RETURN_FLOAT8(result);
+}
+
+/*
+ * Distance from a point to a polygon
+ */
+Datum
+dist_ppoly(PG_FUNCTION_ARGS)
+{
+ Point *point = PG_GETARG_POINT_P(0);
+ POLYGON *poly = PG_GETARG_POLYGON_P(1);
+ float8 result;
+
+ result = dist_ppoly_internal(point, poly);
+
+ PG_RETURN_FLOAT8(result);
+}
+
+static double
+dist_ppoly_internal(Point *pt, POLYGON *poly)
+{
+ float8 result;
float8 d;
int i;
LSEG seg;
- if (point_inside(&(circle->center), poly->npts, poly->p) != 0)
+ if (point_inside(pt, poly->npts, poly->p) != 0)
{
#ifdef GEODEBUG
- printf("dist_cpoly- center inside of polygon\n");
+ printf("dist_ppoly_internal- point inside of polygon\n");
#endif
PG_RETURN_FLOAT8(0.0);
}
@@ -2649,9 +2697,9 @@ dist_cpoly(PG_FUNCTION_ARGS)
seg.p[0].y = poly->p[0].y;
seg.p[1].x = poly->p[poly->npts - 1].x;
seg.p[1].y = poly->p[poly->npts - 1].y;
- result = dist_ps_internal(&circle->center, &seg);
+ result = dist_ps_internal(pt, &seg);
#ifdef GEODEBUG
- printf("dist_cpoly- segment 0/n distance is %f\n", result);
+ printf("dist_ppoly_internal- segment 0/n distance is %f\n", result);
#endif
/* check distances for other segments */
@@ -2661,19 +2709,15 @@ dist_cpoly(PG_FUNCTION_ARGS)
seg.p[0].y = poly->p[i].y;
seg.p[1].x = poly->p[i + 1].x;
seg.p[1].y = poly->p[i + 1].y;
- d = dist_ps_internal(&circle->center, &seg);
+ d = dist_ps_internal(pt, &seg);
#ifdef GEODEBUG
- printf("dist_cpoly- segment %d distance is %f\n", (i + 1), d);
+ printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
#endif
if (d < result)
result = d;
}
- result -= circle->radius;
- if (result < 0)
- result = 0;
-
- PG_RETURN_FLOAT8(result);
+ return result;
}