/** * Create a Geodetic point from a Geocentric point. */ public static function fromGeocentric(Geocentric $point) { // Local definitions and variables // end-criterium of loop, accuracy of sin(Latitude) $genau = 1.0E-12; $genau2 = $genau * $genau; $maxiter = 30; $X = $point->x; $Y = $point->y; // Z value not always supplied // CHECKME: this does not make sense. Without Z we are talking about a flat // plain, and not a 3D point in space. $Z = $point->z ? $point->z : 0.0; /* $P; // distance between semi-minor axis and location $RR; // distance between center and location $CT; // sin of geocentric latitude $ST; // cos of geocentric latitude $RX; $RK; $RN; // Earth radius at location $CPHI0; // cos of start or old geodetic latitude in iterations $SPHI0; // sin of start or old geodetic latitude in iterations $CPHI; // cos of searched geodetic latitude $SPHI; // sin of searched geodetic latitude $SDPHI; // end-criterium: addition-theorem of sin(Latitude(iter)-Latitude(iter-1)) $at_pole; // indicates location is in polar region $iter; // of continous iteration, max. 30 is always enough (s.a.) $lon; $lat; $height; */ $a = $point->getEllipsoid()->a; $b = $point->getEllipsoid()->b; $at_pole = false; // The distance from the axis passing through the poles. $P = sqrt($X * $X + $Y * $Y); $RR = sqrt($X * $X + $Y * $Y + $Z * $Z); // Special cases for latitude and longitude. if ($P / $a < $genau) { // Special case: at the poles if P=0. (X=0, Y=0) $at_pole = true; $lon = 0.0; // If (X,Y,Z)=(0,0,0) then Height becomes semi-minor axis // of ellipsoid (=center of mass) and Latitude becomes PI/2 if ($RR / $a < $genau) { $lat = M_PI_2; $height = -$b; return; } } else { // Ellipsoidal (geodetic) longitude interval: // -PI < Longitude <= +PI $lon = atan2($Y, $X); } // The eccentricity squared. $es = $point->getEllipsoid()->es; /* -------------------------------------------------------------- * Following iterative algorithm was developped by * "Institut für Erdmessung", University of Hannover, July 1988. * Internet: www.ife.uni-hannover.de * Iterative computation of CPHI,SPHI and Height. * Iteration of CPHI and SPHI to 10**-12 radian res$p-> * 2*10**-7 arcsec. * -------------------------------------------------------------- */ $CT = $Z / $RR; $ST = $P / $RR; $RX = 1.0 / sqrt(1.0 - $es * (2.0 - $es) * $ST * $ST); $CPHI0 = $ST * (1.0 - $es) * $RX; $SPHI0 = $CT * $RX; $iter = 0; // Loop to find sin(Latitude) res $p-> Latitude // until |sin(Latitude(iter)-Latitude(iter-1))| < genau do { ++$iter; $RN = $a / sqrt(1.0 - $es * $SPHI0 * $SPHI0); // Ellipsoidal (geodetic) height $height = $P * $CPHI0 + $Z * $SPHI0 - $RN * (1.0 - $es * $SPHI0 * $SPHI0); $RK = $es * $RN / ($RN + $height); $RX = 1.0 / sqrt(1.0 - $RK * (2.0 - $RK) * $ST * $ST); $CPHI = $ST * (1.0 - $RK) * $RX; $SPHI = $CT * $RX; $SDPHI = $SPHI * $CPHI0 - $CPHI * $SPHI0; $CPHI0 = $CPHI; $SPHI0 = $SPHI; } while ($SDPHI * $SDPHI > $genau2 && $iter < $maxiter); // Ellipsoidal (geodetic) latitude $lat = atan($SPHI / abs($CPHI)); // Create a new Geodetic coordinate. // Keep the same datum as the current point. $geodetic_point = new static(rad2deg($lat), rad2deg($lon), $height, $point->getDatum()); return $geodetic_point; }
/** * Convert a geocentric point from the WGS84 datum. */ public function fromWgs84(Geocentric $point) { if ($this->type == static::TYPE_3TERM) { $x = $point->x - $this->params[0]; $y = $point->y - $this->params[1]; $z = $point->z - $this->params[2]; } elseif ($this->type == static::TYPE_7TERM) { $Dx_BF = $this->params[0]; $Dy_BF = $this->params[1]; $Dz_BF = $this->params[2]; // These need converting from seconds of arc to radians. $Rx_BF = $this->params[3] * static::SEC_TO_RAD; $Ry_BF = $this->params[4] * static::SEC_TO_RAD; $Rz_BF = $this->params[5] * static::SEC_TO_RAD; // Convert parts per million to a multiplier $M_BF = 1 + $this->params[6] * static::PPM_TO_MULT; $x_tmp = ($point->x - $Dx_BF) / $M_BF; $y_tmp = ($point->y - $Dy_BF) / $M_BF; $z_tmp = ($point->z - $Dz_BF) / $M_BF; $x = $x_tmp + $Rz_BF * $y_tmp - $Ry_BF * $z_tmp; $y = -$Rz_BF * $x_tmp + $y_tmp + $Rx_BF * $z_tmp; $z = $Ry_BF * $x_tmp - $Rx_BF * $y_tmp + $z_tmp; } else { throw new Excreption('Unknown datum transformation parameter type'); } // Give the point the new datum. $new_point = $point->withOrdinates($x, $y, $z)->withDatum($this); return $new_point; }