PostGIS  3.7.0dev-r@@SVN_REVISION@@

◆ gbox_geocentric_get_gbox_cartesian()

int gbox_geocentric_get_gbox_cartesian ( const GBOX gbox_geocentric,
GBOX gbox_planar 
)

Definition at line 3596 of file lwgeodetic.c.

3597 {
3598  /* Normalized corners of the bounding volume */
3599  POINT3D corners[8];
3600  POINT3D cap_center = {0,0,0};
3601  double furthest_angle = 0.0;
3602  double cap_angle = 0.0;
3603  int all_longitudes = LW_FALSE;
3604  double lon0 = -M_PI, lon1 = M_PI;
3605  double lat0, lat1;
3606  GEOGRAPHIC_POINT cap_center_g;
3607 
3608  if (!gbox_geocentric || !gbox_planar)
3609  {
3610  lwerror("Null pointer passed to %s", __func__);
3611  return LW_FALSE;
3612  }
3613 
3614 #define CORNER_SET(ii, xx, yy, zz) { \
3615  corners[ii].x = gbox_geocentric->xx; \
3616  corners[ii].y = gbox_geocentric->yy; \
3617  corners[ii].z = gbox_geocentric->zz; \
3618  }
3619 
3620  /*
3621  * First find a "centered" vector to serve as the mid-point
3622  * of the input bounding volume.
3623  */
3624  CORNER_SET(0, xmin, ymin, zmin);
3625  CORNER_SET(1, xmax, ymin, zmin);
3626  CORNER_SET(2, xmin, ymax, zmin);
3627  CORNER_SET(3, xmax, ymax, zmin);
3628  CORNER_SET(4, xmin, ymin, zmax);
3629  CORNER_SET(5, xmax, ymin, zmax);
3630  CORNER_SET(6, xmin, ymax, zmax);
3631  CORNER_SET(7, xmax, ymax, zmax);
3632 
3633  /*
3634  * Normalize the volume corners
3635  * and normalize the final vector.
3636  */
3637  for (uint32_t i = 0; i < 8; i++)
3638  {
3639  normalize(&(corners[i]));
3640  cap_center.x += corners[i].x;
3641  cap_center.y += corners[i].y;
3642  cap_center.z += corners[i].z;
3643  }
3644  normalize(&cap_center);
3645 
3646  /*
3647  * Find the volume corner that is furthest from the center,
3648  * and calculate the angle between the center and the corner.
3649  * Now we have a "cap" (center and angle)
3650  */
3651  for (uint32_t i = 0; i < 8; i++)
3652  {
3653  double angle = vector_angle(&cap_center, &(corners[i]));
3654  if (angle > furthest_angle)
3655  furthest_angle = angle;
3656  }
3657  cap_angle = furthest_angle;
3658 
3659  /*
3660  * Calculate the planar box that contains the cap.
3661  * If the cap contains a pole, then we include all longitudes
3662  */
3663  cart2geog(&cap_center, &cap_center_g);
3664 
3665  /* Check whether cap includes the south pole */
3666  lat0 = cap_center_g.lat - cap_angle;
3667  if (lat0 <= -M_PI_2)
3668  {
3669  lat0 = -M_PI_2;
3670  all_longitudes = LW_TRUE;
3671  }
3672 
3673  /* Check whether cap includes the north pole */
3674  lat1 = cap_center_g.lat + cap_angle;
3675  if (lat1 >= M_PI_2)
3676  {
3677  lat1 = M_PI_2;
3678  all_longitudes = LW_TRUE;
3679  }
3680 
3681  if (!all_longitudes)
3682  {
3683  // Compute the range of longitudes covered by the cap. We use the law
3684  // of sines for spherical triangles. Consider the triangle ABC where
3685  // A is the north pole, B is the center of the cap, and C is the point
3686  // of tangency between the cap boundary and a line of longitude. Then
3687  // C is a right angle, and letting a,b,c denote the sides opposite A,B,C,
3688  // we have sin(a)/sin(A) = sin(c)/sin(C), or sin(A) = sin(a)/sin(c).
3689  // Here "a" is the cap angle, and "c" is the colatitude (90 degrees
3690  // minus the latitude). This formula also works for negative latitudes.
3691  //
3692  // The formula for sin(a) follows from the relationship h = 1 - cos(a).
3693 
3694  double sin_a = sin(cap_angle);
3695  double sin_c = cos(cap_center_g.lat);
3696  if (sin_a <= sin_c)
3697  {
3698  double angle_A = asin(sin_a / sin_c);
3699  lon0 = remainder(cap_center_g.lon - angle_A, 2 * M_PI);
3700  lon1 = remainder(cap_center_g.lon + angle_A, 2 * M_PI);
3701  }
3702  else
3703  {
3704  lon0 = -M_PI;
3705  lon1 = M_PI;
3706  }
3707  }
3708 
3709  gbox_planar->xmin = rad2deg(lon0);
3710  gbox_planar->ymin = rad2deg(lat0);
3711  gbox_planar->xmax = rad2deg(lon1);
3712  gbox_planar->ymax = rad2deg(lat1);
3713  FLAGS_SET_GEODETIC(gbox_planar->flags, 0);
3714  FLAGS_SET_Z(gbox_planar->flags, 0);
3715  FLAGS_SET_M(gbox_planar->flags, 0);
3716 
3717  return LW_TRUE;
3718 }
#define LW_FALSE
Definition: liblwgeom.h:94
#define FLAGS_SET_GEODETIC(flags, value)
Definition: liblwgeom.h:175
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:93
#define FLAGS_SET_M(flags, value)
Definition: liblwgeom.h:173
#define FLAGS_SET_Z(flags, value)
Definition: liblwgeom.h:172
void normalize(POINT3D *p)
Normalize to a unit vector.
Definition: lwgeodetic.c:615
void cart2geog(const POINT3D *p, GEOGRAPHIC_POINT *g)
Convert cartesian coordinates on unit sphere to spherical coordinates.
Definition: lwgeodetic.c:414
#define CORNER_SET(ii, xx, yy, zz)
double vector_angle(const POINT3D *v1, const POINT3D *v2)
Angle between two unit vectors.
Definition: lwgeodetic.c:505
#define rad2deg(r)
Definition: lwgeodetic.h:81
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
double ymax
Definition: liblwgeom.h:357
double xmax
Definition: liblwgeom.h:355
double ymin
Definition: liblwgeom.h:356
double xmin
Definition: liblwgeom.h:354
lwflags_t flags
Definition: liblwgeom.h:353
Point in spherical coordinates on the world.
Definition: lwgeodetic.h:54
double z
Definition: liblwgeom.h:402
double x
Definition: liblwgeom.h:402
double y
Definition: liblwgeom.h:402

References cart2geog(), CORNER_SET, GBOX::flags, FLAGS_SET_GEODETIC, FLAGS_SET_M, FLAGS_SET_Z, GEOGRAPHIC_POINT::lat, GEOGRAPHIC_POINT::lon, LW_FALSE, LW_TRUE, lwerror(), normalize(), rad2deg, vector_angle(), POINT3D::x, GBOX::xmax, GBOX::xmin, POINT3D::y, GBOX::ymax, GBOX::ymin, and POINT3D::z.

Referenced by BOX3D_BOXLL_TEST(), and gserialized_estimated_extent().

Here is the call graph for this function:
Here is the caller graph for this function: