/** * 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; }