mirror of
https://github.com/postgres/postgres.git
synced 2025-07-31 22:04:40 +03:00
geo_ops.c: Clarify comments and function arguments
These functions were not crystal clear about what their respective APIs are. Make an effort to improve that. Emre's patch was correct AFAICT, but I (Álvaro) felt the need to improve a few comments a bit more. Any resulting errors are my own. Per complaint from Coverity, Ning Yu, and Tom Lane. Author: Emre Hasegeli, Álvaro Herrera Reviewed-by: Tomas Vondra, Álvaro Herrera Discussion: https://postgr.es/m/26769.1533090136@sss.pgh.pa.us
This commit is contained in:
@ -3,6 +3,16 @@
|
|||||||
* geo_ops.c
|
* geo_ops.c
|
||||||
* 2D geometric operations
|
* 2D geometric operations
|
||||||
*
|
*
|
||||||
|
* This module implements the geometric functions and operators. The
|
||||||
|
* geometric types are (from simple to more complicated):
|
||||||
|
*
|
||||||
|
* - point
|
||||||
|
* - line
|
||||||
|
* - line segment
|
||||||
|
* - box
|
||||||
|
* - circle
|
||||||
|
* - polygon
|
||||||
|
*
|
||||||
* Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
@ -25,6 +35,34 @@
|
|||||||
#include "utils/fmgrprotos.h"
|
#include "utils/fmgrprotos.h"
|
||||||
#include "utils/geo_decls.h"
|
#include "utils/geo_decls.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* * Type constructors have this form:
|
||||||
|
* void type_construct(Type *result, ...);
|
||||||
|
*
|
||||||
|
* * Operators commonly have signatures such as
|
||||||
|
* void type1_operator_type2(Type *result, Type1 *obj1, Type2 *obj2);
|
||||||
|
*
|
||||||
|
* Common operators are:
|
||||||
|
* * Intersection point:
|
||||||
|
* bool type1_interpt_type2(Point *result, Type1 *obj1, Type2 *obj2);
|
||||||
|
* Return whether the two objects intersect. If *result is not NULL,
|
||||||
|
* it is set to the intersection point.
|
||||||
|
*
|
||||||
|
* * Containment:
|
||||||
|
* bool type1_contain_type2(Type1 *obj1, Type2 *obj2);
|
||||||
|
* Return whether obj1 contains obj2.
|
||||||
|
* bool type1_contain_type2(Type1 *contains_obj, Type1 *contained_obj);
|
||||||
|
* Return whether obj1 contains obj2 (used when types are the same)
|
||||||
|
*
|
||||||
|
* * Distance of closest point in or on obj1 to obj2:
|
||||||
|
* float8 type1_closept_type2(Point *result, Type1 *obj1, Type2 *obj2);
|
||||||
|
* Returns the shortest distance between two objects. If *result is not
|
||||||
|
* NULL, it is set to the closest point in or on obj1 to obj2.
|
||||||
|
*
|
||||||
|
* These functions may be used to implement multiple SQL-level operators. For
|
||||||
|
* example, determining whether two lines are parallel is done by checking
|
||||||
|
* whether they don't intersect.
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Internal routines
|
* Internal routines
|
||||||
@ -64,7 +102,7 @@ static int lseg_crossing(float8 x, float8 y, float8 px, float8 py);
|
|||||||
static bool lseg_contain_point(LSEG *lseg, Point *point);
|
static bool lseg_contain_point(LSEG *lseg, Point *point);
|
||||||
static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt);
|
static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt);
|
||||||
static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line);
|
static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line);
|
||||||
static float8 lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2);
|
static float8 lseg_closept_lseg(Point *result, LSEG *on_lseg, LSEG *to_lseg);
|
||||||
|
|
||||||
/* Routines for boxes */
|
/* Routines for boxes */
|
||||||
static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
|
static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
|
||||||
@ -74,7 +112,7 @@ static float8 box_ar(BOX *box);
|
|||||||
static float8 box_ht(BOX *box);
|
static float8 box_ht(BOX *box);
|
||||||
static float8 box_wd(BOX *box);
|
static float8 box_wd(BOX *box);
|
||||||
static bool box_contain_point(BOX *box, Point *point);
|
static bool box_contain_point(BOX *box, Point *point);
|
||||||
static bool box_contain_box(BOX *box1, BOX *box2);
|
static bool box_contain_box(BOX *contains_box, BOX *contained_box);
|
||||||
static bool box_contain_lseg(BOX *box, LSEG *lseg);
|
static bool box_contain_lseg(BOX *box, LSEG *lseg);
|
||||||
static bool box_interpt_lseg(Point *result, BOX *box, LSEG *lseg);
|
static bool box_interpt_lseg(Point *result, BOX *box, LSEG *lseg);
|
||||||
static float8 box_closept_point(Point *result, BOX *box, Point *point);
|
static float8 box_closept_point(Point *result, BOX *box, Point *point);
|
||||||
@ -87,7 +125,7 @@ static float8 circle_ar(CIRCLE *circle);
|
|||||||
static void make_bound_box(POLYGON *poly);
|
static void make_bound_box(POLYGON *poly);
|
||||||
static void poly_to_circle(CIRCLE *result, POLYGON *poly);
|
static void poly_to_circle(CIRCLE *result, POLYGON *poly);
|
||||||
static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
|
static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
|
||||||
static bool poly_contain_poly(POLYGON *polya, POLYGON *polyb);
|
static bool poly_contain_poly(POLYGON *contains_poly, POLYGON *contained_poly);
|
||||||
static bool plist_same(int npts, Point *p1, Point *p2);
|
static bool plist_same(int npts, Point *p1, Point *p2);
|
||||||
static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
|
static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
|
||||||
|
|
||||||
@ -648,15 +686,15 @@ box_contain(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check whether the box is in the box or on its border
|
* Check whether the second box is in the first box or on its border
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
box_contain_box(BOX *box1, BOX *box2)
|
box_contain_box(BOX *contains_box, BOX *contained_box)
|
||||||
{
|
{
|
||||||
return FPge(box1->high.x, box2->high.x) &&
|
return FPge(contains_box->high.x, contained_box->high.x) &&
|
||||||
FPle(box1->low.x, box2->low.x) &&
|
FPle(contains_box->low.x, contained_box->low.x) &&
|
||||||
FPge(box1->high.y, box2->high.y) &&
|
FPge(contains_box->high.y, contained_box->high.y) &&
|
||||||
FPle(box1->low.y, box2->low.y);
|
FPle(contains_box->low.y, contained_box->low.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1223,9 +1261,8 @@ line_interpt(PG_FUNCTION_ARGS)
|
|||||||
/*
|
/*
|
||||||
* Internal version of line_interpt
|
* Internal version of line_interpt
|
||||||
*
|
*
|
||||||
* This returns true if two lines intersect (they do, if they are not
|
* Return whether two lines intersect. If *result is not NULL, it is set to
|
||||||
* parallel), false if they do not. This also sets the intersection point
|
* the intersection point.
|
||||||
* to *result, if it is not NULL.
|
|
||||||
*
|
*
|
||||||
* NOTE: If the lines are identical then we will find they are parallel
|
* NOTE: If the lines are identical then we will find they are parallel
|
||||||
* and report "no intersection". This is a little weird, but since
|
* and report "no intersection". This is a little weird, but since
|
||||||
@ -2244,10 +2281,9 @@ lseg_center(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find the intersection point of two segments (if any).
|
* Return whether the two segments intersect. If *result is not NULL,
|
||||||
|
* it is set to the intersection point.
|
||||||
*
|
*
|
||||||
* This returns true if two line segments intersect, false if they do not.
|
|
||||||
* This also sets the intersection point to *result, if it is not NULL.
|
|
||||||
* This function is almost perfectly symmetric, even though it doesn't look
|
* This function is almost perfectly symmetric, even though it doesn't look
|
||||||
* like it. See lseg_interpt_line() for the other half of it.
|
* like it. See lseg_interpt_line() for the other half of it.
|
||||||
*/
|
*/
|
||||||
@ -2507,11 +2543,8 @@ dist_ppoly_internal(Point *pt, POLYGON *poly)
|
|||||||
*-------------------------------------------------------------------*/
|
*-------------------------------------------------------------------*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if the line segment intersects with the line
|
* Return whether the line segment intersect with the line. If *result is not
|
||||||
*
|
* NULL, it is set to the intersection point.
|
||||||
* This returns true if line segment intersects with line, false if they
|
|
||||||
* do not. This also sets the intersection point to *result, if it is not
|
|
||||||
* NULL.
|
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
|
lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
|
||||||
@ -2534,21 +2567,20 @@ lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
|
|||||||
*/
|
*/
|
||||||
if (!lseg_contain_point(lseg, &interpt))
|
if (!lseg_contain_point(lseg, &interpt))
|
||||||
return false;
|
return false;
|
||||||
|
if (result != NULL)
|
||||||
if (result == NULL)
|
{
|
||||||
return true;
|
/*
|
||||||
|
* If there is an intersection, then check explicitly for matching
|
||||||
/*
|
* endpoints since there may be rounding effects with annoying LSB
|
||||||
* If there is an intersection, then check explicitly for matching
|
* residue.
|
||||||
* endpoints since there may be rounding effects with annoying LSB
|
*/
|
||||||
* residue.
|
if (point_eq_point(&lseg->p[0], &interpt))
|
||||||
*/
|
*result = lseg->p[0];
|
||||||
if (point_eq_point(&lseg->p[0], &interpt))
|
else if (point_eq_point(&lseg->p[1], &interpt))
|
||||||
*result = lseg->p[0];
|
*result = lseg->p[1];
|
||||||
else if (point_eq_point(&lseg->p[1], &interpt))
|
else
|
||||||
*result = lseg->p[1];
|
*result = interpt;
|
||||||
else
|
}
|
||||||
*result = interpt;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2559,11 +2591,9 @@ lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
|
|||||||
*-------------------------------------------------------------------*/
|
*-------------------------------------------------------------------*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The intersection point of a perpendicular of the line
|
* If *result is not NULL, it is set to the intersection point of a
|
||||||
* through the point.
|
* perpendicular of the line through the point. Returns the distance
|
||||||
*
|
* of those two points.
|
||||||
* This sets the closest point to the *result if it is not NULL and returns
|
|
||||||
* the distance to the closest point.
|
|
||||||
*/
|
*/
|
||||||
static float8
|
static float8
|
||||||
line_closept_point(Point *result, LINE *line, Point *point)
|
line_closept_point(Point *result, LINE *line, Point *point)
|
||||||
@ -2610,8 +2640,8 @@ close_pl(PG_FUNCTION_ARGS)
|
|||||||
/*
|
/*
|
||||||
* Closest point on line segment to specified point.
|
* Closest point on line segment to specified point.
|
||||||
*
|
*
|
||||||
* This sets the closest point to the *result if it is not NULL and returns
|
* If *result is not NULL, set it to the closest point on the line segment
|
||||||
* the distance to the closest point.
|
* to the point. Returns the distance of the two points.
|
||||||
*/
|
*/
|
||||||
static float8
|
static float8
|
||||||
lseg_closept_point(Point *result, LSEG *lseg, Point *pt)
|
lseg_closept_point(Point *result, LSEG *lseg, Point *pt)
|
||||||
@ -2650,27 +2680,24 @@ close_ps(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Closest point on line segment to line segment
|
* Closest point on line segment to line segment
|
||||||
*
|
|
||||||
* This sets the closest point to the *result if it is not NULL and returns
|
|
||||||
* the distance to the closest point.
|
|
||||||
*/
|
*/
|
||||||
static float8
|
static float8
|
||||||
lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
|
lseg_closept_lseg(Point *result, LSEG *on_lseg, LSEG *to_lseg)
|
||||||
{
|
{
|
||||||
Point point;
|
Point point;
|
||||||
float8 dist,
|
float8 dist,
|
||||||
d;
|
d;
|
||||||
|
|
||||||
/* First, we handle the case when the line segments are intersecting. */
|
/* First, we handle the case when the line segments are intersecting. */
|
||||||
if (lseg_interpt_lseg(result, l1, l2))
|
if (lseg_interpt_lseg(result, on_lseg, to_lseg))
|
||||||
return 0.0;
|
return 0.0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Then, we find the closest points from the endpoints of the second
|
* Then, we find the closest points from the endpoints of the second
|
||||||
* line segment, and keep the closest one.
|
* line segment, and keep the closest one.
|
||||||
*/
|
*/
|
||||||
dist = lseg_closept_point(result, l1, &l2->p[0]);
|
dist = lseg_closept_point(result, on_lseg, &to_lseg->p[0]);
|
||||||
d = lseg_closept_point(&point, l1, &l2->p[1]);
|
d = lseg_closept_point(&point, on_lseg, &to_lseg->p[1]);
|
||||||
if (float8_lt(d, dist))
|
if (float8_lt(d, dist))
|
||||||
{
|
{
|
||||||
dist = d;
|
dist = d;
|
||||||
@ -2679,19 +2706,19 @@ lseg_closept_lseg(Point *result, LSEG *l1, LSEG *l2)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* The closest point can still be one of the endpoints, so we test them. */
|
/* The closest point can still be one of the endpoints, so we test them. */
|
||||||
d = lseg_closept_point(NULL, l2, &l1->p[0]);
|
d = lseg_closept_point(NULL, to_lseg, &on_lseg->p[0]);
|
||||||
if (float8_lt(d, dist))
|
if (float8_lt(d, dist))
|
||||||
{
|
{
|
||||||
dist = d;
|
dist = d;
|
||||||
if (result != NULL)
|
if (result != NULL)
|
||||||
*result = l1->p[0];
|
*result = on_lseg->p[0];
|
||||||
}
|
}
|
||||||
d = lseg_closept_point(NULL, l2, &l1->p[1]);
|
d = lseg_closept_point(NULL, to_lseg, &on_lseg->p[1]);
|
||||||
if (float8_lt(d, dist))
|
if (float8_lt(d, dist))
|
||||||
{
|
{
|
||||||
dist = d;
|
dist = d;
|
||||||
if (result != NULL)
|
if (result != NULL)
|
||||||
*result = l1->p[1];
|
*result = on_lseg->p[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
return dist;
|
return dist;
|
||||||
@ -2719,8 +2746,8 @@ close_lseg(PG_FUNCTION_ARGS)
|
|||||||
/*
|
/*
|
||||||
* Closest point on or in box to specified point.
|
* Closest point on or in box to specified point.
|
||||||
*
|
*
|
||||||
* This sets the closest point to the *result if it is not NULL and returns
|
* If *result is not NULL, set it to the closest point on the box to the
|
||||||
* the distance to the closest point.
|
* given point, and return the distance of the two points.
|
||||||
*/
|
*/
|
||||||
static float8
|
static float8
|
||||||
box_closept_point(Point *result, BOX *box, Point *pt)
|
box_closept_point(Point *result, BOX *box, Point *pt)
|
||||||
@ -2837,11 +2864,11 @@ close_sl(PG_FUNCTION_ARGS)
|
|||||||
/*
|
/*
|
||||||
* Closest point on line segment to line.
|
* Closest point on line segment to line.
|
||||||
*
|
*
|
||||||
* This sets the closest point to the *result if it is not NULL and returns
|
* Return the distance between the line and the closest point of the line
|
||||||
* the distance to the closest point.
|
* segment to the line. If *result is not NULL, set it to that point.
|
||||||
*
|
*
|
||||||
* NOTE: When the lines are parallel, endpoints of one of the line segment
|
* NOTE: When the lines are parallel, endpoints of one of the line segment
|
||||||
* are FPeq(), in presence of NaN or Infinitive coordinates, or perhaps =
|
* are FPeq(), in presence of NaN or Infinite coordinates, or perhaps =
|
||||||
* even because of simple roundoff issues, there may not be a single closest
|
* even because of simple roundoff issues, there may not be a single closest
|
||||||
* point. We are likely to set the result to the second endpoint in these
|
* point. We are likely to set the result to the second endpoint in these
|
||||||
* cases.
|
* cases.
|
||||||
@ -2896,8 +2923,8 @@ close_ls(PG_FUNCTION_ARGS)
|
|||||||
/*
|
/*
|
||||||
* Closest point on or in box to line segment.
|
* Closest point on or in box to line segment.
|
||||||
*
|
*
|
||||||
* This sets the closest point to the *result if it is not NULL and returns
|
* Returns the distance between the closest point on or in the box to
|
||||||
* the distance to the closest point.
|
* the line segment. If *result is not NULL, it is set to that point.
|
||||||
*/
|
*/
|
||||||
static float8
|
static float8
|
||||||
box_closept_lseg(Point *result, BOX *box, LSEG *lseg)
|
box_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)
|
|||||||
/*
|
/*
|
||||||
* Returns true if segment (a,b) is in polygon, option
|
* Returns true if segment (a,b) is in polygon, option
|
||||||
* start is used for optimization - function checks
|
* start is used for optimization - function checks
|
||||||
* polygon's edges started from start
|
* polygon's edges starting from start
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
|
lseg_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)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------------
|
/*
|
||||||
* Determine if polygon A contains polygon B.
|
* Check whether the first polygon contains the second
|
||||||
*-----------------------------------------------------------------*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
poly_contain_poly(POLYGON *polya, POLYGON *polyb)
|
poly_contain_poly(POLYGON *contains_poly, POLYGON *contained_poly)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
LSEG s;
|
LSEG s;
|
||||||
|
|
||||||
Assert(polya->npts > 0 && polyb->npts > 0);
|
Assert(contains_poly->npts > 0 && contained_poly->npts > 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Quick check to see if bounding box is contained.
|
* Quick check to see if contained's bounding box is contained in
|
||||||
|
* contains' bb.
|
||||||
*/
|
*/
|
||||||
if (!box_contain_box(&polya->boundbox, &polyb->boundbox))
|
if (!box_contain_box(&contains_poly->boundbox, &contained_poly->boundbox))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
s.p[0] = polyb->p[polyb->npts - 1];
|
s.p[0] = contained_poly->p[contained_poly->npts - 1];
|
||||||
|
|
||||||
for (i = 0; i < polyb->npts; i++)
|
for (i = 0; i < contained_poly->npts; i++)
|
||||||
{
|
{
|
||||||
s.p[1] = polyb->p[i];
|
s.p[1] = contained_poly->p[i];
|
||||||
if (!lseg_inside_poly(s.p, s.p + 1, polya, 0))
|
if (!lseg_inside_poly(s.p, s.p + 1, contains_poly, 0))
|
||||||
return false;
|
return false;
|
||||||
s.p[0] = s.p[1];
|
s.p[0] = s.p[1];
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user