pgLatLon

diff latlon-v0005.c @ 20:8a8d6dc44337

Changed/fixed behavior of "contains" operator regarding perimeters; Added "contains" operator for ebox type; Minor changes in README
author jbe
date Mon Sep 12 18:00:52 2016 +0200 (2016-09-12)
parents bd166e5e02cb
children
line diff
     1.1 --- a/latlon-v0005.c	Fri Sep 09 23:44:28 2016 +0200
     1.2 +++ b/latlon-v0005.c	Mon Sep 12 18:00:52 2016 +0200
     1.3 @@ -489,7 +489,13 @@
     1.4  }
     1.5  
     1.6  /* check if point is inside cluster */
     1.7 -static bool pgl_point_in_cluster(pgl_point *point, pgl_cluster *cluster) {
     1.8 +/* (if point is on perimeter, then true is returned if and only if
     1.9 +   strict == false) */
    1.10 +static bool pgl_point_in_cluster(
    1.11 +  pgl_point *point,
    1.12 +  pgl_cluster *cluster,
    1.13 +  bool strict
    1.14 +) {
    1.15    int i, j, k;  /* i: entry, j: point in entry, k: next point in entry */
    1.16    int entrytype;         /* type of entry */
    1.17    int npoints;           /* number of points in entry */
    1.18 @@ -504,8 +510,11 @@
    1.19    int counter = 0;       /* counter for intersections east of point */
    1.20    /* iterate over all entries */
    1.21    for (i=0; i<cluster->nentries; i++) {
    1.22 -    /* get properties of entry */
    1.23 +    /* get type of entry */
    1.24      entrytype = cluster->entries[i].entrytype;
    1.25 +    /* skip all entries but polygons if perimeters are excluded */
    1.26 +    if (strict && entrytype != PGL_ENTRY_POLYGON) continue;
    1.27 +    /* get points of entry */
    1.28      npoints = cluster->entries[i].npoints;
    1.29      points = PGL_ENTRY_POINTS(cluster, i);
    1.30      /* determine east/west orientation of first point of entry and calculate
    1.31 @@ -521,8 +530,8 @@
    1.32      else if (lon_dir > 0 && lon0 < lon_break) lon0 = pgl_round(lon0 + 360);
    1.33      /* iterate over all edges and vertices */
    1.34      for (j=0; j<npoints; j++) {
    1.35 -      /* return true if point is on vertex of polygon */
    1.36 -      if (pgl_point_cmp(point, &(points[j])) == 0) return true;
    1.37 +      /* return if point is on vertex of polygon */
    1.38 +      if (pgl_point_cmp(point, &(points[j])) == 0) return !strict;
    1.39        /* calculate index of next vertex */
    1.40        k = (j+1) % npoints;
    1.41        /* skip last edge unless entry is (closed) outline or polygon */
    1.42 @@ -549,17 +558,17 @@
    1.43        /* consider longitude wrap-around for next vertex */
    1.44        if      (lon_dir < 0 && lon2 > lon_break) lon2 = pgl_round(lon2 - 360);
    1.45        else if (lon_dir > 0 && lon2 < lon_break) lon2 = pgl_round(lon2 + 360);
    1.46 -      /* return true if point is on horizontal (west to east) edge of polygon */
    1.47 +      /* return if point is on horizontal (west to east) edge of polygon */
    1.48        if (
    1.49          lat0 == lat1 && lat0 == lat2 &&
    1.50          ( (lon0 >= lon1 && lon0 <= lon2) || (lon0 >= lon2 && lon0 <= lon1) )
    1.51 -      ) return true;
    1.52 +      ) return !strict;
    1.53        /* check if edge crosses east/west line of point */
    1.54        if ((lat1 < lat0 && lat2 >= lat0) || (lat2 < lat0 && lat1 >= lat0)) {
    1.55          /* calculate longitude of intersection */
    1.56          lon = (lon1 * (lat2-lat0) + lon2 * (lat0-lat1)) / (lat2-lat1);
    1.57 -        /* return true if intersection goes (approximately) through point */
    1.58 -        if (pgl_round(lon) == lon0) return true;
    1.59 +        /* return if intersection goes (approximately) through point */
    1.60 +        if (pgl_round(lon) == lon0) return !strict;
    1.61          /* count intersection if east of point and entry is polygon*/
    1.62          if (entrytype == PGL_ENTRY_POLYGON && lon > lon0) counter++;
    1.63        }
    1.64 @@ -569,8 +578,9 @@
    1.65    return counter & 1;
    1.66  }
    1.67  
    1.68 -/* check if all points of the second cluster are inside the first cluster */
    1.69 -static inline bool pgl_all_cluster_points_in_cluster(
    1.70 +/* check if all points of the second cluster are strictly inside the first
    1.71 +   cluster */
    1.72 +static inline bool pgl_all_cluster_points_strictly_in_cluster(
    1.73    pgl_cluster *outer, pgl_cluster *inner
    1.74  ) {
    1.75    int i, j;           /* i: entry, j: point in entry */
    1.76 @@ -584,7 +594,7 @@
    1.77      /* iterate over all points in entry of "inner" cluster */
    1.78      for (j=0; j<npoints; j++) {
    1.79        /* return false if one point of inner cluster is not in outer cluster */
    1.80 -      if (!pgl_point_in_cluster(points+j, outer)) return false;
    1.81 +      if (!pgl_point_in_cluster(points+j, outer, true)) return false;
    1.82      }
    1.83    }
    1.84    /* otherwise return true */
    1.85 @@ -606,36 +616,33 @@
    1.86      /* iterate over all points in entry of "inner" cluster */
    1.87      for (j=0; j<npoints; j++) {
    1.88        /* return true if one point of inner cluster is in outer cluster */
    1.89 -      if (pgl_point_in_cluster(points+j, outer)) return true;
    1.90 +      if (pgl_point_in_cluster(points+j, outer, false)) return true;
    1.91      }
    1.92    }
    1.93    /* otherwise return false */
    1.94    return false;
    1.95  }
    1.96  
    1.97 -/* check if line segment crosses line */
    1.98 -/* returns -1 if yes, 1 if no, and 0 in corner cases */
    1.99 -/* NOTE: each line (segment) must have a length greater than zero */
   1.100 -static inline double pgl_lseg_crosses_line(
   1.101 +/* check if line segment strictly crosses line (not just touching) */
   1.102 +static inline bool pgl_lseg_crosses_line(
   1.103    double seg_x1,  double seg_y1,  double seg_x2,  double seg_y2,
   1.104 -  double line_x1, double line_y1, double line_x2, double line_y2,
   1.105 -  bool strict
   1.106 +  double line_x1, double line_y1, double line_x2, double line_y2
   1.107  ) {
   1.108 -  double value = (
   1.109 -    (seg_x1-line_x1) * (line_y2-line_y1) -
   1.110 -    (seg_y1-line_y1) * (line_x2-line_x1)
   1.111 -  ) * (
   1.112 -    (seg_x2-line_x1) * (line_y2-line_y1) -
   1.113 -    (seg_y2-line_y1) * (line_x2-line_x1)
   1.114 -  );
   1.115 -  if (strict) return value < 0;
   1.116 -  else return value <= 0;
   1.117 +  return (
   1.118 +    (
   1.119 +      (seg_x1-line_x1) * (line_y2-line_y1) -
   1.120 +      (seg_y1-line_y1) * (line_x2-line_x1)
   1.121 +    ) * (
   1.122 +      (seg_x2-line_x1) * (line_y2-line_y1) -
   1.123 +      (seg_y2-line_y1) * (line_x2-line_x1)
   1.124 +    )
   1.125 +  ) < 0;
   1.126  }
   1.127  
   1.128 -/* check if paths and outlines of two clusters overlap */
   1.129 -/* (set strict to true to disregard corner cases) */
   1.130 +/* check if paths and outlines of two clusters strictly overlap (not just
   1.131 +   touching) */
   1.132  static bool pgl_outlines_overlap(
   1.133 -  pgl_cluster *cluster1, pgl_cluster *cluster2, bool strict
   1.134 +  pgl_cluster *cluster1, pgl_cluster *cluster2
   1.135  ) {
   1.136    int i1, j1, k1;  /* i: entry, j: point in entry, k: next point in entry */
   1.137    int i2, j2, k2;
   1.138 @@ -758,12 +765,10 @@
   1.139            if (
   1.140              pgl_lseg_crosses_line(
   1.141                lat11, lon11, lat12, lon12,
   1.142 -              lat21, lon21, lat22, lon22,
   1.143 -              strict
   1.144 +              lat21, lon21, lat22, lon22
   1.145              ) && pgl_lseg_crosses_line(
   1.146                lat21, lon21, lat22, lon22,
   1.147 -              lat11, lon11, lat12, lon12,
   1.148 -              strict
   1.149 +              lat11, lon11, lat12, lon12
   1.150              )
   1.151            ) {
   1.152              return true;
   1.153 @@ -778,8 +783,9 @@
   1.154  
   1.155  /* check if second cluster is completely contained in first cluster */
   1.156  static bool pgl_cluster_in_cluster(pgl_cluster *outer, pgl_cluster *inner) {
   1.157 -  if (!pgl_all_cluster_points_in_cluster(outer, inner)) return false;
   1.158 -  if (pgl_outlines_overlap(outer, inner, true)) return false;
   1.159 +  if (!pgl_all_cluster_points_strictly_in_cluster(outer, inner)) return false;
   1.160 +  if (pgl_any_cluster_points_in_cluster(inner, outer)) return false;
   1.161 +  if (pgl_outlines_overlap(outer, inner)) return false;
   1.162    return true;
   1.163  }
   1.164  
   1.165 @@ -789,7 +795,7 @@
   1.166  ) {
   1.167    if (pgl_any_cluster_points_in_cluster(cluster1, cluster2)) return true;
   1.168    if (pgl_any_cluster_points_in_cluster(cluster2, cluster1)) return true;
   1.169 -  if (pgl_outlines_overlap(cluster1, cluster2, false)) return true;
   1.170 +  if (pgl_outlines_overlap(cluster1, cluster2)) return true;
   1.171    return false;
   1.172  }
   1.173  
   1.174 @@ -812,7 +818,7 @@
   1.175    double dist;           /* distance calculated in one step */
   1.176    double min_dist = INFINITY;   /* minimum distance */
   1.177    /* distance is zero if point is contained in cluster */
   1.178 -  if (pgl_point_in_cluster(point, cluster)) return 0;
   1.179 +  if (pgl_point_in_cluster(point, cluster, false)) return 0;
   1.180    /* iterate over all entries */
   1.181    for (i=0; i<cluster->nentries; i++) {
   1.182      /* get properties of entry */
   1.183 @@ -2343,7 +2349,7 @@
   1.184        cluster->bounding.center.lat, cluster->bounding.center.lon
   1.185      ) > cluster->bounding.radius
   1.186    ) retval = false;
   1.187 -  else retval = pgl_point_in_cluster(point, cluster);
   1.188 +  else retval = pgl_point_in_cluster(point, cluster, false);
   1.189    PG_FREE_IF_COPY(cluster, 1);
   1.190    PG_RETURN_BOOL(retval);
   1.191  }

Impressum / About Us