mirror of
https://github.com/postgres/postgres.git
synced 2025-06-26 12:21:12 +03:00
Add point <-> polygon distance operator.
Alexander Korotkov, reviewed by Emre Hasegeli.
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1016,6 +1016,8 @@ DATA(insert OID = 1521 ( "#" PGNSP PGUID l f f 0 604 23 0 0 poly_npo
|
||||
DESCR("number of points");
|
||||
DATA(insert OID = 1522 ( "<->" PGNSP PGUID b f f 600 718 701 0 0 dist_pc - - ));
|
||||
DESCR("distance between");
|
||||
DATA(insert OID = 3276 ( "<->" PGNSP PGUID b f f 600 604 701 0 0 dist_ppoly - - ));
|
||||
DESCR("distance between");
|
||||
DATA(insert OID = 1523 ( "<->" PGNSP PGUID b f f 718 604 701 0 0 dist_cpoly - - ));
|
||||
DESCR("distance between");
|
||||
|
||||
|
@ -844,6 +844,7 @@ DATA(insert OID = 726 ( dist_lb PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 70
|
||||
DATA(insert OID = 727 ( dist_sl PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 701 "601 628" _null_ _null_ _null_ _null_ dist_sl _null_ _null_ _null_ ));
|
||||
DATA(insert OID = 728 ( dist_cpoly PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 701 "718 604" _null_ _null_ _null_ _null_ dist_cpoly _null_ _null_ _null_ ));
|
||||
DATA(insert OID = 729 ( poly_distance PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 701 "604 604" _null_ _null_ _null_ _null_ poly_distance _null_ _null_ _null_ ));
|
||||
DATA(insert OID = 3275 ( dist_ppoly PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 701 "600 604" _null_ _null_ _null_ _null_ dist_ppoly _null_ _null_ _null_ ));
|
||||
|
||||
DATA(insert OID = 740 ( text_lt PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "25 25" _null_ _null_ _null_ _null_ text_lt _null_ _null_ _null_ ));
|
||||
DATA(insert OID = 741 ( text_le PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "25 25" _null_ _null_ _null_ _null_ text_le _null_ _null_ _null_ ));
|
||||
|
@ -395,6 +395,7 @@ extern Datum circle_radius(PG_FUNCTION_ARGS);
|
||||
extern Datum circle_distance(PG_FUNCTION_ARGS);
|
||||
extern Datum dist_pc(PG_FUNCTION_ARGS);
|
||||
extern Datum dist_cpoly(PG_FUNCTION_ARGS);
|
||||
extern Datum dist_ppoly(PG_FUNCTION_ARGS);
|
||||
extern Datum circle_center(PG_FUNCTION_ARGS);
|
||||
extern Datum cr_circle(PG_FUNCTION_ARGS);
|
||||
extern Datum box_circle(PG_FUNCTION_ARGS);
|
||||
|
@ -279,3 +279,14 @@ SELECT '((200,800),(800,800),(800,200),(200,200))' && '(1000,1000,0,0)'::polygo
|
||||
t
|
||||
(1 row)
|
||||
|
||||
-- distance from a point
|
||||
SELECT '(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
|
||||
'(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
|
||||
'(2,2)'::point <-> '((0,0),(1,4),(3,1))'::polygon as inside,
|
||||
'(3,3)'::point <-> '((0,2),(2,0),(2,2))'::polygon as near_corner,
|
||||
'(4,4)'::point <-> '((0,0),(0,3),(4,0))'::polygon as near_segment;
|
||||
on_corner | on_segment | inside | near_corner | near_segment
|
||||
-----------+------------+--------+-----------------+--------------
|
||||
0 | 0 | 0 | 1.4142135623731 | 3.2
|
||||
(1 row)
|
||||
|
||||
|
@ -172,3 +172,10 @@ SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon && '((2,1),(2,3),(3,3),(3,1))'
|
||||
-- +-------+
|
||||
SELECT '((1,4),(1,1),(4,1),(4,2),(2,2),(2,4),(1,4))'::polygon && '((3,3),(4,3),(4,4),(3,4),(3,3))'::polygon AS "false";
|
||||
SELECT '((200,800),(800,800),(800,200),(200,200))' && '(1000,1000,0,0)'::polygon AS "true";
|
||||
|
||||
-- distance from a point
|
||||
SELECT '(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
|
||||
'(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
|
||||
'(2,2)'::point <-> '((0,0),(1,4),(3,1))'::polygon as inside,
|
||||
'(3,3)'::point <-> '((0,2),(2,0),(2,2))'::polygon as near_corner,
|
||||
'(4,4)'::point <-> '((0,0),(0,3),(4,0))'::polygon as near_segment;
|
||||
|
Reference in New Issue
Block a user