USGS

Isis 3.0 Application Source Code Reference

Home

CamTools.cpp

Go to the documentation of this file.
00001 /* @file                                                                  
00002  * $Revision: 1.15 $
00003  * $Date: 2009/08/25 01:37:55 $
00004  * $Id: CamTools.cpp,v 1.15 2009/08/25 01:37:55 kbecker Exp $
00005  * 
00006  *   Unless noted otherwise, the portions of Isis written by the USGS are 
00007  *   public domain. See individual third-party library and package descriptions 
00008  *   for intellectual property information, user agreements, and related  
00009  *   information.                                                         
00010  *                                                                        
00011  *   Although Isis has been used by the USGS, no warranty, expressed or   
00012  *   implied, is made by the USGS as to the accuracy and functioning of such 
00013  *   software and related material nor shall the fact of distribution     
00014  *   constitute any such warranty, and no responsibility is assumed by the
00015  *   USGS in connection therewith.                                        
00016  *                                                                        
00017  *   For additional information, launch                                   
00018  *   $ISISROOT/doc//documents/Disclaimers/Disclaimers.html                
00019  *   in a browser or see the Privacy & Disclaimers page on the Isis website,
00020  *   http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on
00021  *   http://www.usgs.gov/privdacy.html.                                    
00022  */ 
00023 #include <cmath>
00024 #include <string>
00025 #include <vector>
00026 #include <numeric>
00027 #include <algorithm>
00028 #if defined(DEBUG)
00029 #include <fstream>
00030 #endif
00031 #include <iostream>
00032 #include <iomanip>
00033 #include <sstream>
00034 
00035 #include "CamTools.h"
00036 #include "CameraFactory.h"
00037 #include "Pvl.h"
00038 #include "SpecialPixel.h"
00039 #include "iTime.h"
00040 #include "iString.h"
00041 #include "iException.h"
00042 #include "Statistics.h"
00043 #include "SpiceUsr.h"
00044 #include "ProjectionFactory.h"
00045 #include "PolygonTools.h"
00046 
00047 #include "geos/geom/GeometryFactory.h"
00048 #include "geos/geom/Geometry.h"
00049 #include "geos/geom/Point.h"
00050 
00051 using namespace std;
00052 
00053 namespace Isis {
00054 
00055 /**
00056  * @brief Round values to specified precision
00057  * 
00058  * @param value  Value to round
00059  * @param precision Precision to round value to
00060  * 
00061  * @return double Rounded value
00062  */
00063 inline double SetRound(double value, const int precision) {
00064     double scale = pow(10.0, precision);
00065     value = round(value * scale) / scale;
00066     return (value);
00067 }
00068 
00069 /** 
00070  * @brief Helper function to convert values to doubles
00071  * 
00072  * @param T Type of value to convert
00073  * @param value Value to convert
00074  * 
00075  * @return double Converted value
00076  */
00077 template <typename T> double ToDouble(const T &value) {
00078     return (iString(value).Trim(" \r\t\n").ToDouble());
00079 }
00080 
00081 /** 
00082  * @brief Helper function to convert values to strings
00083  * 
00084  * @param T Type of value to convert
00085  * @param value Value to convert
00086  * 
00087  * @return string Converted value
00088  */
00089 template <typename T> std::string ToString(const T &value) {
00090     return (iString(value).Trim(" \r\t\n"));
00091 }
00092 
00093 
00094 
00095 bool BandGeometry::isPointValid(const double &sample, const double &line, 
00096                                 const Camera *camera) const {
00097   int nl(_nLines), ns(_nSamps);
00098   if ( camera != 0 ) {
00099     nl = camera->Lines();
00100     ns = camera->Samples();
00101   } 
00102 
00103   if (line < 0.5) return (false);
00104   if (line > (nl+0.5)) return (false);
00105   if (sample < 0.5) return (false);
00106   if (sample > (ns+0.5)) return (false);
00107   return (true);
00108 }
00109 
00110 bool BandGeometry::hasCenterGeometry() const {
00111    BandPropertiesListConstIter b;
00112    for ( b = _gBandList.begin() ; b != _gBandList.end() ; ++b ) {
00113      if ( !IsSpecial(b->centerLatitude) ) return (true);
00114    }
00115    // No valid center exists
00116    return (false);
00117 }
00118 
00119 /**
00120  * @brief Check geometry for presence of limb 
00121  *  
00122  * This method checks corner geometry coordinates for the presence of a planet 
00123  * limb.  This is a simple check for validity of the latitude coordinate at each 
00124  * image corner.  If any of them are invalid (Nulls), then it is deamed to have 
00125  * a limb in the image. 
00126  *  
00127  * Note that this check is only valid if the determination of the geometry has 
00128  * been performed.  So care should be used as to when this check is made. 
00129  * 
00130  * 
00131  * @return bool  True if one of the corner latitude coordinates is NULL.
00132  */
00133 bool BandGeometry::hasLimb() const {
00134    BandPropertiesListConstIter b;
00135    for ( b = _gBandList.begin() ; b != _gBandList.end() ; ++b ) {
00136      if ( IsSpecial(b->upperLeftLatitude) ) return (true);
00137      if ( IsSpecial(b->upperRightLatitude) ) return (true);
00138      if ( IsSpecial(b->lowerRightLatitude) ) return (true);
00139      if ( IsSpecial(b->lowerLeftLatitude) ) return (true);
00140    }
00141    // All outer geometry points are defined
00142    return (false);
00143 }
00144 
00145 
00146 void BandGeometry::destruct() {
00147   // Ensure this can be applied for reentrant operations
00148   _gBandList.clear();
00149    for_each(_polys.begin(), _polys.end(), DeleteObject());
00150    delete _combined;
00151    _combined = 0;
00152    _radius = 1.0;
00153 }
00154 
00155 void BandGeometry::collect(Camera &camera, Cube &cube, bool doGeometry, 
00156                            bool doPolygon) { 
00157   destruct();
00158 
00159   _nLines  = cube.Lines();
00160   _nSamps  = cube.Samples();
00161   _nBands  = cube.Bands();
00162 
00163   //  Compute average planetary radius in meters.  This is used as a fallback
00164   //  to compute surface area if no geoemetry has a center intersect point.
00165   double radii[3];
00166   camera.Radii(radii);
00167   _radius = (radii[0] + radii[1] + radii[2]) / 3.0 * 1000.0;
00168 
00169   double cLine = _nLines;
00170   double cSamp = _nSamps;
00171   double centerLine = cLine / 2.0;
00172   double centerSamp = cSamp / 2.0;
00173 
00174   // Check to determine if geometry is band independant
00175   _isBandIndependent = camera.IsBandIndependent();
00176   _hasCenterGeom = false;
00177   int nbands = (_isBandIndependent ? 1 : _nBands);
00178   for ( int band = 0 ; band < nbands ; band++ ) {
00179     //  Compute band geometry properties
00180     GProperties g;
00181     g.lines = _nLines;
00182     g.samples = _nSamps;
00183     g.bands = _nBands;
00184     g.band = band + 1;
00185     camera.SetBand(band+1);
00186     g.realBand = cube.PhysicalBand(band+1);
00187 
00188 
00189     g.target = camera.Target();
00190 
00191     iTime t1(camera.CacheStartTime());
00192     g.startTime = t1.UTC();
00193     iTime t2(camera.CacheEndTime());
00194     g.endTime = t2.UTC();
00195 
00196     g.centerLine = centerLine;
00197     g.centerSamp = centerSamp;
00198 
00199     // Now compute elements for the center pixel
00200     if (camera.SetImage(centerSamp,centerLine)) {
00201       _hasCenterGeom = true;
00202       g.centerLatitude  = camera.UniversalLatitude();
00203       g.centerLongitude = camera.UniversalLongitude();
00204       g.radius = camera.LocalRadius();
00205 
00206       g.rightAscension = camera.RightAscension();
00207       g.declination    = camera.Declination();
00208 
00209       g.sampRes = camera.SampleResolution();
00210       g.lineRes = camera.LineResolution();
00211 
00212       g.solarLongitude = camera.SolarLongitude();
00213       g.northAzimuth = camera.NorthAzimuth();
00214       g.offNader = camera.OffNadirAngle();
00215       g.subSolarAzimuth = camera.SunAzimuth();
00216       g.subSpacecraftAzimuth = camera.SpacecraftAzimuth();
00217       g.localSolartime = camera.LocalSolarTime();
00218       g.targetCenterDistance = camera.TargetCenterDistance();
00219       g.slantDistance = camera.SlantDistance();
00220 
00221       camera.SubSolarPoint(g.subSolarLatitude,g.subSolarLongitude);
00222       g.subSolarGroundAzimuth = camera.GroundAzimuth(g.centerLatitude, 
00223                                                      g.centerLongitude,
00224                                                      g.subSolarLatitude,
00225                                                      g.subSolarLongitude);
00226       camera.SubSpacecraftPoint(g.subSpacecraftLatitude,g.subSpacecraftLongitude);
00227       g.subSpacecraftGroundAzimuth = camera.GroundAzimuth(g.centerLatitude, 
00228                                                           g.centerLongitude,
00229                                                           g.subSpacecraftLatitude, 
00230                                                           g.subSpacecraftLongitude);
00231 
00232 
00233         //  solve for the parallax and shadow stuff
00234       g.phase = camera.PhaseAngle();
00235       g.emi   = camera.EmissionAngle();
00236       g.inc   = camera.IncidenceAngle();
00237 
00238        //  Need some radian values
00239       if ( !IsSpecial(g.emi) && !IsSpecial(g.subSpacecraftAzimuth) ) {
00240         double emi_r = DegToRad(g.emi);
00241         g.parallaxx = RadToDeg(-tan(emi_r)*cos(DegToRad(g.subSpacecraftAzimuth)));
00242         g.parallaxy = RadToDeg(tan(emi_r)*sin(DegToRad(g.subSpacecraftAzimuth))); }
00243 
00244       if ( !IsSpecial(g.inc) && !IsSpecial(g.subSolarAzimuth) ) {
00245         double inc_r = DegToRad(g.inc);
00246         g.shadowx = RadToDeg(-tan(inc_r)*cos(DegToRad(g.subSolarAzimuth)));
00247         g.shadowy = RadToDeg(tan(inc_r)*sin(DegToRad(g.subSolarAzimuth)));
00248       }
00249     }
00250     //  OK...now get corner pixel geometry.  NOTE this resets image
00251     //  pixel location from center!!!
00252     if ( camera.SetImage(1.0, 1.0) ) {
00253       g.upperLeftLongitude = camera.UniversalLongitude();
00254       g.upperLeftLatitude =  camera.UniversalLatitude();
00255     }
00256 
00257     if ( camera.SetImage(1.0, cLine) ) {
00258       g.lowerLeftLongitude = camera.UniversalLongitude();
00259       g.lowerLeftLatitude =  camera.UniversalLatitude();
00260     }
00261 
00262     if ( camera.SetImage(cSamp, cLine) ) {
00263       g.lowerRightLongitude = camera.UniversalLongitude();
00264       g.lowerRightLatitude =  camera.UniversalLatitude();
00265     }
00266 
00267     if ( camera.SetImage(cSamp, 1.0) ) {
00268       g.upperRightLongitude = camera.UniversalLongitude();
00269       g.upperRightLatitude =  camera.UniversalLatitude();
00270     }
00271 
00272     double minRes = camera.LowestImageResolution();
00273     double maxRes = camera.HighestImageResolution();
00274     if ( !(IsSpecial(minRes) || IsSpecial(maxRes)) ) {
00275       g.grRes = (minRes+maxRes)/2.0;
00276     }
00277 
00278     Pvl camMap;
00279     camera.BasicMapping(camMap);
00280     _mapping = camMap;
00281 
00282     // Test for interesting intersections
00283     if (camera.IntersectsLongitudeDomain(camMap)) g.hasLongitudeBoundary = true;
00284     camera.SetBand(band+1);
00285     if (camera.SetUniversalGround(90.0, 0.0)) {
00286       if ( isPointValid(camera.Sample(), camera.Line(), &camera) ) {
00287         g.hasNorthPole = true;
00288       }
00289     }
00290     if (camera.SetUniversalGround(-90.0, 0.0)) {
00291       if ( isPointValid(camera.Sample(), camera.Line(), &camera) ) {
00292         g.hasSouthPole = true;
00293       }
00294     }
00295 
00296     if ( doPolygon ) {
00297       // Now compute the the image polygon
00298       ImagePolygon poly;
00299       poly.Incidence(_maxIncidence);
00300       poly.Emission(_maxEmission);
00301       poly.EllipsoidLimb(true);  // Allow disabling of shape model for limbs
00302       poly.Create(cube,_pixinc,_pixinc,1,1,0,0,band+1);
00303       geos::geom::MultiPolygon *multiP = poly.Polys();
00304       _polys.push_back(multiP->clone());
00305       if (_combined == 0) {
00306         _combined = multiP->clone();
00307       }
00308       else {
00309         //  Construct composite (union) polygon
00310         geos::geom::Geometry *old(_combined);
00311         _combined = old->Union(multiP);
00312         delete old;
00313       }
00314   
00315       // multiP is freed by ImagePolygon object
00316       _mapping = getProjGeometry(camera, multiP, g);
00317     }
00318 
00319     // Save off this band geometry property
00320     _gBandList.push_back(g);
00321   }
00322 
00323   //  Compute the remainder of the summary bands since some of the operations
00324   //  need the camera model
00325   _summary = getGeometrySummary();
00326   if ( (size() != 1) && (doPolygon)) {     
00327     geos::geom::MultiPolygon *multiP = makeMultiPolygon(_combined);
00328     _mapping = getProjGeometry(camera, multiP, _summary);
00329     delete multiP;
00330   }
00331 
00332   return;
00333 }
00334 
00335 
00336 void BandGeometry::generateGeometryKeys(PvlObject &pband) {
00337   if ( size() <= 0 ) {
00338     std::string mess = "No Band geometry available!";
00339     iException::Message(iException::Programmer, mess, _FILEINFO_);
00340   }
00341 
00342   GProperties g = getGeometrySummary();
00343 
00344 //geometry keywords for band output
00345   pband += PvlKeyword("BandsUsed", size());
00346   pband += PvlKeyword("ReferenceBand", g.band);
00347   pband += PvlKeyword("OriginalBand", g.realBand);
00348 
00349   pband += PvlKeyword("Target", g.target);
00350 
00351   pband += PvlKeyword("StartTime",g.startTime);
00352   pband += PvlKeyword("EndTime",g.endTime);
00353 
00354   pband += ValidateKey("CenterLine",g.centerLine);
00355   pband += ValidateKey("CenterSample",g.centerSamp);
00356   pband += ValidateKey("CenterLatitude",g.centerLatitude);
00357   pband += ValidateKey("CenterLongitude",g.centerLongitude);
00358   pband += ValidateKey("CenterRadius",g.radius);
00359 
00360   pband += ValidateKey("RightAscension",g.rightAscension);
00361   pband += ValidateKey("Declination",g.declination);
00362 
00363   pband += ValidateKey("UpperLeftLongitude",g.upperLeftLongitude);
00364   pband += ValidateKey("UpperLeftLatitude",g.upperLeftLatitude);
00365   pband += ValidateKey("LowerLeftLongitude",g.lowerLeftLongitude);
00366   pband += ValidateKey("LowerLeftLatitude",g.lowerLeftLatitude);
00367   pband += ValidateKey("LowerRightLongitude",g.lowerRightLongitude);
00368   pband += ValidateKey("LowerRightLatitude",g.lowerRightLatitude);
00369   pband += ValidateKey("UpperRightLongitude",g.upperRightLongitude);
00370   pband += ValidateKey("UpperRightLatitude",g.upperRightLatitude);
00371 
00372   pband += ValidateKey("PhaseAngle",g.phase);
00373   pband += ValidateKey("EmissionAngle",g.emi);
00374   pband += ValidateKey("IncidenceAngle",g.inc);
00375 
00376   pband += ValidateKey("NorthAzimuth",g.northAzimuth);
00377   pband += ValidateKey("OffNadir",g.offNader);
00378   pband += ValidateKey("SolarLongitude",g.solarLongitude);
00379   pband += ValidateKey("LocalTime",g.localSolartime);
00380   pband += ValidateKey("TargetCenterDistance",g.targetCenterDistance);
00381   pband += ValidateKey("SlantDistance",g.slantDistance);
00382 
00383   double aveRes(Null);
00384   if (!IsSpecial(g.sampRes) && !IsSpecial(g.lineRes)) {
00385     aveRes = (g.sampRes + g.lineRes) / 2.0;
00386   }
00387 
00388   pband += ValidateKey("SampleResolution",g.sampRes);
00389   pband += ValidateKey("LineResolution",g.lineRes);
00390   pband += ValidateKey("PixelResolution",aveRes);
00391   pband += ValidateKey("MeanGroundResolution",g.grRes);
00392 
00393   pband += ValidateKey("SubSolarAzimuth",g.subSolarAzimuth);
00394   pband += ValidateKey("SubSolarGroundAzimuth",g.subSolarGroundAzimuth);
00395   pband += ValidateKey("SubSolarLatitude", g.subSolarLatitude);
00396   pband += ValidateKey("SubSolarLongitude",g.subSolarLongitude);
00397 
00398   pband += ValidateKey("SubSpacecraftAzimuth", g.subSpacecraftAzimuth);
00399   pband += ValidateKey("SubSpacecraftGroundAzimuth", g.subSpacecraftGroundAzimuth);
00400   pband += ValidateKey("SubSpacecraftLatitude",g.subSpacecraftLatitude);
00401   pband += ValidateKey("SubSpacecraftLongitude",g.subSpacecraftLongitude);
00402 
00403   pband += ValidateKey("ParallaxX",g.parallaxx);
00404   pband += ValidateKey("ParallaxY",g.parallaxy);
00405 
00406   pband += ValidateKey("ShadowX",g.shadowx);
00407   pband += ValidateKey("ShadowY",g.shadowy);
00408 
00409   //  Determine if image crosses Longitude domain
00410   if ( g.hasLongitudeBoundary ) {
00411     pband += PvlKeyword("HasLongitudeBoundary","TRUE");
00412   }
00413   else {
00414     pband += PvlKeyword("HasLongitudeBoundary","FALSE");
00415   }
00416 
00417   //  Add test for North pole in image
00418   if (g.hasNorthPole) {
00419     pband += PvlKeyword("HasNorthPole", "TRUE");
00420   }
00421   else {
00422     pband += PvlKeyword("HasNorthPole", "FALSE");
00423   }
00424 
00425   //  Add test for South pole in image
00426   if (g.hasSouthPole) {
00427     pband += PvlKeyword("HasSouthPole", "TRUE");
00428   }
00429   else {
00430     pband += PvlKeyword("HasSouthPole", "FALSE");
00431   }
00432 
00433   return;
00434 }
00435 
00436 BandGeometry::GProperties BandGeometry::getGeometrySummary() const {
00437   if ( _isBandIndependent  || (size() == 1)) {
00438      return (_gBandList[0]);
00439   }
00440 
00441   //  Get the centroid point of the union polygon
00442   double plon(Null), plat(Null);
00443   if ( _combined != 0 ) {
00444     geos::geom::Point *center = _combined->getCentroid();
00445     plon = center->getX();
00446     plat = center->getY();
00447     delete center;
00448   }
00449 
00450   GProperties bestBand;
00451   double centerDistance(DBL_MAX);
00452 
00453   GProperties corners;
00454   double ulDist(DBL_MIN), urDist(DBL_MIN), 
00455          lrDist(DBL_MIN), llDist(DBL_MIN);
00456 
00457   double radius = getRadius();
00458 
00459   BandPropertiesListConstIter b;
00460   for ( b = _gBandList.begin() ; b != _gBandList.end() ; ++b ) {
00461     double thisDist;
00462 
00463     // Ensure the center latitude/logitude is defined (typically occurs when
00464     // no polygon data is available).  This scheme uses the first one defined.
00465     if ( IsSpecial(plat) || IsSpecial(plon) ) {
00466       plat = b->centerLatitude;
00467       plon = b->centerLongitude;
00468     }
00469 
00470     // Now check all data
00471     bool isCloser = isDistShorter(centerDistance, plat, plon,
00472                                   b->centerLatitude,b->centerLongitude,
00473                                   radius, thisDist) ;
00474     if (isCloser) {
00475         bestBand = *b;
00476         centerDistance = thisDist;
00477       }
00478 
00479     //  Do upper left and right corners
00480     isCloser = isDistShorter(ulDist, plat, plon,
00481                              b->upperLeftLatitude, b->upperLeftLongitude,
00482                              radius, thisDist);
00483     if ( !isCloser ) {
00484       corners.upperLeftLatitude = b->upperLeftLatitude;
00485       corners.upperLeftLongitude = b->upperLeftLongitude;
00486       ulDist = thisDist;
00487     }
00488 
00489     isCloser = isDistShorter(urDist, plat, plon,
00490                              b->upperRightLatitude, b->upperRightLongitude,
00491                              radius, thisDist);
00492     if ( !isCloser ) {
00493       corners.upperRightLatitude = b->upperRightLatitude;
00494       corners.upperRightLongitude = b->upperRightLongitude;
00495       urDist = thisDist;
00496     }
00497 
00498    //  Do lower left and right corners
00499     isCloser = isDistShorter(llDist, plat, plon,
00500                              b->lowerLeftLatitude, b->lowerLeftLongitude,
00501                              radius, thisDist);
00502     if ( !isCloser ) {
00503       corners.lowerLeftLatitude = b->lowerLeftLatitude;
00504       corners.lowerLeftLongitude = b->lowerLeftLongitude;
00505       llDist = thisDist;
00506     }
00507 
00508     isCloser = isDistShorter(lrDist, plat, plon,
00509                              b->lowerRightLatitude, b->lowerRightLongitude,
00510                              radius, thisDist);
00511     if ( !isCloser ) {
00512       corners.lowerRightLatitude = b->lowerRightLatitude;
00513       corners.lowerRightLongitude = b->lowerRightLongitude;
00514       lrDist = thisDist;
00515     }
00516   }
00517 
00518   // Add the corners to the returning property
00519   bestBand.upperLeftLatitude = corners.upperLeftLatitude;
00520   bestBand.upperLeftLongitude = corners.upperLeftLongitude;
00521   bestBand.upperRightLatitude = corners.upperRightLatitude;
00522   bestBand.upperRightLongitude = corners.upperRightLongitude;
00523   bestBand.lowerLeftLatitude = corners.lowerLeftLatitude;
00524   bestBand.lowerLeftLongitude = corners.lowerLeftLongitude;
00525   bestBand.lowerRightLatitude = corners.lowerRightLatitude;
00526   bestBand.lowerRightLongitude = corners.lowerRightLongitude;
00527   return (bestBand);
00528 }
00529 
00530 
00531 Pvl BandGeometry::getProjGeometry(Camera &camera,  
00532                                    geos::geom::MultiPolygon *footprint,
00533                                    GProperties &g) {
00534 
00535 #if defined(DEBUG)
00536   std::ofstream fp("footprint.gml");
00537   fp << PolygonTools::ToGML(footprint, "Footprint");
00538   fp.close();
00539 #endif
00540   // Get basic projection information.  Assumes a Sinusoidal projection with
00541   // East 360 longitude domain and planetocentric laitudes.
00542   Pvl sinuMap;
00543   camera.BasicMapping(sinuMap);
00544   PvlGroup &mapping = sinuMap.FindGroup("Mapping");
00545 
00546   double clon = g.centerLongitude;
00547   double minLon = (double) mapping["MinimumLongitude"];
00548   double maxLon = (double) mapping["MaximumLongitude"];
00549   if ( IsSpecial(clon) ) clon = (minLon + maxLon)/2.0;
00550 
00551   //  Make adjustments for center projection type/ranges.
00552   //  To be consistant with other implementations, do not
00553   //  convert poles to 180 domain.  
00554   geos::geom::MultiPolygon *poly180(0), *poly(footprint);
00555   if ( g.hasLongitudeBoundary ) {
00556     if ( !(g.hasNorthPole || g.hasSouthPole) ) {
00557       // Convert the mapping group contents to 180 Longitude domain
00558       PvlKeyword &ldkey = mapping["LongitudeDomain"];
00559       ldkey.SetValue("180");
00560 
00561       PvlKeyword &minkey = mapping["MinimumLongitude"];
00562       PvlKeyword &maxkey = mapping["MaximumLongitude"];
00563       minkey.SetValue("-180.0");
00564       maxkey.SetValue("180.0");
00565 
00566       // Compute new ranges
00567       double minLat180, maxLat180, minLon180, maxLon180;
00568       camera.GroundRange(minLat180, maxLat180, minLon180, maxLon180, sinuMap);
00569       minkey.SetValue(ToString(minLon180));
00570       maxkey.SetValue(ToString(maxLon180));
00571       clon = (minLon180 + maxLon180) / 2.0;
00572 
00573       // Convert the polygon to 180 domain
00574       poly = poly180 = PolygonTools::To180(footprint);
00575 #if defined(DEBUG)
00576   std::ofstream p180("poly180.gml");
00577   p180 << PolygonTools::ToGML(poly180, "180Domain");
00578   p180.close();
00579 #endif
00580 
00581     }
00582   }
00583 
00584   mapping += PvlKeyword("CenterLongitude", clon);
00585 
00586   Projection *sinu = ProjectionFactory::Create(sinuMap, true);
00587   geos::geom::MultiPolygon *sPoly = PolygonTools::LatLonToXY(*poly, sinu);
00588 #if defined(DEBUG)
00589   std::ofstream ll("sinuprojxy.gml");
00590   ll << PolygonTools::ToGML(sPoly, "SinuProjectedXY");
00591   ll.close();
00592 #endif
00593   geos::geom::Point *center = sPoly->getCentroid();
00594 
00595   sinu->SetCoordinate(center->getX(), center->getY());
00596   g.centroidLongitude = Projection::To360Domain(sinu->UniversalLongitude());
00597   g.centroidLatitude  = sinu->UniversalLatitude();
00598   g.surfaceArea = sPoly->getArea() / (1000.0 * 1000.0);
00599   delete center;
00600   delete sPoly;
00601   delete sinu;
00602   delete poly180;
00603 
00604   if (camera.SetUniversalGround(g.centroidLatitude, g.centroidLongitude)) {
00605     g.centroidLine = camera.Line();
00606     g.centroidSample = camera.Sample();
00607     g.centroidRadius = camera.LocalRadius();
00608   }
00609 
00610   return (sinuMap);
00611 }
00612 
00613 void BandGeometry::generatePolygonKeys(PvlObject &pband) {
00614   if ( size() <= 0 ) {
00615     std::string mess = "No Band geometry available!";
00616     iException::Message(iException::Programmer, mess, _FILEINFO_);
00617   }
00618 
00619    // Compute surface area - already done in collection phase
00620   double radius = getRadius();
00621   double globalCoverage(Null);
00622   if ( !IsSpecial(radius) ) {
00623     double globalArea = 4.0 * pi_c() * (radius * radius) / (1000.0*1000.0);
00624     globalCoverage = _summary.surfaceArea / globalArea * 100.0;
00625     globalCoverage = SetRound(globalCoverage, 6);
00626   }
00627 
00628   pband += ValidateKey("CentroidLine",_summary.centroidLine);
00629   pband += ValidateKey("CentroidSample",_summary.centroidSample);
00630   pband += ValidateKey("CentroidLatitude",_summary.centroidLatitude);
00631   pband += ValidateKey("CentroidLongitude",_summary.centroidLongitude);
00632   pband += ValidateKey("CentroidRadius",_summary.centroidRadius, "meters");
00633   pband += ValidateKey("SurfaceArea",_summary.surfaceArea,"km^2");
00634   pband += ValidateKey("GlobalCoverage",globalCoverage,"percent");
00635   if ( _combined != 0 ) {
00636     pband += PvlKeyword("PixelIncrement", _pixinc);
00637     if ( _combined->getGeometryTypeId() != geos::geom::GEOS_MULTIPOLYGON ) {
00638       geos::geom::MultiPolygon *geom = makeMultiPolygon(_combined);
00639       pband += PvlKeyword("GisFootprint", geom->toString());
00640       delete geom;
00641     }
00642     else {
00643       pband += PvlKeyword("GisFootprint", _combined->toString());
00644     }
00645   }
00646   else {
00647     pband += PvlKeyword("GisFootprint", Null);
00648   }
00649 
00650   // Add the mapping group used to project polygon
00651   pband.AddGroup(_mapping.FindGroup("Mapping"));
00652   return;
00653 }
00654 
00655 double BandGeometry::getRadius() const {
00656   Statistics polyRadius, centRadius;
00657   BandPropertiesListConstIter b;
00658   for ( b = _gBandList.begin() ; b != _gBandList.end() ; ++b ) {
00659     polyRadius.AddData(b->centroidRadius);
00660     centRadius.AddData(b->radius);
00661   }
00662   double radius = polyRadius.Average();
00663   if ( IsSpecial(radius) ) radius = centRadius.Average();
00664   if ( IsSpecial(radius) ) radius = _radius;
00665   return (radius);
00666 }
00667 
00668 double BandGeometry::getPixelResolution() const {
00669   Statistics groundRes, pixelRes;
00670    BandPropertiesListConstIter b;
00671    for ( b = _gBandList.begin() ; b != _gBandList.end() ; ++b ) {
00672      pixelRes.AddData(b->sampRes);
00673      pixelRes.AddData(b->lineRes);
00674      groundRes.AddData(b->grRes);
00675    }
00676 
00677    double res = groundRes.Average();
00678    if ( IsSpecial(res) ) res = pixelRes.Average();
00679    return (res);
00680 }
00681 
00682 double BandGeometry::getPixelsPerDegree(double pixres, 
00683                                         double radius) const {
00684   double circumference = 2.0  * pi_c() * radius;
00685   double metersPerDegree = circumference / 360.0;
00686   double pixelsPerDegree = metersPerDegree / pixres;
00687   return (pixelsPerDegree);
00688 }
00689 
00690 
00691 bool BandGeometry::isDistShorter(double bestDist, double lat1, double lon1, 
00692                                  double lat2, double lon2, double radius, 
00693                                  double &thisDist) const {
00694   if ( IsSpecial(lat1) ) return (false);
00695   if ( IsSpecial(lon1) ) return (false);
00696   if ( IsSpecial(lat2) ) return (false);
00697   if ( IsSpecial(lon2) ) return (false);
00698   if ( IsSpecial(radius) ) return (false);
00699 
00700   thisDist = Camera::Distance(lat1, lon1, lat2, lon2, radius);
00701   return (thisDist < bestDist);
00702 }
00703 
00704 geos::geom::MultiPolygon *BandGeometry::makeMultiPolygon(
00705                                            geos::geom::Geometry *g) const {
00706   vector<geos::geom::Geometry *> polys;
00707   polys.push_back(g);
00708   const geos::geom::GeometryFactory *gfactory = geos::geom::GeometryFactory::getDefaultInstance();
00709   return (gfactory->createMultiPolygon(polys));
00710 }
00711 
00712 
00713 } // namespace Isis