Skip to content

Commit 4520ba6

Browse files
committed
Add point <-> polygon distance operator.
Alexander Korotkov, reviewed by Emre Hasegeli.
1 parent ee3bec5 commit 4520ba6

File tree

6 files changed

+82
-16
lines changed

6 files changed

+82
-16
lines changed

src/backend/utils/adt/geo_ops.c

Lines changed: 60 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ static double dist_ps_internal(Point *pt, LSEG *lseg);
7373
static Point *line_interpt_internal(LINE *l1, LINE *l2);
7474
static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
7575
static Point *lseg_interpt_internal(LSEG *l1, LSEG *l2);
76+
static double dist_ppoly_internal(Point *pt, POLYGON *poly);
7677

7778

7879
/*
@@ -2415,6 +2416,9 @@ lseg_interpt(PG_FUNCTION_ARGS)
24152416
* Minimum distance from one object to another.
24162417
*-------------------------------------------------------------------*/
24172418

2419+
/*
2420+
* Distance from a point to a line
2421+
*/
24182422
Datum
24192423
dist_pl(PG_FUNCTION_ARGS)
24202424
{
@@ -2431,6 +2435,9 @@ dist_pl_internal(Point *pt, LINE *line)
24312435
HYPOT(line->A, line->B));
24322436
}
24332437

2438+
/*
2439+
* Distance from a point to a lseg
2440+
*/
24342441
Datum
24352442
dist_ps(PG_FUNCTION_ARGS)
24362443
{
@@ -2494,7 +2501,7 @@ dist_ps_internal(Point *pt, LSEG *lseg)
24942501
}
24952502

24962503
/*
2497-
** Distance from a point to a path
2504+
* Distance from a point to a path
24982505
*/
24992506
Datum
25002507
dist_ppath(PG_FUNCTION_ARGS)
@@ -2550,6 +2557,9 @@ dist_ppath(PG_FUNCTION_ARGS)
25502557
PG_RETURN_FLOAT8(result);
25512558
}
25522559

2560+
/*
2561+
* Distance from a point to a box
2562+
*/
25532563
Datum
25542564
dist_pb(PG_FUNCTION_ARGS)
25552565
{
@@ -2566,7 +2576,9 @@ dist_pb(PG_FUNCTION_ARGS)
25662576
PG_RETURN_FLOAT8(result);
25672577
}
25682578

2569-
2579+
/*
2580+
* Distance from a lseg to a line
2581+
*/
25702582
Datum
25712583
dist_sl(PG_FUNCTION_ARGS)
25722584
{
@@ -2589,7 +2601,9 @@ dist_sl(PG_FUNCTION_ARGS)
25892601
PG_RETURN_FLOAT8(result);
25902602
}
25912603

2592-
2604+
/*
2605+
* Distance from a lseg to a box
2606+
*/
25932607
Datum
25942608
dist_sb(PG_FUNCTION_ARGS)
25952609
{
@@ -2608,7 +2622,9 @@ dist_sb(PG_FUNCTION_ARGS)
26082622
PG_RETURN_DATUM(result);
26092623
}
26102624

2611-
2625+
/*
2626+
* Distance from a line to a box
2627+
*/
26122628
Datum
26132629
dist_lb(PG_FUNCTION_ARGS)
26142630
{
@@ -2625,21 +2641,53 @@ dist_lb(PG_FUNCTION_ARGS)
26252641
PG_RETURN_NULL();
26262642
}
26272643

2628-
2644+
/*
2645+
* Distance from a circle to a polygon
2646+
*/
26292647
Datum
26302648
dist_cpoly(PG_FUNCTION_ARGS)
26312649
{
26322650
CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
26332651
POLYGON *poly = PG_GETARG_POLYGON_P(1);
26342652
float8 result;
2653+
2654+
/* calculate distance to center, and subtract radius */
2655+
result = dist_ppoly_internal(&circle->center, poly);
2656+
2657+
result -= circle->radius;
2658+
if (result < 0)
2659+
result = 0;
2660+
2661+
PG_RETURN_FLOAT8(result);
2662+
}
2663+
2664+
/*
2665+
* Distance from a point to a polygon
2666+
*/
2667+
Datum
2668+
dist_ppoly(PG_FUNCTION_ARGS)
2669+
{
2670+
Point *point = PG_GETARG_POINT_P(0);
2671+
POLYGON *poly = PG_GETARG_POLYGON_P(1);
2672+
float8 result;
2673+
2674+
result = dist_ppoly_internal(point, poly);
2675+
2676+
PG_RETURN_FLOAT8(result);
2677+
}
2678+
2679+
static double
2680+
dist_ppoly_internal(Point *pt, POLYGON *poly)
2681+
{
2682+
float8 result;
26352683
float8 d;
26362684
int i;
26372685
LSEG seg;
26382686

2639-
if (point_inside(&(circle->center), poly->npts, poly->p) != 0)
2687+
if (point_inside(pt, poly->npts, poly->p) != 0)
26402688
{
26412689
#ifdef GEODEBUG
2642-
printf("dist_cpoly- center inside of polygon\n");
2690+
printf("dist_ppoly_internal- point inside of polygon\n");
26432691
#endif
26442692
PG_RETURN_FLOAT8(0.0);
26452693
}
@@ -2649,9 +2697,9 @@ dist_cpoly(PG_FUNCTION_ARGS)
26492697
seg.p[0].y = poly->p[0].y;
26502698
seg.p[1].x = poly->p[poly->npts - 1].x;
26512699
seg.p[1].y = poly->p[poly->npts - 1].y;
2652-
result = dist_ps_internal(&circle->center, &seg);
2700+
result = dist_ps_internal(pt, &seg);
26532701
#ifdef GEODEBUG
2654-
printf("dist_cpoly- segment 0/n distance is %f\n", result);
2702+
printf("dist_ppoly_internal- segment 0/n distance is %f\n", result);
26552703
#endif
26562704

26572705
/* check distances for other segments */
@@ -2661,19 +2709,15 @@ dist_cpoly(PG_FUNCTION_ARGS)
26612709
seg.p[0].y = poly->p[i].y;
26622710
seg.p[1].x = poly->p[i + 1].x;
26632711
seg.p[1].y = poly->p[i + 1].y;
2664-
d = dist_ps_internal(&circle->center, &seg);
2712+
d = dist_ps_internal(pt, &seg);
26652713
#ifdef GEODEBUG
2666-
printf("dist_cpoly- segment %d distance is %f\n", (i + 1), d);
2714+
printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
26672715
#endif
26682716
if (d < result)
26692717
result = d;
26702718
}
26712719

2672-
result -= circle->radius;
2673-
if (result < 0)
2674-
result = 0;
2675-
2676-
PG_RETURN_FLOAT8(result);
2720+
return result;
26772721
}
26782722

26792723

src/include/catalog/pg_operator.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,6 +1016,8 @@ DATA(insert OID = 1521 ( "#" PGNSP PGUID l f f 0 604 23 0 0 poly_npo
10161016
DESCR("number of points");
10171017
DATA(insert OID = 1522 ( "<->" PGNSP PGUID b f f 600 718 701 0 0 dist_pc - - ));
10181018
DESCR("distance between");
1019+
DATA(insert OID = 3276 ( "<->" PGNSP PGUID b f f 600 604 701 0 0 dist_ppoly - - ));
1020+
DESCR("distance between");
10191021
DATA(insert OID = 1523 ( "<->" PGNSP PGUID b f f 718 604 701 0 0 dist_cpoly - - ));
10201022
DESCR("distance between");
10211023

src/include/catalog/pg_proc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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
844844
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_ ));
845845
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_ ));
846846
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_ ));
847+
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_ ));
847848

848849
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_ ));
849850
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_ ));

src/include/utils/geo_decls.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ extern Datum circle_radius(PG_FUNCTION_ARGS);
395395
extern Datum circle_distance(PG_FUNCTION_ARGS);
396396
extern Datum dist_pc(PG_FUNCTION_ARGS);
397397
extern Datum dist_cpoly(PG_FUNCTION_ARGS);
398+
extern Datum dist_ppoly(PG_FUNCTION_ARGS);
398399
extern Datum circle_center(PG_FUNCTION_ARGS);
399400
extern Datum cr_circle(PG_FUNCTION_ARGS);
400401
extern Datum box_circle(PG_FUNCTION_ARGS);

src/test/regress/expected/polygon.out

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,3 +279,14 @@ SELECT '((200,800),(800,800),(800,200),(200,200))' && '(1000,1000,0,0)'::polygo
279279
t
280280
(1 row)
281281

282+
-- distance from a point
283+
SELECT '(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
284+
'(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
285+
'(2,2)'::point <-> '((0,0),(1,4),(3,1))'::polygon as inside,
286+
'(3,3)'::point <-> '((0,2),(2,0),(2,2))'::polygon as near_corner,
287+
'(4,4)'::point <-> '((0,0),(0,3),(4,0))'::polygon as near_segment;
288+
on_corner | on_segment | inside | near_corner | near_segment
289+
-----------+------------+--------+-----------------+--------------
290+
0 | 0 | 0 | 1.4142135623731 | 3.2
291+
(1 row)
292+

src/test/regress/sql/polygon.sql

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,3 +172,10 @@ SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon && '((2,1),(2,3),(3,3),(3,1))'
172172
-- +-------+
173173
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";
174174
SELECT '((200,800),(800,800),(800,200),(200,200))' && '(1000,1000,0,0)'::polygon AS "true";
175+
176+
-- distance from a point
177+
SELECT '(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
178+
'(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
179+
'(2,2)'::point <-> '((0,0),(1,4),(3,1))'::polygon as inside,
180+
'(3,3)'::point <-> '((0,2),(2,0),(2,2))'::polygon as near_corner,
181+
'(4,4)'::point <-> '((0,0),(0,3),(4,0))'::polygon as near_segment;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy