/** * This method is used to set the latitude/longitude (assumed to be of the * correct LatitudeType, LongitudeDirection, and LongitudeDomain. The Set * forces an attempted calculation of the projection X/Y values. This may or * may not be successful and a status is returned as such. * * @param lat Latitude value to project * * @param lon Longitude value to project * * @return bool */ bool PointPerspective::SetGround(const double lat, const double lon) { // Convert longitude to radians & clean up m_longitude = lon; double lonRadians = lon * PI / 180.0; if (m_longitudeDirection == PositiveWest) lonRadians *= -1.0; // Now convert latitude to radians & clean up ... it must be planetographic m_latitude = lat; double latRadians = lat; if (IsPlanetocentric()) latRadians = ToPlanetographic(latRadians); latRadians *= PI / 180.0; // Compute helper variables double deltaLon = (lonRadians - m_centerLongitude); double sinphi = sin(latRadians); double cosphi = cos(latRadians); double coslon = cos(deltaLon); // Lat/Lon cannot be projected double g = m_sinph0 * sinphi + m_cosph0 * cosphi * coslon; if (g < (1.0 / m_P)) { m_good = false; return m_good; } // Compute the coordinates double ksp = (m_P - 1.0) / (m_P - g); double x = m_equatorialRadius * ksp * cosphi * sin(deltaLon); double y = m_equatorialRadius * ksp * (m_cosph0 * sinphi - m_sinph0 * cosphi * coslon); SetComputedXY(x, y); m_good = true; return m_good; }
/** * Constructs an PointPerspective object * * @param label This argument must be a Label containing the proper mapping * information as indicated in the Projection class. Additionally, * the point perspective projection requires the center longitude * to be defined in the keyword CenterLongitude. * * @param allowDefaults If set to false the constructor expects that a keyword * of CenterLongitude will be in the label. Otherwise it * will attempt to compute the center longitude using the * middle of the longitude range specified in the labels. * Defaults to false. * * @throws IException::Io */ PointPerspective::PointPerspective(Pvl &label, bool allowDefaults) : TProjection::TProjection(label) { try { // Try to read the mapping group PvlGroup &mapGroup = label.findGroup("Mapping", Pvl::Traverse); // Compute and write the default center longitude if allowed and // necessary if ((allowDefaults) && (!mapGroup.hasKeyword("CenterLongitude"))) { double lon = (m_minimumLongitude + m_maximumLongitude) / 2.0; mapGroup += PvlKeyword("CenterLongitude", toString(lon)); } // Compute and write the default center latitude if allowed and // necessary if ((allowDefaults) && (!mapGroup.hasKeyword("CenterLatitude"))) { double lat = (m_minimumLatitude + m_maximumLatitude) / 2.0; mapGroup += PvlKeyword("CenterLatitude", toString(lat)); } // Get the center longitude & latitude m_centerLongitude = mapGroup["CenterLongitude"]; m_centerLatitude = mapGroup["CenterLatitude"]; if (IsPlanetocentric()) { m_centerLatitude = ToPlanetographic(m_centerLatitude); } // convert to radians, adjust for longitude direction m_centerLongitude *= PI / 180.0; m_centerLatitude *= PI / 180.0; if (m_longitudeDirection == PositiveWest) m_centerLongitude *= -1.0; // Calculate sine & cosine of center latitude m_sinph0 = sin(m_centerLatitude); m_cosph0 = cos(m_centerLatitude); // Get the distance above planet center (the point of perspective from // the center of planet), and calculate P m_distance = mapGroup["Distance"]; m_distance *= 1000.; m_P = 1.0 + (m_distance / m_equatorialRadius); } catch(IException &e) { QString message = "Invalid label group [Mapping]"; throw IException(e, IException::Io, message, _FILEINFO_); } }
/** * This method is used to set the latitude/longitude (assumed to be of the * correct LatitudeType, LongitudeDirection, and LongitudeDomain. The Set * forces an attempted calculation of the projection X/Y values. This may or * may not be successful and a status is returned as such. * * @param lat Latitude value to project * * @param lon Longitude value to project * * @return bool */ bool LunarAzimuthalEqualArea::SetGround(const double lat, const double lon) { // Convert longitude to radians m_longitude = lon; double lonRadians = lon * Isis::PI / 180.0; if (m_longitudeDirection == PositiveWest) lonRadians *= -1.0; // Now convert latitude to radians... it must be planetographic m_latitude = lat; double latRadians = lat; if (IsPlanetocentric()) latRadians = ToPlanetographic(latRadians); latRadians *= Isis::PI / 180.0; double x, y; if (lonRadians == 0.0 && latRadians == 0.0) { x = 0.0; y = 0.0; SetComputedXY(x, y); m_good = true; return true; } double E = acos(cos(latRadians) * cos(lonRadians)); double test = (sin(lonRadians) * cos(latRadians)) / sin(E); if (test > 1.0) test = 1.0; else if (test < -1.0) test = -1.0; double D = HALFPI - asin(test); if (latRadians < 0.0) D = -D; double radius = m_equatorialRadius; double PFAC = (HALFPI + m_maxLibration) / HALFPI; double RP = radius * sin(E / PFAC); x = RP * cos(D); y = RP * sin(D); SetComputedXY(x, y); m_good = true; return true; } // of SetGround
/** * This method is used to set the latitude/longitude (assumed to be of the * correct LatitudeType, LongitudeDirection, and LongitudeDomain. The Set * forces an attempted calculation of the projection X/Y values. This may or * may not be successful and a status is returned as such. * * @param lat Latitude value to project * * @param lon Longitude value to project * * @return bool */ bool TransverseMercator::SetGround(const double lat,const double lon) { // Get longitude & fix direction p_longitude = lon; if (p_longitudeDirection == PositiveWest) p_longitude *= -1.0; double cLonDeg = p_centerLongitude * 180.0 / Isis::PI; double deltaLon = p_longitude - cLonDeg; while (deltaLon < -360.0) deltaLon += 360.0; while (deltaLon > 360.0) deltaLon -= 360.0; double deltaLonRads = deltaLon * Isis::PI / 180.0; // Now convert latitude to radians & clean up ... it must be planetographic p_latitude = lat; double latRadians = p_latitude * Isis::PI / 180.0; if (IsPlanetocentric()) { latRadians = ToPlanetographic(p_latitude) * Isis::PI / 180.0; } double ml = p_equatorialRadius * (p_e0 * latRadians - p_e1 * sin(2.0 * latRadians) + p_e2 * sin(4.0 * latRadians) - p_e3 * sin(6.0 * latRadians)); // Declare variables const double epsilon = 1.0e-10; // Sphere Conversion double x,y; if (p_sph) { double cosphi = cos(latRadians); double b = cosphi * sin(deltaLonRads); // Point projects to infinity if (fabs(fabs(b) - 1.0) <= epsilon) { p_good = false; return p_good; } x = 0.5 * p_equatorialRadius * p_scalefactor * log((1.0 + b) / (1.0 - b)); // If arcosine argument is too close to 1, con=0.0 because arcosine(1)=0 double con = cosphi * cos(deltaLonRads) / sqrt(1.0 - b * b); if (fabs(con) > 1.0) { con = 0.0; } else { con = acos(con); } if(p_latitude < 0.0) con = -con; y = p_equatorialRadius * p_scalefactor * (con - p_centerLatitude); } // Ellipsoid Conversion else { if(fabs(Isis::HALFPI - fabs(latRadians)) < epsilon) { x = 0.0; y = p_scalefactor * (ml - p_ml0); } else { double sinphi = sin(latRadians); double cosphi = cos(latRadians); double al = cosphi * deltaLonRads; double als = al * al; double c = p_esp * cosphi * cosphi; double tq = tan(latRadians); double t = tq * tq; double n = p_equatorialRadius / sqrt (1.0 - p_eccsq * sinphi * sinphi); x = p_scalefactor * n * al * (1.0 + als / 6.0 * (1.0 - t + c + als / 20.0 * (5.0 - 18.0 * t + t * t + 72.0 * c - 58.0 * p_esp))); y = p_scalefactor *(ml - p_ml0 + n * tq * (als * (0.5 + als / 24.0 * (5.0 - t + 9.0 * c + 4.0 * c * c + als / 30.0 * (61.0 - 58.0 * t + t * t + 600.0 * c - 330.0 * p_esp))))); } } SetComputedXY(x,y); p_good = true; return p_good; }
/** * Constructs a TransverseMercator object * * @param label This argument must be a Label containing the proper mapping * information as indicated in the Projection class. Additionally, * the transversemercator projection requires the center longitude * to be defined in the keyword CenterLongitude, and the scale * factor to be defined in the keyword ScaleFactor. * * @param allowDefaults If set to false the constructor expects that a keyword * of CenterLongitude and ScaleFactor will be in the label. * Otherwise it will attempt to compute the center * longitude using the middle of the longitude range * specified in the label, and the scale factor will * default to 1.0. Defaults to false. * * @throws IException */ TransverseMercator::TransverseMercator(Pvl &label, bool allowDefaults) : TProjection::TProjection(label) { try { // Try to read the mapping group PvlGroup &mapGroup = label.findGroup("Mapping", Pvl::Traverse); // Compute and write the default center longitude if allowed and // necessary if ((allowDefaults) && (!mapGroup.hasKeyword("CenterLongitude"))) { double lon = (m_minimumLongitude + m_maximumLongitude) / 2.0; mapGroup += PvlKeyword("CenterLongitude", toString(lon)); } // Compute and write the default center latitude if allowed and // necessary if ((allowDefaults) && (!mapGroup.hasKeyword("CenterLatitude"))) { double lat = (m_minimumLatitude + m_maximumLatitude) / 2.0; mapGroup += PvlKeyword("CenterLatitude", toString(lat)); } // Get the center longitude & latitude m_centerLongitude = mapGroup["CenterLongitude"]; m_centerLatitude = mapGroup["CenterLatitude"]; // make sure the center latitude value is valid if (fabs(m_centerLatitude) >= 90.0) { string msg = "Invalid Center Latitude Value. Must be between -90 and 90"; throw IException(IException::Io, msg, _FILEINFO_); } // make sure the center longitude value is valid if (fabs(m_centerLongitude) > 360.0) { string msg = "Invalid Center Longitude Value. Must be between -360 and 360"; throw IException(IException::Io, msg, _FILEINFO_); } // convert latitude to planetographic if it is planetocentric if (IsPlanetocentric()) { m_centerLatitude = ToPlanetographic(m_centerLatitude); } // convert to radians and adjust for longitude direction if (m_longitudeDirection == PositiveWest) m_centerLongitude *= -1.0; m_centerLatitude *= PI / 180.0; m_centerLongitude *= PI / 180.0; // Compute other necessary variables. See Snyder, page 61 m_eccsq = Eccentricity() * Eccentricity(); m_esp = m_eccsq; m_e0 = 1.0 - 0.25 * m_eccsq * (1.0 + m_eccsq / 16.0 * (3.0 + 1.25 * m_eccsq)); m_e1 = 0.375 * m_eccsq * (1.0 + 0.25 * m_eccsq * (1.0 + 0.468750 * m_eccsq)); m_e2 = 0.058593750 * m_eccsq * m_eccsq * (1.0 + 0.750 * m_eccsq); m_e3 = m_eccsq * m_eccsq * m_eccsq * (35.0 / 3072.0); m_ml0 = m_equatorialRadius * (m_e0 * m_centerLatitude - m_e1 * sin(2.0 * m_centerLatitude) + m_e2 * sin(4.0 * m_centerLatitude) - m_e3 * sin(6.0 * m_centerLatitude)); // Set flag for sphere or ellipsiod m_sph = true; // Sphere if (Eccentricity() >= .00001) { m_sph = false; // Ellipsoid m_esp = m_eccsq / (1.0 - m_eccsq); } // Get the scale factor if ((allowDefaults) && (!mapGroup.hasKeyword("ScaleFactor"))) { mapGroup += PvlKeyword("ScaleFactor", toString(1.0)); } m_scalefactor = mapGroup["ScaleFactor"]; } catch(IException &e) { string message = "Invalid label group [Mapping]"; throw IException(e, IException::Io, message, _FILEINFO_); } }
/** * This method is used to set the latitude/longitude (assumed to be of the * correct LatitudeType, LongitudeDirection, and LongitudeDomain. The Set * forces an attempted calculation of the projection X/Y values. This may or * may not be successful and a status is returned as such. * * @param lat Latitude value to project * * @param lon Longitude value to project * * @return bool */ bool TransverseMercator::SetGround(const double lat, const double lon) { // Get longitude & fix direction m_longitude = lon; if (m_longitudeDirection == PositiveWest) m_longitude *= -1.0; double cLonDeg = m_centerLongitude * 180.0 / PI; double deltaLon = m_longitude - cLonDeg; while(deltaLon < -360.0) deltaLon += 360.0; while(deltaLon > 360.0) deltaLon -= 360.0; double deltaLonRads = deltaLon * PI / 180.0; // Now convert latitude to radians & clean up ... it must be planetographic m_latitude = lat; double latRadians = m_latitude * PI / 180.0; if (IsPlanetocentric()) { latRadians = ToPlanetographic(m_latitude) * PI / 180.0; } // distance along the meridian fromthe Equator to the latitude phi // see equation (3-21) on pages 61, 17. double M = m_equatorialRadius * (m_e0 * latRadians - m_e1 * sin(2.0 * latRadians) + m_e2 * sin(4.0 * latRadians) - m_e3 * sin(6.0 * latRadians)); // Declare variables const double epsilon = 1.0e-10; // Sphere Conversion double x, y; if (m_sph) { double cosphi = cos(latRadians); double b = cosphi * sin(deltaLonRads); // Point projects to infinity if (fabs(fabs(b) - 1.0) <= epsilon) { m_good = false; return m_good; } x = 0.5 * m_equatorialRadius * m_scalefactor * log((1.0 + b) / (1.0 - b)); // If arcosine argument is too close to 1, con=0.0 because arcosine(1)=0 double con = cosphi * cos(deltaLonRads) / sqrt(1.0 - b * b); if (fabs(con) > 1.0) { con = 0.0; } else { con = acos(con); } if (m_latitude < 0.0) con = -con; y = m_equatorialRadius * m_scalefactor * (con - m_centerLatitude); } // Ellipsoid Conversion else { if (fabs(HALFPI - fabs(latRadians)) < epsilon) { x = 0.0; y = m_scalefactor * (M - m_ml0); } else { // Define Snyder's variables for ellipsoidal projections, page61 double sinphi = sin(latRadians); double cosphi = cos(latRadians); double A = cosphi * deltaLonRads; // see equation (8-15), page 61 double Asquared = A * A; double C = m_esp * cosphi * cosphi; // see equation (8-14), page 61 double tanphi = tan(latRadians); double T = tanphi * tanphi; // see equation (8-13), page 61 double N = m_equatorialRadius / sqrt(1.0 - m_eccsq * sinphi * sinphi); // see equation (4-20), page 61 x = m_scalefactor * N * A * (1.0 + Asquared / 6.0 * (1.0 - T + C + Asquared / 20.0 *(5.0 - 18.0*T + T*T + 72.0*C - 58.0*m_esp))); y = m_scalefactor * (M - m_ml0 + N*tanphi*(Asquared * (0.5 + Asquared / 24.0 * (5.0 - T + 9.0*C + 4.0*C*C + Asquared / 30.0 *(61.0 - 58.0*T + T*T + 600.0*C - 330.0*m_esp))))); } } SetComputedXY(x, y); m_good = true; return m_good; }