USGS

Isis 3.0 Application Source Code Reference

Home

map2map.cpp

Go to the documentation of this file.
00001 #define GUIHELPERS
00002 
00003 #include "Isis.h"
00004 #include "ProcessRubberSheet.h"
00005 #include "ProjectionFactory.h"
00006 #include "Projection.h"
00007 #include "map2map.h"
00008 
00009 using namespace std;
00010 using namespace Isis;
00011 
00012 void PrintMap();
00013 void LoadMapRange();
00014 
00015 map <string, void *> GuiHelpers() {
00016   map <string, void *> helper;
00017   helper ["PrintMap"] = (void *) PrintMap;
00018   helper ["LoadMapRange"] = (void *) LoadMapRange;
00019   return helper;
00020 }
00021 
00022 void IsisMain() {
00023   // We will be warping a cube
00024   ProcessRubberSheet p;
00025 
00026   // Get the map projection file provided by the user
00027   UserInterface &ui = Application::GetUserInterface();
00028   Pvl userPvl(ui.GetFilename("MAP"));
00029   PvlGroup &userMappingGrp = userPvl.FindGroup("Mapping", Pvl::Traverse);
00030 
00031   // Open the input cube and get the projection
00032   Cube *icube = p.SetInputCube("FROM");
00033 
00034   // Get the mapping group
00035   PvlGroup fromMappingGrp = icube->getGroup("Mapping");
00036   Projection *inproj = icube->getProjection();
00037   PvlGroup outMappingGrp = fromMappingGrp;
00038 
00039   // If the default range is FROM, then wipe out any range data in user mapping file
00040   if(ui.GetString("DEFAULTRANGE").compare("FROM") == 0 && !ui.GetBoolean("MATCHMAP")) {
00041     if(userMappingGrp.HasKeyword("MinimumLatitude")) {
00042       userMappingGrp.DeleteKeyword("MinimumLatitude");
00043     }
00044 
00045     if(userMappingGrp.HasKeyword("MaximumLatitude")) {
00046       userMappingGrp.DeleteKeyword("MaximumLatitude");
00047     }
00048 
00049     if(userMappingGrp.HasKeyword("MinimumLongitude")) {
00050       userMappingGrp.DeleteKeyword("MinimumLongitude");
00051     }
00052 
00053     if(userMappingGrp.HasKeyword("MaximumLongitude")) {
00054       userMappingGrp.DeleteKeyword("MaximumLongitude");
00055     }
00056   }
00057 
00058   // Deal with user overrides entered in the GUI. Do this by changing the user's mapping group, which
00059   // will then overlay anything in the output mapping group.
00060   if(ui.WasEntered("MINLAT") && !ui.GetBoolean("MATCHMAP")) {
00061     userMappingGrp.AddKeyword(PvlKeyword("MinimumLatitude", ui.GetDouble("MINLAT")), Pvl::Replace);
00062   }
00063 
00064   if(ui.WasEntered("MAXLAT") && !ui.GetBoolean("MATCHMAP")) {
00065     userMappingGrp.AddKeyword(PvlKeyword("MaximumLatitude", ui.GetDouble("MAXLAT")), Pvl::Replace);
00066   }
00067 
00068   if(ui.WasEntered("MINLON") && !ui.GetBoolean("MATCHMAP")) {
00069     userMappingGrp.AddKeyword(PvlKeyword("MinimumLongitude", ui.GetDouble("MINLON")), Pvl::Replace);
00070   }
00071 
00072   if(ui.WasEntered("MAXLON") && !ui.GetBoolean("MATCHMAP")) {
00073     userMappingGrp.AddKeyword(PvlKeyword("MaximumLongitude", ui.GetDouble("MAXLON")), Pvl::Replace);
00074   }
00075 
00076   /**
00077    * If the user is changing from positive east to positive west, or vice-versa, the output minimum is really
00078    * the input maximum. However, the user mapping group must be left unaffected (an input minimum must be the
00079    * output minimum). To accomplish this, we swap the minimums/maximums in the output group ahead of time. This
00080    * causes the minimums and maximums to correlate to the output minimums and maximums. That way when we copy
00081    * the user mapping group into the output group a mimimum overrides a minimum and a maximum overrides a maximum.
00082    */
00083   bool sameDirection = true;
00084   if(userMappingGrp.HasKeyword("LongitudeDirection")) {
00085     if(((string)userMappingGrp["LongitudeDirection"]).compare(fromMappingGrp["LongitudeDirection"]) != 0) {
00086       sameDirection = false;
00087     }
00088   }
00089 
00090   // Since the out mapping group came from the from mapping group, which came from a valid cube,
00091   // we can assume both min/max lon exists if min longitude exists.
00092   if(!sameDirection && outMappingGrp.HasKeyword("MinimumLongitude")) {
00093     double minLon = outMappingGrp["MinimumLongitude"];
00094     double maxLon = outMappingGrp["MaximumLongitude"];
00095 
00096     outMappingGrp["MaximumLongitude"] = minLon;
00097     outMappingGrp["MinimumLongitude"] = maxLon;
00098   }
00099 
00100   if(ui.GetString("PIXRES").compare("FROM") == 0 && !ui.GetBoolean("MATCHMAP")) {
00101     // Resolution will be in fromMappingGrp and outMappingGrp at this time
00102     //   delete from user mapping grp
00103     if(userMappingGrp.HasKeyword("Scale")) {
00104       userMappingGrp.DeleteKeyword("Scale");
00105     }
00106 
00107     if(userMappingGrp.HasKeyword("PixelResolution")) {
00108       userMappingGrp.DeleteKeyword("PixelResolution");
00109     }
00110   }
00111   else if(ui.GetString("PIXRES").compare("MAP") == 0 || ui.GetBoolean("MATCHMAP")) {
00112     // Resolution will be in userMappingGrp - delete all others
00113     if(outMappingGrp.HasKeyword("Scale")) {
00114       outMappingGrp.DeleteKeyword("Scale");
00115     }
00116 
00117     if(outMappingGrp.HasKeyword("PixelResolution")) {
00118       outMappingGrp.DeleteKeyword("PixelResolution");
00119     }
00120 
00121     if(fromMappingGrp.HasKeyword("Scale"));
00122     {
00123       fromMappingGrp.DeleteKeyword("Scale");
00124     }
00125 
00126     if(fromMappingGrp.HasKeyword("PixelResolution")) {
00127       fromMappingGrp.DeleteKeyword("PixelResolution");
00128     }
00129   }
00130   else if(ui.GetString("PIXRES").compare("MPP") == 0) {
00131     // Resolution specified - delete all and add to outMappingGrp
00132     if(outMappingGrp.HasKeyword("Scale")) {
00133       outMappingGrp.DeleteKeyword("Scale");
00134     }
00135 
00136     if(outMappingGrp.HasKeyword("PixelResolution")) {
00137       outMappingGrp.DeleteKeyword("PixelResolution");
00138     }
00139 
00140     if(fromMappingGrp.HasKeyword("Scale")) {
00141       fromMappingGrp.DeleteKeyword("Scale");
00142     }
00143 
00144     if(fromMappingGrp.HasKeyword("PixelResolution")) {
00145       fromMappingGrp.DeleteKeyword("PixelResolution");
00146     }
00147 
00148     if(userMappingGrp.HasKeyword("Scale")) {
00149       userMappingGrp.DeleteKeyword("Scale");
00150     }
00151 
00152     if(userMappingGrp.HasKeyword("PixelResolution")) {
00153       userMappingGrp.DeleteKeyword("PixelResolution");
00154     }
00155 
00156     outMappingGrp.AddKeyword(PvlKeyword("PixelResolution", ui.GetDouble("RESOLUTION"), "meters/pixel"), Pvl::Replace);
00157   }
00158   else if(ui.GetString("PIXRES").compare("PPD") == 0) {
00159     // Resolution specified - delete all and add to outMappingGrp
00160     if(outMappingGrp.HasKeyword("Scale")) {
00161       outMappingGrp.DeleteKeyword("Scale");
00162     }
00163 
00164     if(outMappingGrp.HasKeyword("PixelResolution")) {
00165       outMappingGrp.DeleteKeyword("PixelResolution");
00166     }
00167 
00168     if(fromMappingGrp.HasKeyword("Scale")) {
00169       fromMappingGrp.DeleteKeyword("Scale");
00170     }
00171 
00172     if(fromMappingGrp.HasKeyword("PixelResolution")) {
00173       fromMappingGrp.DeleteKeyword("PixelResolution");
00174     }
00175 
00176     if(userMappingGrp.HasKeyword("Scale")) {
00177       userMappingGrp.DeleteKeyword("Scale");
00178     }
00179 
00180     if(userMappingGrp.HasKeyword("PixelResolution")) {
00181       userMappingGrp.DeleteKeyword("PixelResolution");
00182     }
00183 
00184     outMappingGrp.AddKeyword(PvlKeyword("Scale", ui.GetDouble("RESOLUTION"), "pixels/degree"), Pvl::Replace);
00185   }
00186 
00187   // Rotation will NOT Propagate
00188   if(outMappingGrp.HasKeyword("Rotation")) {
00189     outMappingGrp.DeleteKeyword("Rotation");
00190   }
00191 
00192 
00193   /**
00194    * The user specified map template file overrides what ever is in the
00195    * cube's mapping group.
00196    */
00197   for(int keyword = 0; keyword < userMappingGrp.Keywords(); keyword ++) {
00198     outMappingGrp.AddKeyword(userMappingGrp[keyword], Pvl::Replace);
00199   }
00200 
00201   /**
00202    * Now, we have to deal with unit conversions. We convert only if the following are true:
00203    *   1) We used values from the input cube
00204    *   2) The values are longitudes or latitudes
00205    *   3) The map file or user-specified information uses a different measurement system than
00206    *        the input cube for said values.
00207    *
00208    * The data is corrected for:
00209    *   1) Positive east/positive west
00210    *   2) Longitude domain
00211    *   3) planetographic/planetocentric.
00212    */
00213 
00214   // First, the longitude direction
00215   if(!sameDirection) {
00216     PvlGroup longitudes = inproj->MappingLongitudes();
00217 
00218     for(int index = 0; index < longitudes.Keywords(); index ++) {
00219       if(!userMappingGrp.HasKeyword(longitudes[index].Name())) {
00220         // use the from domain because that's where our values are coming from
00221         if(((string)userMappingGrp["LongitudeDirection"]).compare("PositiveEast") == 0) {
00222           outMappingGrp[longitudes[index].Name()] =
00223             Projection::ToPositiveEast(outMappingGrp[longitudes[index].Name()], outMappingGrp["LongitudeDomain"]);
00224         }
00225         else {
00226           outMappingGrp[longitudes[index].Name()] =
00227             Projection::ToPositiveWest(outMappingGrp[longitudes[index].Name()], outMappingGrp["LongitudeDomain"]);
00228         }
00229       }
00230     }
00231   }
00232 
00233   // Second, longitude domain
00234   if(userMappingGrp.HasKeyword("LongitudeDomain")) { // user set a new domain?
00235     if((int)userMappingGrp["LongitudeDomain"] != (int)fromMappingGrp["LongitudeDomain"]) { // new domain different?
00236       PvlGroup longitudes = inproj->MappingLongitudes();
00237 
00238       for(int index = 0; index < longitudes.Keywords(); index ++) {
00239         if(!userMappingGrp.HasKeyword(longitudes[index].Name())) {
00240           if((int)userMappingGrp["LongitudeDomain"] == 180) {
00241             outMappingGrp[longitudes[index].Name()] = Projection::To180Domain(outMappingGrp[longitudes[index].Name()]);
00242           }
00243           else {
00244             outMappingGrp[longitudes[index].Name()] = Projection::To360Domain(outMappingGrp[longitudes[index].Name()]);
00245           }
00246         }
00247       }
00248 
00249     }
00250   }
00251 
00252   // Third, planetographic/planetocentric
00253   if(userMappingGrp.HasKeyword("LatitudeType")) { // user set a new domain?
00254     if(((string)userMappingGrp["LatitudeType"]).compare(fromMappingGrp["LatitudeType"]) != 0) { // new lat type different?
00255 
00256       PvlGroup latitudes = inproj->MappingLatitudes();
00257 
00258       for(int index = 0; index < latitudes.Keywords(); index ++) {
00259         if(!userMappingGrp.HasKeyword(latitudes[index].Name())) {
00260           if(((string)userMappingGrp["LatitudeType"]).compare("Planetographic") == 0) {
00261             outMappingGrp[latitudes[index].Name()] = Projection::ToPlanetographic(
00262                   (double)fromMappingGrp[latitudes[index].Name()],
00263                   (double)fromMappingGrp["EquatorialRadius"],
00264                   (double)fromMappingGrp["PolarRadius"]);
00265           }
00266           else {
00267             outMappingGrp[latitudes[index].Name()] = Projection::ToPlanetocentric(
00268                   (double)fromMappingGrp[latitudes[index].Name()],
00269                   (double)fromMappingGrp["EquatorialRadius"],
00270                   (double)fromMappingGrp["PolarRadius"]);
00271           }
00272         }
00273       }
00274 
00275     }
00276   }
00277 
00278   // Try a couple equivalent longitudes to fix the ordering of min,max for border cases
00279   if ((double)outMappingGrp["MinimumLongitude"] >=
00280       (double)outMappingGrp["MaximumLongitude"]) {
00281 
00282     if ((string)outMappingGrp["MinimumLongitude"] == "180.0" && 
00283         (int)userMappingGrp["LongitudeDomain"] == 180)
00284       outMappingGrp["MinimumLongitude"] = "-180";
00285 
00286     if ((string)outMappingGrp["MaximumLongitude"] == "-180.0" &&
00287         (int)userMappingGrp["LongitudeDomain"] == 180)
00288       outMappingGrp["MaximumLongitude"] = "180";
00289 
00290     if ((string)outMappingGrp["MinimumLongitude"] == "360.0" &&
00291         (int)userMappingGrp["LongitudeDomain"] == 360)
00292       outMappingGrp["MinimumLongitude"] = "0";
00293 
00294     if ((string)outMappingGrp["MaximumLongitude"] == "0.0" &&
00295         (int)userMappingGrp["LongitudeDomain"] == 360)
00296       outMappingGrp["MaximumLongitude"] = "360";
00297   }
00298 
00299   // If MinLon/MaxLon out of order, we weren't able to calculate the correct values
00300   if((double)outMappingGrp["MinimumLongitude"] >= (double)outMappingGrp["MaximumLongitude"]) {
00301     if(!ui.WasEntered("MINLON") || !ui.WasEntered("MAXLON")) {
00302       string msg = "Unable to determine the correct [MinimumLongitude,MaximumLongitude].";
00303       msg += " Please specify these values in the [MINLON,MAXLON] parameters";
00304       throw iException::Message(iException::Pvl, msg, _FILEINFO_);
00305     }
00306   }
00307 
00308   int samples, lines;
00309   Pvl mapData;
00310   // Copy to preserve cube labels so we can match cube size
00311   if(userPvl.HasObject("IsisCube")) {
00312     mapData = userPvl;
00313     mapData.FindObject("IsisCube").DeleteGroup("Mapping");
00314     mapData.FindObject("IsisCube").AddGroup(outMappingGrp);
00315   }
00316   else {
00317     mapData.AddGroup(outMappingGrp);
00318   }
00319 
00320   // *NOTE: The UpperLeftX,UpperLeftY keywords will not be used in the CreateForCube
00321   //   method, and they will instead be recalculated. This is correct.
00322   Projection *outproj = ProjectionFactory::CreateForCube(mapData, samples, lines,
00323                         ui.GetBoolean("MATCHMAP"));
00324 
00325   // Set up the transform object which will simply map
00326   // output line/samps -> output lat/lons -> input line/samps
00327   Transform *transform = new map2map(icube->getSampleCount(),
00328                                      icube->getLineCount(),
00329                                      icube->getProjection(),
00330                                      samples,
00331                                      lines,
00332                                      outproj,
00333                                      ui.GetBoolean("TRIM"));
00334 
00335   // Allocate the output cube and add the mapping labels
00336   Cube *ocube = p.SetOutputCube("TO", transform->OutputSamples(),
00337                                 transform->OutputLines(),
00338                                 icube->getBandCount());
00339 
00340   PvlGroup cleanOutGrp = outproj->Mapping();
00341 
00342   // ProjectionFactory::CreateForCube updated mapData to have the correct
00343   //   upperleftcornerx, upperleftcornery, scale and resolution. Use these
00344   //   updated numbers.
00345   cleanOutGrp.AddKeyword(mapData.FindGroup("Mapping", Pvl::Traverse)["UpperLeftCornerX"], Pvl::Replace);
00346   cleanOutGrp.AddKeyword(mapData.FindGroup("Mapping", Pvl::Traverse)["UpperLeftCornerY"], Pvl::Replace);
00347   cleanOutGrp.AddKeyword(mapData.FindGroup("Mapping", Pvl::Traverse)["Scale"], Pvl::Replace);
00348   cleanOutGrp.AddKeyword(mapData.FindGroup("Mapping", Pvl::Traverse)["PixelResolution"], Pvl::Replace);
00349 
00350   ocube->putGroup(cleanOutGrp);
00351 
00352   // Set up the interpolator
00353   Interpolator *interp;
00354   if(ui.GetString("INTERP") == "NEARESTNEIGHBOR") {
00355     interp = new Interpolator(Interpolator::NearestNeighborType);
00356   }
00357   else if(ui.GetString("INTERP") == "BILINEAR") {
00358     interp = new Interpolator(Interpolator::BiLinearType);
00359   }
00360   else if(ui.GetString("INTERP") == "CUBICCONVOLUTION") {
00361     interp = new Interpolator(Interpolator::CubicConvolutionType);
00362   }
00363   else {
00364     string msg = "Unknow value for INTERP [" + ui.GetString("INTERP") + "]";
00365     throw iException::Message(iException::Programmer, msg, _FILEINFO_);
00366   }
00367 
00368   // Warp the cube
00369   p.StartProcess(*transform, *interp);
00370   p.EndProcess();
00371 
00372   Application::Log(cleanOutGrp);
00373 
00374   // Cleanup
00375   delete transform;
00376   delete interp;
00377 }
00378 
00379 // Transform object constructor
00380 map2map::map2map(const int inputSamples, const int inputLines, Projection *inmap,
00381                  const int outputSamples, const int outputLines, Projection *outmap,
00382                  bool trim) {
00383   p_inputSamples = inputSamples;
00384   p_inputLines = inputLines;
00385   p_inmap = inmap;
00386 
00387   p_outputSamples = outputSamples;
00388   p_outputLines = outputLines;
00389   p_outmap = outmap;
00390 
00391   p_trim = trim;
00392 
00393   p_inputWorldSize = 0;
00394   bool wrapPossible = inmap->IsEquatorialCylindrical();
00395 
00396   if(inmap->IsEquatorialCylindrical()) {
00397     // Figure out how many samples 360 degrees is
00398     wrapPossible = wrapPossible && inmap->SetUniversalGround(0, 0);
00399     int worldStart = (int)(inmap->WorldX() + 0.5);
00400     wrapPossible = wrapPossible && inmap->SetUniversalGround(0, 180);
00401     int worldEnd = (int)(inmap->WorldX() + 0.5);
00402 
00403     p_inputWorldSize = abs(worldEnd - worldStart) * 2;
00404   }
00405 }
00406 
00407 // Transform method mapping output line/samps to lat/lons to input line/samps
00408 bool map2map::Xform(double &inSample, double &inLine,
00409                     const double outSample, const double outLine) {
00410   // See if the output image coordinate converts to lat/lon
00411   if(!p_outmap->SetWorld(outSample, outLine)) return false;
00412 
00413   // See if we should trim
00414   if((p_trim) && (p_outmap->HasGroundRange())) {
00415     if(p_outmap->Latitude() < p_outmap->MinimumLatitude()) return false;
00416     if(p_outmap->Latitude() > p_outmap->MaximumLatitude()) return false;
00417     if(p_outmap->Longitude() < p_outmap->MinimumLongitude()) return false;
00418     if(p_outmap->Longitude() > p_outmap->MaximumLongitude()) return false;
00419   }
00420 
00421   // Get the universal lat/lon and see if it can be converted to input line/samp
00422   double lat = p_outmap->UniversalLatitude();
00423   double lon = p_outmap->UniversalLongitude();
00424   if(!p_inmap->SetUniversalGround(lat, lon)) return false;
00425 
00426   inSample = p_inmap->WorldX();
00427   inLine = p_inmap->WorldY();
00428 
00429   if(p_inputWorldSize != 0) {
00430     // Try to correct the sample if we can,
00431     //   this is the simplest way to code the
00432     //   translation although it probably could
00433     //   be done in one "if"
00434     while(inSample < 0.5) {
00435       inSample += p_inputWorldSize;
00436     }
00437 
00438     while(inSample > p_inputSamples + 0.5) {
00439       inSample -= p_inputWorldSize;
00440     }
00441   }
00442 
00443   // Make sure the point is inside the input image
00444   if(inSample < 0.5) return false;
00445   if(inLine < 0.5) return false;
00446   if(inSample > p_inputSamples + 0.5) return false;
00447   if(inLine > p_inputLines + 0.5) return false;
00448 
00449   // Everything is good
00450   return true;
00451 }
00452 
00453 int map2map::OutputSamples() const {
00454   return p_outputSamples;
00455 }
00456 
00457 int map2map::OutputLines() const {
00458   return p_outputLines;
00459 }
00460 
00461 
00462 // Helper function to print out mapfile to session log
00463 void PrintMap() {
00464   UserInterface &ui = Application::GetUserInterface();
00465 
00466   // Get mapping group from map file
00467   Pvl userMap;
00468   userMap.Read(ui.GetFilename("MAP"));
00469   PvlGroup &userGrp = userMap.FindGroup("Mapping", Pvl::Traverse);
00470 
00471   //Write map file out to the log
00472   Isis::Application::GuiLog(userGrp);
00473 }
00474 
00475 void LoadMapRange() {
00476   UserInterface &ui = Application::GetUserInterface();
00477 
00478   // Get map file
00479   Pvl userMap;
00480 
00481   try {
00482     userMap.Read(ui.GetFilename("MAP"));
00483   }
00484   catch(iException &e) {
00485     e.Clear();
00486   }
00487 
00488   // Get input cube
00489   Pvl fromMap;
00490 
00491   try {
00492     fromMap.Read(ui.GetFilename("FROM"));
00493   }
00494   catch(iException &e) {
00495     e.Clear();
00496   }
00497 
00498   // Try to get the mapping groups
00499   PvlGroup fromMapping("Mapping");
00500 
00501   try {
00502     fromMapping = fromMap.FindGroup("Mapping", Pvl::Traverse);
00503   }
00504   catch(iException &e) {
00505     e.Clear();
00506   }
00507 
00508   PvlGroup userMapping("Mapping");
00509 
00510   try {
00511     userMapping = userMap.FindGroup("Mapping", Pvl::Traverse);
00512   }
00513   catch(iException &e) {
00514     e.Clear();
00515   }
00516 
00517   // Do conversions on from map
00518 
00519   // Longitude conversions first
00520   if(userMapping.HasKeyword("LongitudeDirection")) {
00521     if(((string)userMapping["LongitudeDirection"]).compare(fromMapping["LongitudeDirection"]) != 0) {
00522       double minLon = fromMapping["MinimumLongitude"];
00523       double maxLon = fromMapping["MaximumLongitude"];
00524       int domain = fromMapping["LongitudeDomain"];
00525 
00526       if(userMapping.HasKeyword("LongitudeDomain")) {
00527         domain = userMapping["LongitudeDomain"];
00528       }
00529 
00530       if((string)userMapping["LongitudeDirection"] == "PositiveEast") {
00531         fromMapping["MaximumLongitude"] = Projection::ToPositiveEast(minLon, domain);
00532         fromMapping["MinimumLongitude"] = Projection::ToPositiveEast(maxLon, domain);
00533       }
00534       else if((string)userMapping["LongitudeDirection"] == "PositiveWest") {
00535         fromMapping["MaximumLongitude"] = Projection::ToPositiveWest(minLon, domain);
00536         fromMapping["MinimumLongitude"] = Projection::ToPositiveWest(maxLon, domain);
00537       }
00538     }
00539   }
00540 
00541   // Latitude conversions now
00542   if(userMapping.HasKeyword("LatitudeType")) { // user set a new domain?
00543     if(((string)userMapping["LatitudeType"]).compare(fromMapping["LatitudeType"]) != 0) { // new lat type different?
00544       if(((string)userMapping["LatitudeType"]).compare("Planetographic") == 0) {
00545         fromMapping["MinimumLatitude"] = Projection::ToPlanetographic(
00546                                            (double)fromMapping["MinimumLatitude"],
00547                                            (double)fromMapping["EquatorialRadius"],
00548                                            (double)fromMapping["PolarRadius"]);
00549         fromMapping["MaximumLatitude"] = Projection::ToPlanetographic(
00550                                            (double)fromMapping["MaximumLatitude"],
00551                                            (double)fromMapping["EquatorialRadius"],
00552                                            (double)fromMapping["PolarRadius"]);
00553       }
00554       else {
00555         fromMapping["MinimumLatitude"] = Projection::ToPlanetocentric(
00556                                            (double)fromMapping["MinimumLatitude"],
00557                                            (double)fromMapping["EquatorialRadius"],
00558                                            (double)fromMapping["PolarRadius"]);
00559         fromMapping["MaximumLatitude"] = Projection::ToPlanetocentric(
00560                                            (double)fromMapping["MaximumLatitude"],
00561                                            (double)fromMapping["EquatorialRadius"],
00562                                            (double)fromMapping["PolarRadius"]);
00563       }
00564     }
00565   }
00566 
00567   // Failed at longitudes, use our originals!
00568   if((double)fromMapping["MinimumLongitude"] >= (double)fromMapping["MaximumLongitude"]) {
00569     try {
00570       fromMapping["MinimumLongitude"] = fromMap.FindGroup("Mapping", Pvl::Traverse)["MinimumLongitude"];
00571       fromMapping["MaximumLongitude"] = fromMap.FindGroup("Mapping", Pvl::Traverse)["MaximumLongitude"];
00572     }
00573     catch(iException &e) {
00574       e.Clear();
00575     }
00576   }
00577 
00578   // Overlay lat/lons in map file (if DEFAULTRANGE=MAP)
00579   if(ui.GetString("DEFAULTRANGE") == "MAP") {
00580     if(userMapping.HasKeyword("MinimumLatitude")) {
00581       fromMapping["MinimumLatitude"] = userMapping["MinimumLatitude"];
00582     }
00583 
00584     if(userMapping.HasKeyword("MaximumLatitude")) {
00585       fromMapping["MaximumLatitude"] = userMapping["MaximumLatitude"];
00586     }
00587 
00588     if(userMapping.HasKeyword("MinimumLongitude")) {
00589       fromMapping["MinimumLongitude"] = userMapping["MinimumLongitude"];
00590     }
00591 
00592     if(userMapping.HasKeyword("MaximumLongitude")) {
00593       fromMapping["MaximumLongitude"] = userMapping["MaximumLongitude"];
00594     }
00595   }
00596 
00597   if(ui.WasEntered("MINLAT")) {
00598     ui.Clear("MINLAT");
00599   }
00600 
00601   if(ui.WasEntered("MAXLAT")) {
00602     ui.Clear("MAXLAT");
00603   }
00604 
00605   if(ui.WasEntered("MINLON")) {
00606     ui.Clear("MINLON");
00607   }
00608 
00609   if(ui.WasEntered("MAXLON")) {
00610     ui.Clear("MAXLON");
00611   }
00612 
00613   ui.PutDouble("MINLAT", fromMapping["MinimumLatitude"]);
00614   ui.PutDouble("MAXLAT", fromMapping["MaximumLatitude"]);
00615   ui.PutDouble("MINLON", fromMapping["MinimumLongitude"]);
00616   ui.PutDouble("MAXLON", fromMapping["MaximumLongitude"]);
00617 }