33 * geo_ops.c
44 * 2D geometric operations
55 *
6+ * This module implements the geometric functions and operators. The
7+ * geometric types are (from simple to more complicated):
8+ *
9+ * - point
10+ * - line
11+ * - line segment
12+ * - box
13+ * - circle
14+ * - polygon
15+ *
616 * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
717 * Portions Copyright (c) 1994, Regents of the University of California
818 *
2535#include "utils/fmgrprotos.h"
2636#include "utils/geo_decls.h"
2737
38+ /*
39+ * * Type constructors have this form:
40+ * void type_construct(Type *result, ...);
41+ *
42+ * * Operators commonly have signatures such as
43+ * void type1_operator_type2(Type *result, Type1 *obj1, Type2 *obj2);
44+ *
45+ * Common operators are:
46+ * * Intersection point:
47+ * bool type1_interpt_type2(Point *result, Type1 *obj1, Type2 *obj2);
48+ * Return whether the two objects intersect. If *result is not NULL,
49+ * it is set to the intersection point.
50+ *
51+ * * Containment:
52+ * bool type1_contain_type2(Type1 *obj1, Type2 *obj2);
53+ * Return whether obj1 contains obj2.
54+ * bool type1_contain_type2(Type1 *contains_obj, Type1 *contained_obj);
55+ * Return whether obj1 contains obj2 (used when types are the same)
56+ *
57+ * * Distance of closest point in or on obj1 to obj2:
58+ * float8 type1_closept_type2(Point *result, Type1 *obj1, Type2 *obj2);
59+ * Returns the shortest distance between two objects. If *result is not
60+ * NULL, it is set to the closest point in or on obj1 to obj2.
61+ *
62+ * These functions may be used to implement multiple SQL-level operators. For
63+ * example, determining whether two lines are parallel is done by checking
64+ * whether they don't intersect.
65+ */
2866
2967/*
3068 * Internal routines
@@ -64,7 +102,7 @@ static int lseg_crossing(float8 x, float8 y, float8 px, float8 py);
64102static bool lseg_contain_point (LSEG * lseg , Point * point );
65103static float8 lseg_closept_point (Point * result , LSEG * lseg , Point * pt );
66104static float8 lseg_closept_line (Point * result , LSEG * lseg , LINE * line );
67- static float8 lseg_closept_lseg (Point * result , LSEG * l1 , LSEG * l2 );
105+ static float8 lseg_closept_lseg (Point * result , LSEG * on_lseg , LSEG * to_lseg );
68106
69107/* Routines for boxes */
70108static inline void box_construct (BOX * result , Point * pt1 , Point * pt2 );
@@ -74,7 +112,7 @@ static float8 box_ar(BOX *box);
74112static float8 box_ht (BOX * box );
75113static float8 box_wd (BOX * box );
76114static bool box_contain_point (BOX * box , Point * point );
77- static bool box_contain_box (BOX * box1 , BOX * box2 );
115+ static bool box_contain_box (BOX * contains_box , BOX * contained_box );
78116static bool box_contain_lseg (BOX * box , LSEG * lseg );
79117static bool box_interpt_lseg (Point * result , BOX * box , LSEG * lseg );
80118static float8 box_closept_point (Point * result , BOX * box , Point * point );
@@ -87,7 +125,7 @@ static float8 circle_ar(CIRCLE *circle);
87125static void make_bound_box (POLYGON * poly );
88126static void poly_to_circle (CIRCLE * result , POLYGON * poly );
89127static bool lseg_inside_poly (Point * a , Point * b , POLYGON * poly , int start );
90- static bool poly_contain_poly (POLYGON * polya , POLYGON * polyb );
128+ static bool poly_contain_poly (POLYGON * contains_poly , POLYGON * contained_poly );
91129static bool plist_same (int npts , Point * p1 , Point * p2 );
92130static float8 dist_ppoly_internal (Point * pt , POLYGON * poly );
93131
@@ -648,15 +686,15 @@ box_contain(PG_FUNCTION_ARGS)
648686}
649687
650688/*
651- * Check whether the box is in the box or on its border
689+ * Check whether the second box is in the first box or on its border
652690 */
653691static bool
654- box_contain_box (BOX * box1 , BOX * box2 )
692+ box_contain_box (BOX * contains_box , BOX * contained_box )
655693{
656- return FPge (box1 -> high .x , box2 -> high .x ) &&
657- FPle (box1 -> low .x , box2 -> low .x ) &&
658- FPge (box1 -> high .y , box2 -> high .y ) &&
659- FPle (box1 -> low .y , box2 -> low .y );
694+ return FPge (contains_box -> high .x , contained_box -> high .x ) &&
695+ FPle (contains_box -> low .x , contained_box -> low .x ) &&
696+ FPge (contains_box -> high .y , contained_box -> high .y ) &&
697+ FPle (contains_box -> low .y , contained_box -> low .y );
660698}
661699
662700
@@ -1223,9 +1261,8 @@ line_interpt(PG_FUNCTION_ARGS)
12231261/*
12241262 * Internal version of line_interpt
12251263 *
1226- * This returns true if two lines intersect (they do, if they are not
1227- * parallel), false if they do not. This also sets the intersection point
1228- * to *result, if it is not NULL.
1264+ * Return whether two lines intersect. If *result is not NULL, it is set to
1265+ * the intersection point.
12291266 *
12301267 * NOTE: If the lines are identical then we will find they are parallel
12311268 * and report "no intersection". This is a little weird, but since
@@ -2244,10 +2281,9 @@ lseg_center(PG_FUNCTION_ARGS)
22442281
22452282
22462283/*
2247- * Find the intersection point of two segments (if any).
2284+ * Return whether the two segments intersect. If *result is not NULL,
2285+ * it is set to the intersection point.
22482286 *
2249- * This returns true if two line segments intersect, false if they do not.
2250- * This also sets the intersection point to *result, if it is not NULL.
22512287 * This function is almost perfectly symmetric, even though it doesn't look
22522288 * like it. See lseg_interpt_line() for the other half of it.
22532289 */
@@ -2507,11 +2543,8 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
25072543 *-------------------------------------------------------------------*/
25082544
25092545/*
2510- * Check if the line segment intersects with the line
2511- *
2512- * This returns true if line segment intersects with line, false if they
2513- * do not. This also sets the intersection point to *result, if it is not
2514- * NULL.
2546+ * Return whether the line segment intersect with the line. If *result is not
2547+ * NULL, it is set to the intersection point.
25152548 */
25162549static bool
25172550lseg_interpt_line (Point * result , LSEG * lseg , LINE * line )
@@ -2534,21 +2567,20 @@ lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
25342567 */
25352568 if (!lseg_contain_point (lseg , & interpt ))
25362569 return false;
2537-
2538- if (result == NULL )
2539- return true;
2540-
2541- /*
2542- * If there is an intersection, then check explicitly for matching
2543- * endpoints since there may be rounding effects with annoying LSB
2544- * residue.
2545- */
2546- if (point_eq_point (& lseg -> p [0 ], & interpt ))
2547- * result = lseg -> p [0 ];
2548- else if (point_eq_point (& lseg -> p [1 ], & interpt ))
2549- * result = lseg -> p [1 ];
2550- else
2551- * result = interpt ;
2570+ if (result != NULL )
2571+ {
2572+ /*
2573+ * If there is an intersection, then check explicitly for matching
2574+ * endpoints since there may be rounding effects with annoying LSB
2575+ * residue.
2576+ */
2577+ if (point_eq_point (& lseg -> p [0 ], & interpt ))
2578+ * result = lseg -> p [0 ];
2579+ else if (point_eq_point (& lseg -> p [1 ], & interpt ))
2580+ * result = lseg -> p [1 ];
2581+ else
2582+ * result = interpt ;
2583+ }
25522584
25532585 return true;
25542586}
@@ -2559,11 +2591,9 @@ lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
25592591 *-------------------------------------------------------------------*/
25602592
25612593/*
2562- * The intersection point of a perpendicular of the line
2563- * through the point.
2564- *
2565- * This sets the closest point to the *result if it is not NULL and returns
2566- * the distance to the closest point.
2594+ * If *result is not NULL, it is set to the intersection point of a
2595+ * perpendicular of the line through the point. Returns the distance
2596+ * of those two points.
25672597 */
25682598static float8
25692599line_closept_point (Point * result , LINE * line , Point * point )
@@ -2610,8 +2640,8 @@ close_pl(PG_FUNCTION_ARGS)
26102640/*
26112641 * Closest point on line segment to specified point.
26122642 *
2613- * This sets the closest point to the *result if it is not NULL and returns
2614- * the distance to the closest point .
2643+ * If *result is not NULL, set it to the closest point on the line segment
2644+ * to the point. Returns the distance of the two points .
26152645 */
26162646static float8
26172647lseg_closept_point (Point * result , LSEG * lseg , Point * pt )
@@ -2650,27 +2680,24 @@ close_ps(PG_FUNCTION_ARGS)
26502680
26512681/*
26522682 * Closest point on line segment to line segment
2653- *
2654- * This sets the closest point to the *result if it is not NULL and returns
2655- * the distance to the closest point.
26562683 */
26572684static float8
2658- lseg_closept_lseg (Point * result , LSEG * l1 , LSEG * l2 )
2685+ lseg_closept_lseg (Point * result , LSEG * on_lseg , LSEG * to_lseg )
26592686{
26602687 Point point ;
26612688 float8 dist ,
26622689 d ;
26632690
26642691 /* First, we handle the case when the line segments are intersecting. */
2665- if (lseg_interpt_lseg (result , l1 , l2 ))
2692+ if (lseg_interpt_lseg (result , on_lseg , to_lseg ))
26662693 return 0.0 ;
26672694
26682695 /*
26692696 * Then, we find the closest points from the endpoints of the second
26702697 * line segment, and keep the closest one.
26712698 */
2672- dist = lseg_closept_point (result , l1 , & l2 -> p [0 ]);
2673- d = lseg_closept_point (& point , l1 , & l2 -> p [1 ]);
2699+ dist = lseg_closept_point (result , on_lseg , & to_lseg -> p [0 ]);
2700+ d = lseg_closept_point (& point , on_lseg , & to_lseg -> p [1 ]);
26742701 if (float8_lt (d , dist ))
26752702 {
26762703 dist = d ;
@@ -2679,19 +2706,19 @@ lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
26792706 }
26802707
26812708 /* The closest point can still be one of the endpoints, so we test them. */
2682- d = lseg_closept_point (NULL , l2 , & l1 -> p [0 ]);
2709+ d = lseg_closept_point (NULL , to_lseg , & on_lseg -> p [0 ]);
26832710 if (float8_lt (d , dist ))
26842711 {
26852712 dist = d ;
26862713 if (result != NULL )
2687- * result = l1 -> p [0 ];
2714+ * result = on_lseg -> p [0 ];
26882715 }
2689- d = lseg_closept_point (NULL , l2 , & l1 -> p [1 ]);
2716+ d = lseg_closept_point (NULL , to_lseg , & on_lseg -> p [1 ]);
26902717 if (float8_lt (d , dist ))
26912718 {
26922719 dist = d ;
26932720 if (result != NULL )
2694- * result = l1 -> p [1 ];
2721+ * result = on_lseg -> p [1 ];
26952722 }
26962723
26972724 return dist ;
@@ -2719,8 +2746,8 @@ close_lseg(PG_FUNCTION_ARGS)
27192746/*
27202747 * Closest point on or in box to specified point.
27212748 *
2722- * This sets the closest point to the *result if it is not NULL and returns
2723- * the distance to the closest point .
2749+ * If *result is not NULL, set it to the closest point on the box to the
2750+ * given point, and return the distance of the two points .
27242751 */
27252752static float8
27262753box_closept_point (Point * result , BOX * box , Point * pt )
@@ -2837,11 +2864,11 @@ close_sl(PG_FUNCTION_ARGS)
28372864/*
28382865 * Closest point on line segment to line.
28392866 *
2840- * This sets the closest point to the *result if it is not NULL and returns
2841- * the distance to the closest point.
2867+ * Return the distance between the line and the closest point of the line
2868+ * segment to the line. If *result is not NULL, set it to that point.
28422869 *
28432870 * NOTE: When the lines are parallel, endpoints of one of the line segment
2844- * are FPeq(), in presence of NaN or Infinitive coordinates, or perhaps =
2871+ * are FPeq(), in presence of NaN or Infinite coordinates, or perhaps =
28452872 * even because of simple roundoff issues, there may not be a single closest
28462873 * point. We are likely to set the result to the second endpoint in these
28472874 * cases.
@@ -2896,8 +2923,8 @@ close_ls(PG_FUNCTION_ARGS)
28962923/*
28972924 * Closest point on or in box to line segment.
28982925 *
2899- * This sets the closest point to the *result if it is not NULL and returns
2900- * the distance to the closest point.
2926+ * Returns the distance between the closest point on or in the box to
2927+ * the line segment. If *result is not NULL, it is set to that point.
29012928 */
29022929static float8
29032930box_closept_lseg (Point * result , BOX * box , LSEG * lseg )
@@ -3753,7 +3780,7 @@ touched_lseg_inside_poly(Point *a, Point *b, LSEG *s, POLYGON *poly, int start)
37533780/*
37543781 * Returns true if segment (a,b) is in polygon, option
37553782 * start is used for optimization - function checks
3756- * polygon's edges started from start
3783+ * polygon's edges starting from start
37573784 */
37583785static bool
37593786lseg_inside_poly (Point * a , Point * b , POLYGON * poly , int start )
@@ -3821,29 +3848,30 @@ lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
38213848 return res ;
38223849}
38233850
3824- /*-----------------------------------------------------------------
3825- * Determine if polygon A contains polygon B.
3826- *-----------------------------------------------------------------* /
3851+ /*
3852+ * Check whether the first polygon contains the second
3853+ */
38273854static bool
3828- poly_contain_poly (POLYGON * polya , POLYGON * polyb )
3855+ poly_contain_poly (POLYGON * contains_poly , POLYGON * contained_poly )
38293856{
38303857 int i ;
38313858 LSEG s ;
38323859
3833- Assert (polya -> npts > 0 && polyb -> npts > 0 );
3860+ Assert (contains_poly -> npts > 0 && contained_poly -> npts > 0 );
38343861
38353862 /*
3836- * Quick check to see if bounding box is contained.
3863+ * Quick check to see if contained's bounding box is contained in
3864+ * contains' bb.
38373865 */
3838- if (!box_contain_box (& polya -> boundbox , & polyb -> boundbox ))
3866+ if (!box_contain_box (& contains_poly -> boundbox , & contained_poly -> boundbox ))
38393867 return false;
38403868
3841- s .p [0 ] = polyb -> p [polyb -> npts - 1 ];
3869+ s .p [0 ] = contained_poly -> p [contained_poly -> npts - 1 ];
38423870
3843- for (i = 0 ; i < polyb -> npts ; i ++ )
3871+ for (i = 0 ; i < contained_poly -> npts ; i ++ )
38443872 {
3845- s .p [1 ] = polyb -> p [i ];
3846- if (!lseg_inside_poly (s .p , s .p + 1 , polya , 0 ))
3873+ s .p [1 ] = contained_poly -> p [i ];
3874+ if (!lseg_inside_poly (s .p , s .p + 1 , contains_poly , 0 ))
38473875 return false;
38483876 s .p [0 ] = s .p [1 ];
38493877 }
0 commit comments