PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches

◆ 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: