/**
  * @param double|S2Point $radians_or_x
  * @param S2Point $y
  * Return the angle between two points, which is also equal to the distance
  * between these points on the unit sphere. The points do not need to be
  * normalized.
  */
 public function __construct($radians_or_x = null, $y = null)
 {
     if ($radians_or_x instanceof S2Point && $y instanceof S2Point) {
         $this->radians = $radians_or_x->angle($y);
     } else {
         $this->radians = $radians_or_x === null ? 0 : $radians_or_x;
     }
 }
示例#2
0
 public static function toPoint()
 {
     return S2Point::normalize(self::toPointRaw());
 }
 public static function xyzToFace(S2Point $p)
 {
     $face = $p->largestAbsComponent();
     if ($p->get($face) < 0) {
         $face += 3;
     }
     return $face;
 }
示例#4
0
 public function toString()
 {
     return sprintf("Edge: (%s -> %s)\n   or [%s -> %s]", $this->start->toDegreesString(), $this->end->toDegreesString(), $this->start, $this->end);
 }
 public static function normalize(S2Point $p)
 {
     $norm = $p->norm();
     if ($norm != 0) {
         $norm = 1.0 / $norm;
     }
     return S2Point::mul($p, $norm);
 }
 /**
  * Return the average area for cells at the given level.
  *#/
  * public static double averageArea(int level) {
  * return S2Projections.AVG_AREA.getValue(level);
  * }
  *
  * /**
  * Return the average area of cells at this level. This is accurate to within
  * a factor of 1.7 (for S2_QUADRATIC_PROJECTION) and is extremely cheap to
  * compute.
  *#/
  * public double averageArea() {
  * return averageArea(level);
  * }
  *
  * /**
  * Return the approximate area of this cell. This method is accurate to within
  * 3% percent for all cell sizes and accurate to within 0.1% for cells at
  * level 5 or higher (i.e. 300km square or smaller). It is moderately cheap to
  * compute.
  *#/
  * public double approxArea() {
  *
  * // All cells at the first two levels have the same area.
  * if (level < 2) {
  * return averageArea(level);
  * }
  *
  * // First, compute the approximate area of the cell when projected
  * // perpendicular to its normal. The cross product of its diagonals gives
  * // the normal, and the length of the normal is twice the projected area.
  * double flatArea = 0.5 * S2Point.crossProd(
  * S2Point.sub(getVertex(2), getVertex(0)), S2Point.sub(getVertex(3), getVertex(1))).norm();
  *
  * // Now, compensate for the curvature of the cell surface by pretending
  * // that the cell is shaped like a spherical cap. The ratio of the
  * // area of a spherical cap to the area of its projected disc turns out
  * // to be 2 / (1 + sqrt(1 - r*r)) where "r" is the radius of the disc.
  * // For example, when r=0 the ratio is 1, and when r=1 the ratio is 2.
  * // Here we set Pi*r*r == flat_area to find the equivalent disc.
  * return flatArea * 2 / (1 + Math.sqrt(1 - Math.min(S2.M_1_PI * flatArea, 1.0)));
  * }
  *
  * /**
  * Return the area of this cell as accurately as possible. This method is more
  * expensive but it is accurate to 6 digits of precision even for leaf cells
  * (whose area is approximately 1e-18).
  *#/
  * public double exactArea() {
  * S2Point v0 = getVertex(0);
  * S2Point v1 = getVertex(1);
  * S2Point v2 = getVertex(2);
  * S2Point v3 = getVertex(3);
  * return S2.area(v0, v1, v2) + S2.area(v0, v2, v3);
  * }
  *
  * // //////////////////////////////////////////////////////////////////////
  * // S2Region interface (see {@code S2Region} for details):
  *
  * @Override
  * public S2Region clone() {
  * S2Cell clone = new S2Cell();
  * clone.face = this.face;
  * clone.level = this.level;
  * clone.orientation = this.orientation;
  * clone.uv = this.uv.clone();
  *
  * return clone;
  * }
  */
 public function getCapBound()
 {
     // Use the cell center in (u,v)-space as the cap axis. This vector is
     // very close to GetCenter() and faster to compute. Neither one of these
     // vectors yields the bounding cap with minimal surface area, but they
     // are both pretty close.
     //
     // It's possible to show that the two vertices that are furthest from
     // the (u,v)-origin never determine the maximum cap size (this is a
     // possible future optimization).
     $u = 0.5 * ($this->uv[0][0] + $this->uv[0][1]);
     $v = 0.5 * ($this->uv[1][0] + $this->uv[1][1]);
     $cap = S2Cap::fromAxisHeight(S2Point::normalize(S2Projections::faceUvToXyz($this->face, $u, $v)), 0);
     for ($k = 0; $k < 4; ++$k) {
         $cap = $cap->addPoint($this->getVertex($k));
     }
     return $cap;
 }
 public static function longitude(S2Point $p)
 {
     // Note that atan2(0, 0) is defined to be zero.
     return S1Angle::sradians(atan2($p->get(1), $p->get(0)));
 }
 /** Return true if the cap is full, i.e. it contains all points. *#/
  * public boolean isFull() {
  * return height >= 2;
  * }
  *
  * /**
  * Return the complement of the interior of the cap. A cap and its complement
  * have the same boundary but do not share any interior points. The complement
  * operator is not a bijection, since the complement of a singleton cap
  * (containing a single point) is the same as the complement of an empty cap.
  *#/
  * public S2Cap complement() {
  * // The complement of a full cap is an empty cap, not a singleton.
  * // Also make sure that the complement of an empty cap has height 2.
  * double cHeight = isFull() ? -1 : 2 - Math.max(height, 0.0);
  * return S2Cap.fromAxisHeight(S2Point.neg(axis), cHeight);
  * }
  *
  * /**
  * Return true if and only if this cap contains the given other cap (in a set
  * containment sense, e.g. every cap contains the empty cap).
  *#/
  * public boolean contains(S2Cap other) {
  * if (isFull() || other.isEmpty()) {
  * return true;
  * }
  * return angle().radians() >= axis.angle(other.axis)
  * + other.angle().radians();
  * }
  *
  * /**
  * Return true if and only if the interior of this cap intersects the given
  * other cap. (This relationship is not symmetric, since only the interior of
  * this cap is used.)
  *#/
  * public boolean interiorIntersects(S2Cap other) {
  * // Interior(X) intersects Y if and only if Complement(Interior(X))
  * // does not contain Y.
  * return !complement().contains(other);
  * }
  *
  * /**
  * Return true if and only if the given point is contained in the interior of
  * the region (i.e. the region excluding its boundary). 'p' should be a
  * unit-length vector.
  *#/
  * public boolean interiorContains(S2Point p) {
  * // assert (S2.isUnitLength(p));
  * return isFull() || S2Point.sub(axis, p).norm2() < 2 * height;
  * }
  *
  * /**
  * Increase the cap height if necessary to include the given point. If the cap
  * is empty the axis is set to the given point, but otherwise it is left
  * unchanged. 'p' should be a unit-length vector.
  */
 public function addPoint(S2Point $p)
 {
     // Compute the squared chord length, then convert it into a height.
     // assert (S2.isUnitLength(p));
     if ($this->isEmpty()) {
         return new S2Cap($p, 0);
     } else {
         // To make sure that the resulting cap actually includes this point,
         // we need to round up the distance calculation. That is, after
         // calling cap.AddPoint(p), cap.Contains(p) should be true.
         $dist2 = S2Point::sub($this->axis, $p)->norm2();
         $newHeight = max($this->height, self::ROUND_UP * 0.5 * $dist2);
         return new S2Cap($this->axis, $newHeight);
     }
 }