/** Return the leaf cell containing the given S2LatLng. */
 public static function fromLatLng(S2LatLng $ll)
 {
     return self::fromPoint($ll->toPoint());
 }
 /**
  * Return a rectangle that contains all points whose latitude distance from
  * this rectangle is at most margin.lat(), and whose longitude distance from
  * this rectangle is at most margin.lng(). In particular, latitudes are
  * clamped while longitudes are wrapped. Note that any expansion of an empty
  * interval remains empty, and both components of the given margin must be
  * non-negative.
  *
  * NOTE: If you are trying to grow a rectangle by a certain *distance* on the
  * sphere (e.g. 5km), use the ConvolveWithCap() method instead.
  * @return S2LatLngRect
  */
 public function expanded(S2LatLng $margin)
 {
     // assert (margin.lat().radians() >= 0 && margin.lng().radians() >= 0);
     if ($this->isEmpty()) {
         return $this;
     }
     return new S2LatLngRect($this->lat->expanded($margin->lat()->radians())->intersection($this->fullLat()), $this->lng->expanded($margin->lng()->radians()));
 }
 /**
  * Return the distance (measured along the surface of the sphere) to the given
  * point.
  */
 public function getDistance(S2LatLng $o)
 {
     // This implements the Haversine formula, which is numerically stable for
     // small distances but only gets about 8 digits of precision for very large
     // distances (e.g. antipodal points). Note that 8 digits is still accurate
     // to within about 10cm for a sphere the size of the Earth.
     //
     // This could be fixed with another sin() and cos() below, but at that point
     // you might as well just convert both arguments to S2Points and compute the
     // distance that way (which gives about 15 digits of accuracy for all
     // distances).
     $lat1 = self::lat()->radians();
     $lat2 = $o->lat()->radians();
     $lng1 = self::lng()->radians();
     $lng2 = $o->lng()->radians();
     $dlat = sin(0.5 * ($lat2 - $lat1));
     $dlng = sin(0.5 * ($lng2 - $lng1));
     $x = $dlat * $dlat + $dlng * $dlng * cos($lat1) * cos($lat2);
     return S1Angle::sradians(2 * atan2(sqrt($x), sqrt(max(0.0, 1.0 - $x))));
     // Return the distance (measured along the surface of the sphere) to the
     // given S2LatLng. This is mathematically equivalent to:
     //
     // S1Angle::FromRadians(ToPoint().Angle(o.ToPoint())
     //
     // but this implementation is slightly more efficient.
 }
 public function toDegreesString()
 {
     $s2LatLng = new S2LatLng($this);
     return "(" . $s2LatLng->latDegrees() . ", " . $s2LatLng->lngDegrees() . ")";
 }
 public function getRectBound()
 {
     if ($this->isEmpty()) {
         return S2LatLngRect::emptya();
     }
     // Convert the axis to a (lat,lng) pair, and compute the cap angle.
     $axisLatLng = new S2LatLng($this->axis);
     $capAngle = $this->angle()->radians();
     $allLongitudes = false;
     $lat = array();
     $lng = array();
     $lng[0] = -S2::M_PI;
     $lng[1] = S2::M_PI;
     // Check whether cap includes the south pole.
     $lat[0] = $axisLatLng->lat()->radians() - $capAngle;
     if ($lat[0] <= -S2::M_PI_2) {
         $lat[0] = -S2::M_PI_2;
         $allLongitudes = true;
     }
     // Check whether cap includes the north pole.
     $lat[1] = $axisLatLng->lat()->radians() + $capAngle;
     if ($lat[1] >= S2::M_PI_2) {
         $lat[1] = S2::M_PI_2;
         $allLongitudes = true;
     }
     if (!$allLongitudes) {
         // Compute the range of longitudes covered by the cap. We use the law
         // of sines for spherical triangles. Consider the triangle ABC where
         // A is the north pole, B is the center of the cap, and C is the point
         // of tangency between the cap boundary and a line of longitude. Then
         // C is a right angle, and letting a,b,c denote the sides opposite A,B,C,
         // we have sin(a)/sin(A) = sin(c)/sin(C), or sin(A) = sin(a)/sin(c).
         // Here "a" is the cap angle, and "c" is the colatitude (90 degrees
         // minus the latitude). This formula also works for negative latitudes.
         //
         // The formula for sin(a) follows from the relationship h = 1 - cos(a).
         $sinA = sqrt($this->height * (2 - $this->height));
         $sinC = cos($axisLatLng->lat()->radians());
         if ($sinA <= $sinC) {
             $angleA = asin($sinA / $sinC);
             $lng[0] = S2::IEEEremainder($axisLatLng->lng()->radians() - $angleA, 2 * S2::M_PI);
             $lng[1] = S2::IEEEremainder($axisLatLng->lng()->radians() + $angleA, 2 * S2::M_PI);
         }
     }
     return new S2LatLngRect(new R1Interval($lat[0], $lat[1]), new S1Interval($lng[0], $lng[1]));
 }