/** * 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; }
/** * This method is used to set the projection x/y. The Set forces an attempted * calculation of the corresponding latitude/longitude position. This may or * may not be successful and a status is returned as such. * * @param x X coordinate of the projection in units that are the same as the * radii in the label * * @param y Y coordinate of the projection in units that are the same as the * radii in the label * * @return bool */ bool LunarAzimuthalEqualArea::SetCoordinate(const double x, const double y) { // Save the coordinate SetXY(x, y); double RP = sqrt((x * x) + (y * y)); double lat, lon; if (y == 0.0 && x == 0.0) { lat = 0.0; lon = 0.0; return true; } double radius = m_equatorialRadius; double D = atan2(y, x); double test = RP / radius; if (abs(test) > 1.0) { return false; } double EPSILON = 0.0000000001; double PFAC = (HALFPI + m_maxLibration) / HALFPI; double E = PFAC * asin(RP / radius); lat = HALFPI - (acos(sin(D) * sin(E))); if (abs(HALFPI - abs(lat)) <= EPSILON) { lon = 0.0; } else { test = sin(E) * cos(D) / sin(HALFPI - lat); if (test > 1.0) test = 1.0; else if (test < -1.0) test = -1.0; lon = asin(test); } if (E >= HALFPI) { if (lon <= 0.0) lon = -PI - lon; else lon = PI - lon; } // Convert to degrees m_latitude = lat * 180.0 / Isis::PI; m_longitude = lon * 180.0 / Isis::PI; // Cleanup the latitude if (IsPlanetocentric()) m_latitude = ToPlanetocentric(m_latitude); 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 projection x/y. The Set forces an attempted * calculation of the corresponding latitude/longitude position. This may or * may not be successful and a status is returned as such. * * @param x X coordinate of the projection in units that are the same as the * radii in the label * * @param y Y coordinate of the projection in units that are the same as the * radii in the label * * @return bool */ bool TransverseMercator::SetCoordinate(const double x, const double y) { // Save the coordinate SetXY(x,y); // Declare & Initialize variables double f,g,h,temp,con,phi,dphi,sinphi,cosphi,tanphi; double c,cs,t,ts,n,rp,d,ds; const double epsilon = 1.0e-10; // Sphere Conversion if (p_sph) { f = exp(GetX() / (p_equatorialRadius * p_scalefactor)); g = 0.5 * (f - 1.0 / f); temp = p_centerLatitude + GetY() / (p_equatorialRadius * p_scalefactor); h = cos(temp); con = sqrt((1.0 - h * h) / (1.0 + g * g)); if (con > 1.0) con = 1.0; if (con < -1.0) con = -1.0; p_latitude = asin(con); if (temp < 0.0 ) p_latitude = -p_latitude; p_longitude = p_centerLongitude; if (g != 0.0 || h != 0.0) { p_longitude = atan2(g,h) + p_centerLongitude; } } // Ellipsoid Conversion else if (!p_sph) { con = (p_ml0 + GetY() / p_scalefactor) / p_equatorialRadius; phi = con; for (int i = 1; i < 7; i++) { dphi = ((con + p_e1 * sin(2.0 * phi) - p_e2 * sin(4.0 * phi) + p_e3 * sin(6.0 * phi)) / p_e0) - phi; phi += dphi; if (fabs(dphi) <= epsilon) break; } // Didn't converge if (fabs(dphi) > epsilon) { p_good = false; return p_good; } if (fabs(phi) >= Isis::HALFPI) { if (GetY() >= 0.0) p_latitude = fabs(Isis::HALFPI); if (GetY() < 0.0) p_latitude = - fabs(Isis::HALFPI); p_longitude = p_centerLongitude; } else { sinphi = sin(phi); cosphi = cos(phi); tanphi = tan(phi); c = p_esp * cosphi * cosphi; cs = c * c; t = tanphi * tanphi; ts = t * t; con = 1.0 - p_eccsq * sinphi * sinphi; n = p_equatorialRadius / sqrt(con); rp = n * (1.0 - p_eccsq) / con; d = GetX() / (n * p_scalefactor); ds = d * d; p_latitude = phi - (n * tanphi * ds / rp) * (0.5 - ds / 24.0 * (5.0 + 3.0 * t + 10.0 * c - 4.0 * cs - 9.0 * p_esp - ds / 30.0 * (61.0 + 90.0 * t + 298.0 * c + 45.0 * ts - 252.0 * p_esp - 3.0 * cs))); // Latitude cannot be greater than + or - halfpi radians (or 90 degrees) if (fabs(p_latitude) > Isis::HALFPI) { p_good = false; return p_good; } p_longitude = p_centerLongitude + (d * (1.0 - ds / 6.0 * (1.0 + 2.0 * t + c - ds / 20.0 * (5.0 - 2.0 * c + 28.0 * t - 3.0 * cs + 8.0 * p_esp + 24.0 * ts))) / cosphi); } } // Convert to Degrees p_latitude *= 180.0 / Isis::PI; p_longitude *= 180.0 / Isis::PI; // Cleanup the longitude if (p_longitudeDirection == PositiveWest) p_longitude *= -1.0; // These need to be done for circular type projections p_longitude = To360Domain (p_longitude); if (p_longitudeDomain == 180) p_longitude = To180Domain(p_longitude); // Cleanup the latitude if (IsPlanetocentric()) p_latitude = ToPlanetocentric(p_latitude); p_good = true; return p_good; }
/** * 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; }
/** * This method is used to set the projection x/y. The Set forces an attempted * calculation of the corresponding latitude/longitude position. This may or * may not be successful and a status is returned as such. * * @param x X coordinate of the projection in units that are the same as the * radii in the label * * @param y Y coordinate of the projection in units that are the same as the * radii in the label * * @return bool */ bool PointPerspective::SetCoordinate(const double x, const double y) { // Save the coordinate SetXY(x, y); // Declare instance variables and calculate rho double rho, rp, con, com, z, sinz, cosz; const double epsilon = 1.0e-10; rho = sqrt(GetX() * GetX() + GetY() * GetY()); rp = rho / m_equatorialRadius; con = m_P - 1.0; com = m_P + 1.0; // Error calculating rho - should be less than equatorial radius if (rp > (sqrt(con / com))) { m_good = false; return m_good; } // Calculate the latitude and longitude m_longitude = m_centerLongitude; if (fabs(rho) <= epsilon) { m_latitude = m_centerLatitude; } else { if (rp <= epsilon) { sinz = 0.0; } else { sinz = (m_P - sqrt(1.0 - rp * rp * com / con)) / (con / rp + rp / con); } z = asin(sinz); sinz = sin(z); cosz = cos(z); con = cosz * m_sinph0 + GetY() * sinz * m_cosph0 / rho; if (con > 1.0) con = 1.0; if (con < -1.0) con = -1.0; m_latitude = asin(con); con = fabs(m_centerLatitude) - HALFPI; if (fabs(con) <= epsilon) { if (m_centerLatitude >= 0.0) { m_longitude += atan2(GetX(), -GetY()); } else { m_longitude += atan2(-GetX(), GetY()); } } else { con = cosz - m_sinph0 * sin(m_latitude); if ((fabs(con) >= epsilon) || (fabs(GetX()) >= epsilon)) { m_longitude += atan2(GetX() * sinz * m_cosph0, con * rho); } } } // Convert to degrees m_latitude *= 180.0 / PI; m_longitude *= 180.0 / PI; // Cleanup the longitude if (m_longitudeDirection == PositiveWest) m_longitude *= -1.0; // These need to be done for circular type projections m_longitude = To360Domain(m_longitude); if (m_longitudeDomain == 180) m_longitude = To180Domain(m_longitude); // Cleanup the latitude if (IsPlanetocentric()) m_latitude = ToPlanetocentric(m_latitude); m_good = true; return m_good; }