|
Isis 3.0 Application Source Code Reference |
Home |
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