|
Isis 3.0 Object Programmers' Reference |
Home |
00001 00023 #include <cfloat> 00024 #include <cmath> 00025 #include "Camera.h" 00026 #include "Projection.h" 00027 #include "Constants.h" 00028 #include "CameraDetectorMap.h" 00029 #include "CameraFocalPlaneMap.h" 00030 #include "CameraDistortionMap.h" 00031 #include "CameraGroundMap.h" 00032 #include "CameraSkyMap.h" 00033 #include "ProjectionFactory.h" 00034 #include "NaifStatus.h" 00035 00036 using namespace std; 00037 namespace Isis { 00043 Camera::Camera (Isis::Pvl &lab) : Isis::Sensor (lab) { 00044 // Get the image size which can be different than the alpha cube size 00045 Isis::PvlGroup &dims = lab.FindObject("IsisCube") 00046 .FindObject("Core") 00047 .FindGroup("Dimensions"); 00048 p_lines = dims["Lines"]; 00049 p_samples = dims["Samples"]; 00050 p_bands = dims["Bands"]; 00051 00052 SetGeometricTilingHint(); 00053 00054 // Get the AlphaCube information 00055 p_alphaCube = new Isis::AlphaCube(lab); 00056 00057 // Get the projection group if it exists 00058 if (lab.FindObject("IsisCube").HasGroup("Mapping")) { 00059 p_projection = ProjectionFactory::CreateFromCube(lab); 00060 } 00061 else { 00062 p_projection = NULL; 00063 } 00064 p_ignoreProjection = false; 00065 00066 // Initialize stuff 00067 p_focalLength = 0.0; 00068 p_pixelPitch = 1.0; 00069 p_referenceBand = 0; 00070 p_childBand = 1; 00071 00072 p_distortionMap = NULL; 00073 p_focalPlaneMap = NULL; 00074 p_detectorMap = NULL; 00075 p_groundMap = NULL; 00076 p_skyMap = NULL; 00077 00078 // See if we have a reference band 00079 Isis::PvlGroup &inst = lab.FindObject("IsisCube").FindGroup("Instrument"); 00080 if (inst.HasKeyword("ReferenceBand")) { 00081 p_referenceBand = inst["ReferenceBand"]; 00082 } 00083 00084 p_groundRangeComputed = false; 00085 p_raDecRangeComputed = false; 00086 p_pointComputed = false; 00087 } 00088 00090 Camera::~Camera () { 00091 if (p_projection) { 00092 delete p_projection; 00093 p_projection = NULL; 00094 } 00095 00096 if(p_alphaCube) { 00097 delete p_alphaCube; 00098 p_alphaCube = NULL; 00099 } 00100 00101 if(p_distortionMap) { 00102 delete p_distortionMap; 00103 p_distortionMap = NULL; 00104 } 00105 00106 if(p_focalPlaneMap) { 00107 delete p_focalPlaneMap; 00108 p_focalPlaneMap = NULL; 00109 } 00110 00111 if(p_detectorMap) { 00112 delete p_detectorMap; 00113 p_detectorMap = NULL; 00114 } 00115 00116 if(p_groundMap) { 00117 delete p_groundMap; 00118 p_groundMap = NULL; 00119 } 00120 00121 if(p_skyMap) { 00122 delete p_skyMap; 00123 p_skyMap = NULL; 00124 } 00125 } 00126 00137 bool Camera::SetImage (const double sample, const double line) { 00138 p_childSample = sample; 00139 p_childLine = line; 00140 p_pointComputed = true; 00141 00142 // Case of no map projection 00143 if (p_projection == NULL || p_ignoreProjection) { 00144 // Convert to parent coordinate (remove crop, pad, shrink, enlarge) 00145 double parentSample = p_alphaCube->AlphaSample(sample); 00146 double parentLine = p_alphaCube->AlphaLine(line); 00147 // Convert from parent to detector 00148 if (p_detectorMap->SetParent(parentSample,parentLine)) { 00149 double detectorSample = p_detectorMap->DetectorSample(); 00150 double detectorLine = p_detectorMap->DetectorLine(); 00151 // Now Convert from detector to distorted focal plane 00152 if (p_focalPlaneMap->SetDetector(detectorSample,detectorLine)) { 00153 double focalPlaneX = p_focalPlaneMap->FocalPlaneX(); 00154 double focalPlaneY = p_focalPlaneMap->FocalPlaneY(); 00155 // Remove optical distortion 00156 if (p_distortionMap->SetFocalPlane(focalPlaneX,focalPlaneY)) { 00157 // Map to the ground 00158 double x = p_distortionMap->UndistortedFocalPlaneX(); 00159 double y = p_distortionMap->UndistortedFocalPlaneY(); 00160 double z = p_distortionMap->UndistortedFocalPlaneZ(); 00161 p_hasIntersection = p_groundMap->SetFocalPlane(x,y,z); 00162 return p_hasIntersection; 00163 } 00164 } 00165 } 00166 } 00167 00168 // The projection is a sky map 00169 else if (p_projection->IsSky()) { 00170 if (p_projection->SetWorld(sample,line)) { 00171 if (SetRightAscensionDeclination(p_projection->Longitude(), 00172 p_projection->UniversalLatitude())) { 00173 p_childSample = sample; 00174 p_childLine = line; 00175 00176 return HasSurfaceIntersection(); 00177 } 00178 } 00179 } 00180 00181 // We have map projected camera model 00182 else { 00183 if (p_projection->SetWorld(sample,line)) { 00184 if (SetUniversalGround(p_projection->UniversalLatitude(), 00185 p_projection->UniversalLongitude())) { 00186 p_childSample = sample; 00187 p_childLine = line; 00188 00189 p_hasIntersection = true; 00190 return p_hasIntersection; 00191 } 00192 } 00193 } 00194 00195 // failure 00196 p_hasIntersection = false; 00197 return p_hasIntersection; 00198 } 00199 00209 bool Camera::SetUniversalGround (const double latitude, const double longitude) { 00210 // Convert lat/lon to undistorted focal plane x/y 00211 if (p_groundMap->SetGround(latitude,longitude)) { 00212 return RawFocalPlanetoImage(); 00213 } 00214 00215 p_hasIntersection = false; 00216 return p_hasIntersection; 00217 } 00218 00219 00220 00228 bool Camera::RawFocalPlanetoImage () { 00229 double ux = p_groundMap->FocalPlaneX(); 00230 double uy = p_groundMap->FocalPlaneY(); 00231 // Convert undistorted x/y to distorted x/y 00232 if (p_distortionMap->SetUndistortedFocalPlane(ux,uy)) { 00233 double focalPlaneX = p_distortionMap->FocalPlaneX(); 00234 double focalPlaneY = p_distortionMap->FocalPlaneY(); 00235 // Convert distorted x/y to detector position 00236 if (p_focalPlaneMap->SetFocalPlane(focalPlaneX,focalPlaneY)) { 00237 double detectorSample = p_focalPlaneMap->DetectorSample(); 00238 double detectorLine = p_focalPlaneMap->DetectorLine(); 00239 // Convert detector to parent position 00240 if (p_detectorMap->SetDetector(detectorSample,detectorLine)) { 00241 double parentSample = p_detectorMap->ParentSample(); 00242 double parentLine = p_detectorMap->ParentLine(); 00243 p_pointComputed = true; 00244 00245 if (p_projection == NULL || p_ignoreProjection) { 00246 p_childSample = p_alphaCube->BetaSample(parentSample); 00247 p_childLine = p_alphaCube->BetaLine(parentLine); 00248 p_hasIntersection = true; 00249 return p_hasIntersection; 00250 } 00251 else if (p_projection->IsSky()) { 00252 if (p_projection->SetGround(Declination(),RightAscension())) { 00253 p_childSample = p_projection->WorldX(); 00254 p_childLine = p_projection->WorldY(); 00255 p_hasIntersection = true; 00256 return p_hasIntersection; 00257 } 00258 } 00259 else { 00260 if (p_projection->SetUniversalGround(UniversalLatitude(), UniversalLongitude())) { 00261 p_childSample = p_projection->WorldX(); 00262 p_childLine = p_projection->WorldY(); 00263 p_hasIntersection = true; 00264 return p_hasIntersection; 00265 } 00266 } 00267 } 00268 } 00269 } 00270 00271 p_hasIntersection = false; 00272 return p_hasIntersection; 00273 } 00274 00275 00276 00289 bool Camera::SetUniversalGround (const double latitude, const double longitude, 00290 const double radius) { 00291 // Convert lat/lon to undistorted focal plane x/y 00292 if (p_groundMap->SetGround(latitude,longitude,radius)) { 00293 return RawFocalPlanetoImage(); // sets p_hasIntersection 00294 } 00295 00296 p_hasIntersection = false; 00297 return p_hasIntersection; 00298 } 00299 00305 double Camera::DetectorResolution () { 00306 if (HasSurfaceIntersection()) { 00307 double sB[3]; 00308 InstrumentPosition(sB); 00309 double pB[3]; 00310 Coordinate(pB); 00311 double a = sB[0] - pB[0]; 00312 double b = sB[1] - pB[1]; 00313 double c = sB[2] - pB[2]; 00314 double dist = sqrt(a*a + b*b + c*c) * 1000.0; 00315 return dist / (p_focalLength / p_pixelPitch); 00316 } 00317 return -1.0; 00318 } 00319 00325 double Camera::SampleResolution () { 00326 return DetectorResolution() * p_detectorMap->SampleScaleFactor(); 00327 } 00328 00334 double Camera::LineResolution () { 00335 return DetectorResolution() * p_detectorMap->LineScaleFactor(); 00336 } 00337 00343 double Camera::PixelResolution () { 00344 double lineRes = LineResolution(); 00345 double sampRes = SampleResolution(); 00346 if (lineRes < 0.0) return -1.0; 00347 if (sampRes < 0.0) return -1.0; 00348 return (lineRes + sampRes) / 2.0; 00349 } 00350 00356 double Camera::LowestImageResolution () { 00357 GroundRangeResolution(); 00358 return p_maxres; 00359 } 00360 00366 double Camera::HighestImageResolution () { 00367 GroundRangeResolution(); 00368 return p_minres; 00369 } 00370 00374 void Camera::GroundRangeResolution () { 00375 // Have we already done this 00376 if (p_groundRangeComputed) return; 00377 p_groundRangeComputed = true; 00378 00379 bool computed = p_pointComputed; 00380 double originalSample = Sample(); 00381 double originalLine = Line(); 00382 int originalBand = Band(); 00383 00384 // Initializations 00385 p_minlat = DBL_MAX; 00386 p_minlon = DBL_MAX; 00387 p_minlon180 = DBL_MAX; 00388 p_maxlat = -DBL_MAX; 00389 p_maxlon = -DBL_MAX; 00390 p_maxlon180 = -DBL_MAX; 00391 p_minres = DBL_MAX; 00392 p_maxres = -DBL_MAX; 00393 00394 // See if we have band dependence and loop for the appropriate number of bands 00395 int eband = p_bands; 00396 if (IsBandIndependent()) eband = 1; 00397 for (int band=1; band<=eband; band++) { 00398 SetBand(band); 00399 00400 // Loop for each line testing the left and right sides of the image 00401 for (int line=1; line<=p_lines+1; line++) { 00402 // Look for the first good lat/lon on the left edge of the image 00403 // If it is the first or last line then test the whole line 00404 int samp; 00405 for (samp=1; samp<=p_samples+1; samp++) { 00406 00407 if (SetImage((double)samp-0.5,(double)line-0.5)) { 00408 double lat = UniversalLatitude(); 00409 double lon = UniversalLongitude(); 00410 if (lat < p_minlat) p_minlat = lat; 00411 if (lat > p_maxlat) p_maxlat = lat; 00412 if (lon < p_minlon) p_minlon = lon; 00413 if (lon > p_maxlon) p_maxlon = lon; 00414 00415 if (lon > 180.0) lon -= 360.0; 00416 if (lon < p_minlon180) p_minlon180 = lon; 00417 if (lon > p_maxlon180) p_maxlon180 = lon; 00418 00419 double res = PixelResolution(); 00420 if (res > 0.0) { 00421 if (res < p_minres) p_minres = res; 00422 if (res > p_maxres) p_maxres = res; 00423 } 00424 if ((line != 1) && (line != p_lines+1)) break; 00425 } 00426 } 00427 00428 //We've already checked the first and last lines. 00429 if(line == 1) continue; 00430 if(line == p_lines+1) continue; 00431 00432 // Look for the first good lat/lon on the right edge of the image 00433 if (samp < p_samples+1) { 00434 for (samp=p_samples+1; samp>=1; samp--) { 00435 if (SetImage((double)samp-0.5,(double)line-0.5)) { 00436 double lat = UniversalLatitude(); 00437 double lon = UniversalLongitude(); 00438 if (lat < p_minlat) p_minlat = lat; 00439 if (lat > p_maxlat) p_maxlat = lat; 00440 if (lon < p_minlon) p_minlon = lon; 00441 if (lon > p_maxlon) p_maxlon = lon; 00442 00443 if (lon > 180.0) lon -= 360.0; 00444 if (lon < p_minlon180) p_minlon180 = lon; 00445 if (lon > p_maxlon180) p_maxlon180 = lon; 00446 00447 double res = PixelResolution(); 00448 if (res > 0.0) { 00449 if (res < p_minres) p_minres = res; 00450 if (res > p_maxres) p_maxres = res; 00451 } 00452 break; 00453 } 00454 } 00455 } 00456 } 00457 00458 // Test at the sub-spacecraft point to see if we have a 00459 // better resolution 00460 double lat,lon; 00461 SubSpacecraftPoint(lat,lon); 00462 if (SetUniversalGround(lat,lon)) { 00463 if (Sample() >= 0.5 && Line() >= 0.5 && 00464 Sample() <= p_samples + 0.5 && Line() <= p_lines + 0.5) { 00465 double res = PixelResolution(); 00466 if (res > 0.0) { 00467 if (res < p_minres) p_minres = res; 00468 if (res > p_maxres) p_maxres = res; 00469 } 00470 } 00471 } 00472 00473 // Special test for ground range to see if either pole is in the image 00474 if (SetUniversalGround(90.0,0.0)) { 00475 if (Sample() >= 0.5 && Line() >= 0.5 && 00476 Sample() <= p_samples + 0.5 && Line() <= p_lines + 0.5) { 00477 p_maxlat = 90.0; 00478 p_minlon = 0.0; 00479 p_maxlon = 360.0; 00480 p_minlon180 = -180.0; 00481 p_maxlon180 = 180.0; 00482 } 00483 } 00484 00485 if (SetUniversalGround(-90.0,0.0)) { 00486 if (Sample() >= 0.5 && Line() >= 0.5 && 00487 Sample() <= p_samples + 0.5 && Line() <= p_lines + 0.5) { 00488 p_minlat = -90.0; 00489 p_minlon = 0.0; 00490 p_maxlon = 360.0; 00491 p_minlon180 = -180.0; 00492 p_maxlon180 = 180.0; 00493 } 00494 } 00495 00496 // Another special test for ground range as we could have the 00497 // 0-360 seam running right through the image so 00498 // test it as well (the increment may not be fine enough !!!) 00499 for (double lat=p_minlat; lat<=p_maxlat; lat+=(p_maxlat-p_minlat)/10.0) { 00500 if (SetUniversalGround(lat,0.0)) { 00501 if (Sample() >= 0.5 && Line() >= 0.5 && 00502 Sample() <= p_samples + 0.5 && Line() <= p_lines + 0.5) { 00503 p_minlon = 0.0; 00504 p_maxlon = 360.0; 00505 break; 00506 } 00507 } 00508 } 00509 00510 // Another special test for ground range as we could have the 00511 // -180-180 seam running right through the image so 00512 // test it as well (the increment may not be fine enough !!!) 00513 for (double lat=p_minlat; lat<=p_maxlat; lat+=(p_maxlat-p_minlat)/10.0) { 00514 if (SetUniversalGround(lat,180.0)) { 00515 if (Sample() >= 0.5 && Line() >= 0.5 && 00516 Sample() <= p_samples + 0.5 && Line() <= p_lines + 0.5) { 00517 p_minlon180 = -180.0; 00518 p_maxlon180 = 180.0; 00519 break; 00520 } 00521 } 00522 } 00523 } 00524 00525 SetBand(originalBand); 00526 00527 if(computed) { 00528 SetImage(originalSample, originalLine); 00529 } 00530 else { 00531 p_pointComputed = false; 00532 } 00533 00534 // Checks for invalide lat/lon ranges 00535 if ( p_minlon == DBL_MAX || p_minlat == DBL_MAX || p_maxlon == -DBL_MAX || p_maxlat == -DBL_MAX ) { 00536 string message = "Camera missed planet or SPICE data off."; 00537 throw iException::Message( iException::Camera, message, _FILEINFO_ ); 00538 } 00539 } 00540 00549 bool Camera::IntersectsLongitudeDomain (Isis::Pvl &pvl) { 00550 double minlat, minlon, maxlat, maxlon; 00551 return GroundRange(minlat,maxlat,minlon,maxlon,pvl); 00552 } 00553 00570 bool Camera::GroundRange (double &minlat, double &maxlat, 00571 double &minlon, double &maxlon, 00572 Isis::Pvl &pvl) { 00573 // Compute the ground range and resolution 00574 GroundRangeResolution(); 00575 00576 // Get the default radii 00577 double radii[3]; 00578 Radii(radii); 00579 double a = radii[0] * 1000.0; 00580 double b = radii[2] * 1000.0; 00581 00582 // See if the PVL overrides the radii 00583 Isis::PvlGroup map = pvl.FindGroup("Mapping",Isis::Pvl::Traverse); 00584 if (map.HasKeyword("EquatorialRadius")) a = map["EquatorialRadius"]; 00585 if (map.HasKeyword("PolarRadius")) b = map["PolarRadius"]; 00586 00587 // Convert to planetographic if necessary 00588 minlat = p_minlat; 00589 maxlat = p_maxlat; 00590 if (map.HasKeyword("LatitudeType")) { 00591 Isis::iString latType = (string) map["LatitudeType"]; 00592 if (latType.UpCase() == "PLANETOGRAPHIC") { 00593 if (abs(minlat) < 90.0) { // So tan doesn't fail 00594 minlat *= Isis::PI / 180.0; 00595 minlat = atan (tan(minlat) * (a / b) * (a / b)); 00596 minlat *= 180.0 / Isis::PI; 00597 } 00598 00599 if (abs(maxlat) < 90.0) { // So tan doesn't fail 00600 maxlat *= Isis::PI / 180.0; 00601 maxlat = atan (tan(maxlat) * (a / b) * (a / b)); 00602 maxlat *= 180.0 / Isis::PI; 00603 } 00604 } 00605 } 00606 00607 // Assume 0 to 360 domain but change it if necessary 00608 minlon = p_minlon; 00609 maxlon = p_maxlon; 00610 bool domain360 = true; 00611 if (map.HasKeyword("LongitudeDomain")) { 00612 Isis::iString lonDomain = (string) map["LongitudeDomain"]; 00613 if (lonDomain.UpCase() == "180") { 00614 minlon = p_minlon180; 00615 maxlon = p_maxlon180; 00616 domain360 = false; 00617 } 00618 } 00619 00620 // Convert to the proper longitude direction 00621 if (map.HasKeyword("LongitudeDirection")) { 00622 Isis::iString lonDirection = (string) map["LongitudeDirection"]; 00623 if (lonDirection.UpCase() == "POSITIVEWEST") { 00624 double swap = minlon; 00625 minlon = -maxlon; 00626 maxlon = -swap; 00627 } 00628 } 00629 00630 // Convert to the proper longitude domain 00631 if (domain360) { 00632 while (minlon < 0.0) { 00633 minlon += 360.0; 00634 maxlon += 360.0; 00635 } 00636 while (minlon > 360.0) { 00637 minlon -= 360.0; 00638 maxlon -= 360.0; 00639 } 00640 } 00641 else { 00642 while (minlon < -180.0) { 00643 minlon += 360.0; 00644 maxlon += 360.0; 00645 } 00646 while (minlon > 180.0) { 00647 minlon -= 360.0; 00648 maxlon -= 360.0; 00649 } 00650 } 00651 // Now return if it crosses the longitude domain boundary 00652 if ((maxlon - minlon) > 359.0) return true; 00653 return false; 00654 } 00655 00661 void Camera::BasicMapping (Isis::Pvl &pvl) { 00662 Isis::PvlGroup map("Mapping"); 00663 map += Isis::PvlKeyword("TargetName",Target()); 00664 map += Isis::PvlKeyword("EquatorialRadius",p_radii[0]*1000.0,"<meters>"); 00665 map += Isis::PvlKeyword("PolarRadius",p_radii[2]*1000.0,"<meters>"); 00666 map += Isis::PvlKeyword("LatitudeType","Planetocentric"); 00667 map += Isis::PvlKeyword("LongitudeDirection","PositiveEast"); 00668 map += Isis::PvlKeyword("LongitudeDomain","360"); 00669 00670 GroundRangeResolution(); 00671 map += Isis::PvlKeyword("MinimumLatitude",p_minlat); 00672 map += Isis::PvlKeyword("MaximumLatitude",p_maxlat); 00673 map += Isis::PvlKeyword("MinimumLongitude",p_minlon); 00674 map += Isis::PvlKeyword("MaximumLongitude",p_maxlon); 00675 map += Isis::PvlKeyword("PixelResolution",p_minres); 00676 00677 map += Isis::PvlKeyword("ProjectionName","Sinusoidal"); 00678 pvl.AddGroup(map); 00679 } 00680 00682 void Camera::SetFocalLength () { 00683 int code = NaifIkCode(); 00684 string key = "INS" + Isis::iString(code) + "_FOCAL_LENGTH"; 00685 SetFocalLength(Isis::Spice::GetDouble(key)); 00686 } 00687 00689 void Camera::SetPixelPitch () { 00690 int code = NaifIkCode(); 00691 string key = "INS" + Isis::iString(code) + "_PIXEL_PITCH"; 00692 SetPixelPitch(Isis::Spice::GetDouble(key)); 00693 } 00694 00705 bool Camera::SetRightAscensionDeclination(const double ra, const double dec) { 00706 if (p_skyMap->SetSky(ra,dec)) { 00707 double ux = p_skyMap->FocalPlaneX(); 00708 double uy = p_skyMap->FocalPlaneY(); 00709 if (p_distortionMap->SetUndistortedFocalPlane(ux,uy)) { 00710 double dx = p_distortionMap->FocalPlaneX(); 00711 double dy = p_distortionMap->FocalPlaneY(); 00712 if (p_focalPlaneMap->SetFocalPlane(dx,dy)) { 00713 double detectorSamp = p_focalPlaneMap->DetectorSample(); 00714 double detectorLine = p_focalPlaneMap->DetectorLine(); 00715 if (p_detectorMap->SetDetector(detectorSamp,detectorLine)) { 00716 double parentSample = p_detectorMap->ParentSample(); 00717 double parentLine = p_detectorMap->ParentLine(); 00718 p_pointComputed = true; 00719 00720 if (p_projection == NULL || p_ignoreProjection) { 00721 p_childSample = p_alphaCube->BetaSample(parentSample); 00722 p_childLine = p_alphaCube->BetaLine(parentLine); 00723 return true; 00724 } 00725 else if (p_projection->IsSky()) { 00726 if (p_projection->SetGround(dec,ra)) { 00727 p_childSample = p_projection->WorldX(); 00728 p_childLine = p_projection->WorldY(); 00729 return true; 00730 } 00731 } 00732 else if (p_hasIntersection) { 00733 if (p_projection->SetUniversalGround(UniversalLatitude(), 00734 UniversalLongitude())) { 00735 p_childSample = p_projection->WorldX(); 00736 p_childLine = p_projection->WorldY(); 00737 return true; 00738 } 00739 } 00740 } 00741 } 00742 } 00743 } 00744 00745 return false; 00746 } 00747 00762 bool Camera::RaDecRange (double &minra, double &maxra, 00763 double &mindec, double &maxdec) { 00764 if(p_projection != NULL && !p_projection->IsSky()) { 00765 iString msg = "Camera::RaDecRange can not calculate a right ascension, declination range"; 00766 msg += " for projected images which are not projected to sky"; 00767 throw iException::Message(iException::Programmer, msg, _FILEINFO_); 00768 } 00769 00770 bool computed = p_pointComputed; 00771 double originalSample = Sample(); 00772 double originalLine = Line(); 00773 int originalBand = Band(); 00774 00775 // Have we already done this 00776 if (!p_raDecRangeComputed) { 00777 p_raDecRangeComputed = true; 00778 00779 // Initializations 00780 p_mindec = DBL_MAX; 00781 p_minra = DBL_MAX; 00782 p_minra180 = DBL_MAX; 00783 p_maxdec = -DBL_MAX; 00784 p_maxra = -DBL_MAX; 00785 p_maxra180 = -DBL_MAX; 00786 00787 // See if we have band dependence and loop for the appropriate number of bands 00788 int eband = p_bands; 00789 if (IsBandIndependent()) eband = 1; 00790 for (int band=1; band<=eband; band++) { 00791 this->SetBand(band); 00792 00793 for (int line=1; line<=p_lines; line++) { 00794 // Test left, top, and bottom sides 00795 int samp; 00796 for (samp=1; samp<=p_samples; samp++) { 00797 SetImage((double)samp,(double)line); 00798 double ra = RightAscension(); 00799 double dec = Declination(); 00800 if (ra < p_minra) p_minra = ra; 00801 if (ra > p_maxra) p_maxra = ra; 00802 if (dec < p_mindec) p_mindec = dec; 00803 if (dec > p_maxdec) p_maxdec = dec; 00804 00805 if (ra > 180.0) ra -= 360.0; 00806 if (ra < p_minra180) p_minra180 = ra; 00807 if (ra > p_maxra180) p_maxra180 = ra; 00808 00809 if ((line != 1) && (line != p_lines)) break; 00810 } 00811 00812 // Test right side 00813 if (samp < p_samples) { 00814 for (samp=p_samples; samp>=1; samp--) { 00815 SetImage((double)samp,(double)line); 00816 double ra = RightAscension(); 00817 double dec = Declination(); 00818 if (ra < p_minra) p_minra = ra; 00819 if (ra > p_maxra) p_maxra = ra; 00820 if (dec < p_mindec) p_mindec = dec; 00821 if (dec > p_maxdec) p_maxdec = dec; 00822 00823 if (ra > 180.0) ra -= 360.0; 00824 if (ra < p_minra180) p_minra180 = ra; 00825 if (ra > p_maxra180) p_maxra180 = ra; 00826 00827 break; 00828 } 00829 } 00830 } 00831 00832 // Special test for ground range to see if either pole is in the image 00833 if (SetRightAscensionDeclination(0.0,90.0)) { 00834 if ((Line() >= 0.5) && (Line() <= p_lines) && 00835 (Sample() >= 0.5) && (Sample() <= p_samples)) { 00836 p_maxdec = 90.0; 00837 p_minra = 0.0; 00838 p_maxra = 360.0; 00839 p_minra180 = -180.0; 00840 p_maxra180 = 180.0; 00841 } 00842 } 00843 00844 if (SetRightAscensionDeclination(0.0,-90.0)) { 00845 if ((Line() >= 0.5) && (Line() <= p_lines) && 00846 (Sample() >= 0.5) && (Sample() <= p_samples)) { 00847 p_mindec = -90.0; 00848 p_minra = 0.0; 00849 p_maxra = 360.0; 00850 p_minra180 = -180.0; 00851 p_maxra180 = 180.0; 00852 } 00853 } 00854 00855 // Another special test for ground range as we could have the 00856 // 0-360 seam running right through the image so 00857 // test it as well (the increment may not be fine enough !!!) 00858 for (double dec=p_mindec; dec<=p_maxdec; dec+=(p_maxdec-p_mindec)/10.0) { 00859 if (SetRightAscensionDeclination(0.0,dec)) { 00860 if ((Line() >= 0.5) && (Line() <= p_lines) && 00861 (Sample() >= 0.5) && (Sample() <= p_samples)) { 00862 p_minra = 0.0; 00863 p_maxra = 360.0; 00864 break; 00865 } 00866 } 00867 } 00868 00869 // Another special test for ground range as we could have the 00870 // 0-360 seam running right through the image so 00871 // test it as well (the increment may not be fine enough !!!) 00872 for (double dec=p_mindec; dec<=p_maxdec; dec+=(p_maxdec-p_mindec)/10.0) { 00873 if (SetRightAscensionDeclination(180.0,dec)) { 00874 if ((Line() >= 0.5) && (Line() <= p_lines) && 00875 (Sample() >= 0.5) && (Sample() <= p_samples)) { 00876 p_minra180 = -180.0; 00877 p_maxra180 = 180.0; 00878 break; 00879 } 00880 } 00881 } 00882 } 00883 } 00884 00885 minra = p_minra; 00886 maxra = p_maxra; 00887 mindec = p_mindec; 00888 maxdec = p_maxdec; 00889 00890 SetBand(originalBand); 00891 00892 if(computed) { 00893 SetImage(originalSample, originalLine); 00894 } 00895 else { 00896 p_pointComputed = false; 00897 } 00898 00899 return true; 00900 } 00901 00902 00909 double Camera::RaDecResolution () { 00910 if(p_projection != NULL && !p_projection->IsSky()) { 00911 iString msg = "Camera::RaDecResolution can not calculate a right ascension, declination resolution"; 00912 msg += " for projected images which are not projected to sky"; 00913 throw iException::Message(iException::Programmer, msg, _FILEINFO_); 00914 } 00915 00916 bool computed = p_pointComputed; 00917 double originalSample = Sample(); 00918 double originalLine = Line(); 00919 int originalBand = Band(); 00920 00921 SetImage(1.0,1.0); 00922 double ra1 = RightAscension(); 00923 double dec1 = Declination(); 00924 00925 SetImage(1.0,(double)p_lines); 00926 double ra2 = RightAscension(); 00927 double dec2 = Declination(); 00928 00929 double dist = (ra1 - ra2) * (ra1 - ra2) + (dec1 - dec2) * (dec1 - dec2); 00930 dist = sqrt(dist); 00931 double lineRes = dist / (p_lines - 1); 00932 00933 SetImage((double)p_samples,1.0); 00934 ra2 = RightAscension(); 00935 dec2 = Declination(); 00936 00937 dist = (ra1 - ra2) * (ra1 - ra2) + (dec1 - dec2) * (dec1 - dec2); 00938 dist = sqrt(dist); 00939 double sampRes = dist / (p_samples - 1); 00940 00941 SetBand(originalBand); 00942 00943 if(computed) { 00944 SetImage(originalSample, originalLine); 00945 } 00946 else { 00947 p_pointComputed = false; 00948 } 00949 00950 return (sampRes < lineRes) ? sampRes : lineRes; 00951 } 00952 00958 double Camera::NorthAzimuth () { 00959 return ComputeAzimuth(p_radii[2],90.0,0.0); 00960 } 00961 00969 double Camera::SunAzimuth () { 00970 double lat,lon; 00971 SubSolarPoint (lat,lon); 00972 return ComputeAzimuth(LocalRadius()/1000.0,lat,lon); 00973 } 00974 00982 double Camera::SpacecraftAzimuth () { 00983 double lat,lon; 00984 SubSpacecraftPoint (lat,lon); 00985 return ComputeAzimuth(LocalRadius()/1000.0,lat,lon); 00986 } 00987 01002 double Camera::ComputeAzimuth(const double radius, 01003 const double lat, const double lon) { 01004 if (!HasSurfaceIntersection()) return -1.0; 01005 01006 bool computed = p_pointComputed; 01007 double originalSample = Sample(); 01008 double originalLine = Line(); 01009 01010 NaifStatus::CheckErrors(); 01011 01012 // Convert the point to x/y/z in body-fixed 01013 SpiceDouble pB[3]; 01014 latrec_c(radius,lon*Isis::PI/180.0,lat*Isis::PI/180.0,pB); 01015 01016 // Get the origin point 01017 SpiceDouble oB[3]; 01018 Coordinate(oB); 01019 01020 // Get the difference unit vector 01021 SpiceDouble poB[3],upoB[3]; 01022 vsub_c(pB,oB,poB); 01023 vhat_c(poB,upoB); 01024 01025 // Scale to be within a pixel (km) 01026 double scale = (PixelResolution() / 1000.0) / 2.0; 01027 SpiceDouble supoB[3]; 01028 vscl_c(scale,upoB,supoB); 01029 01030 // Compute the new point in body fixed. This point will be within 01031 // a pixel of the origin but in the same direction as the 01032 // requested lat/lon 01033 SpiceDouble nB[3]; 01034 vadd_c(oB,supoB,nB); 01035 01036 // However, it could be below the surface of the planet so bring it 01037 // back 01038 vhat_c(nB,nB); 01039 vscl_c(LocalRadius()/1000.0,nB,nB); 01040 01041 // Get the origin image coordinate 01042 double osample = Sample(); 01043 double oline = Line(); 01044 01045 // Convert the point to a lat/lon and find out its image coordinate 01046 double nrad,nlon,nlat; 01047 reclat_c(nB,&nrad,&nlon,&nlat); 01048 SetUniversalGround(nlat*180.0/Isis::PI,nlon*180.0/Isis::PI); 01049 double nsample = Sample(); 01050 double nline = Line(); 01051 01052 // TODO: Write PushState and PopState method to ensure the 01053 // internals of the class are set based on SetImage or SetGround 01054 SetImage(osample,oline); 01055 01056 double deltaSample = nsample - osample; 01057 double deltaLine = nline - oline; 01058 01059 // Compute the angle 01060 double azimuth = 0.0; 01061 if (deltaSample != 0.0 || deltaLine != 0.0) { 01062 azimuth = atan2(deltaLine,deltaSample); 01063 azimuth *= 180.0 / Isis::PI; 01064 } 01065 if (azimuth < 0.0) azimuth += 360.0; 01066 if (azimuth > 360.0) azimuth -= 360.0; 01067 01068 NaifStatus::CheckErrors(); 01069 01070 if(computed) { 01071 SetImage(originalSample, originalLine); 01072 } 01073 else { 01074 p_pointComputed = false; 01075 } 01076 01077 return azimuth; 01078 } 01079 01085 double Camera::OffNadirAngle () { 01086 NaifStatus::CheckErrors(); 01087 01088 // Get the xyz coordinates for the spacecraft and point we are interested in 01089 double coord[3],spCoord[3]; 01090 Coordinate(coord); 01091 InstrumentPosition(spCoord); 01092 01093 // Get the angle between the 2 points and convert to degrees 01094 double a = vsep_c(coord,spCoord) * 180.0 / Isis::PI; 01095 double b = 180.0 - EmissionAngle(); 01096 01097 // The three angles in a triangle must add up to 180 degrees 01098 double c = 180.0 - (a + b); 01099 01100 NaifStatus::CheckErrors(); 01101 01102 return c; 01103 } 01104 01120 double Camera::GroundAzimuth(double glat, double glon, 01121 double slat, double slon) { 01122 double a = (90.0 - slat) * Isis::PI / 180.0; 01123 double b = (90.0 - glat) * Isis::PI / 180.0; 01124 double c = (glon - slon) * Isis::PI / 180.0; 01125 double absum = 0.5 * (a + b); 01126 double cosabsum = cos(absum); 01127 double sinabsum = sin(absum); 01128 double abdif = 0.5 * (a - b); 01129 double cosabdif = cos(abdif); 01130 double sinabdif = sin(abdif); 01131 double cotc = 1.0 / (tan(0.5 * c)); 01132 double tanabsum = cotc * cosabdif / cosabsum; 01133 double tanabdif = cotc * sinabdif / sinabsum; 01134 double ABsum = atan(tanabsum); 01135 double ABdif = atan(tanabdif); 01136 double A = ABsum + ABdif; 01137 double B = ABsum - ABdif; 01138 double sinc = sin(c) * sin(a) / sin(A); 01139 c = asin(sinc); 01140 double azimuthA = A * 180.0 / Isis::PI + 90.0; 01141 double azimuthB = 90.0 - B * 180.0 / Isis::PI; 01142 double azimuth = 0.0; 01143 if ((glat > slat && glon > slon) || 01144 (glat < slat && glon > slon)) { 01145 if (azimuthA < azimuthB) { 01146 azimuth = 270.0 - azimuthA; 01147 } else { 01148 azimuth = 270.0 - azimuthB; 01149 } 01150 } else if ((glat < slat && glon < slon) || 01151 (glat > slat && glon < slon)) { 01152 if (azimuthA < azimuthB) { 01153 azimuth = 90.0 - azimuthA; 01154 } else { 01155 azimuth = 90.0 - azimuthB; 01156 } 01157 } 01158 return azimuth; 01159 } 01160 01174 double Camera::Distance(double lat1, double lon1, 01175 double lat2, double lon2, double radius) { 01176 // Convert lat/lon values to radians 01177 double latRad1 = lat1 * Isis::PI / 180.0; 01178 double latRad2 = lat2 * Isis::PI / 180.0; 01179 double lonRad1 = lon1 * Isis::PI / 180.0; 01180 double lonRad2 = lon2 * Isis::PI / 180.0; 01181 01182 double deltaLat = latRad2 - latRad1; 01183 double deltaLon = lonRad2 - lonRad1; 01184 double a = (sin(deltaLat/2) * sin(deltaLat/2)) + cos(latRad1) * 01185 cos(latRad2) * (sin(deltaLon/2) * sin(deltaLon/2)); 01186 double c = 2 * atan(sqrt(a) / sqrt(1-a)); 01187 double dist = radius * c; 01188 return dist; 01189 } 01190 01191 01198 void Camera::SetDistortionMap (CameraDistortionMap *map) { 01199 if(p_distortionMap) { 01200 delete p_distortionMap; 01201 } 01202 01203 p_distortionMap = map; 01204 }; 01205 01212 void Camera::SetFocalPlaneMap (CameraFocalPlaneMap *map) { 01213 if(p_focalPlaneMap) { 01214 delete p_focalPlaneMap; 01215 } 01216 01217 p_focalPlaneMap = map; 01218 }; 01219 01226 void Camera::SetDetectorMap (CameraDetectorMap *map) { 01227 if(p_detectorMap) { 01228 delete p_detectorMap; 01229 } 01230 01231 p_detectorMap = map; 01232 }; 01233 01240 void Camera::SetGroundMap (CameraGroundMap *map) { 01241 if(p_groundMap) { 01242 delete p_groundMap; 01243 } 01244 01245 p_groundMap = map; 01246 }; 01247 01253 void Camera::SetSkyMap (CameraSkyMap *map) { 01254 if(p_skyMap) { 01255 delete p_skyMap; 01256 } 01257 01258 p_skyMap = map; 01259 }; 01260 01269 void Camera::LoadCache(int cacheSize) { 01270 // We want to stay in unprojected space for this process 01271 bool projIgnored = p_ignoreProjection; 01272 p_ignoreProjection = true; 01273 01274 double etStart = 0.0, etEnd = 0.0; 01275 01276 for(int band = 1; band <= Bands(); band++) { 01277 SetBand(band); 01278 SetImage(0.5, 0.5); 01279 double etStartTmp = EphemerisTime(); 01280 SetImage(p_alphaCube->BetaSamples() + 0.5, p_alphaCube->BetaLines() + 0.5); 01281 double etEndTmp = EphemerisTime(); 01282 01283 if(band == 1) { 01284 etStart = min(etStartTmp, etEndTmp); 01285 etEnd = max(etStartTmp, etEndTmp); 01286 } 01287 01288 etStart = min(etStart, min(etStartTmp, etEndTmp)); 01289 etEnd = max(etEnd, max(etStartTmp, etEndTmp)); 01290 } 01291 01292 if(cacheSize <= 0) { 01293 // BetaLines() + 1 so we get at least 2 points for interpolation 01294 cacheSize = p_alphaCube->BetaLines() + 1; 01295 01296 if(etStart == etEnd) { 01297 cacheSize = 1; 01298 } 01299 } 01300 01301 if(etStart == -DBL_MAX || etEnd == -DBL_MAX) { 01302 string msg = "Unable to find time range for the spice kernels"; 01303 throw iException::Message(iException::Programmer, msg, _FILEINFO_); 01304 } 01305 01306 // Set a position in the image so that the PixelResolution can be calculated 01307 SetImage(p_alphaCube->BetaSamples()/2, p_alphaCube->BetaLines()/2); 01308 double tol = PixelResolution()/100.; //meters/pix/100. 01309 01310 if (tol < 0.) { 01311 // Alternative calculation of ground resolution of a pixel/100 01312 double altitudeMeters; 01313 if (IsSky()) { // Use the unit sphere as the target 01314 altitudeMeters = 1.0; 01315 } 01316 else { 01317 altitudeMeters = SpacecraftAltitude()*1000.; 01318 } 01319 tol = PixelPitch()*altitudeMeters/FocalLength()/100.; 01320 } 01321 01322 p_ignoreProjection = projIgnored; 01323 01324 Spice::CreateCache(etStart, etEnd, cacheSize, tol); 01325 01326 SetEphemerisTime(etStart); 01327 01328 // Reset to band 1 01329 SetBand(1); 01330 } 01331 01348 void Camera::SetGeometricTilingHint(int startSize, int endSize) { 01349 // verify the start size is a multiple of 2 greater than 2 01350 int powerOf2 = 2; 01351 01352 // No hint if 2's are passed in 01353 if(startSize == 2 && endSize == 2) { 01354 p_geometricTilingStartSize = 2; 01355 p_geometricTilingEndSize = 2; 01356 return; 01357 } 01358 01359 if(endSize > startSize) { 01360 iString message = "Camera::SetGeometricTilingHint End size must be smaller than the start size"; 01361 throw iException::Message(iException::Programmer, message, _FILEINFO_); 01362 } 01363 01364 if(startSize < 4) { 01365 iString message = "Camera::SetGeometricTilingHint Start size must be at least 4"; 01366 throw iException::Message(iException::Programmer, message, _FILEINFO_); 01367 } 01368 01369 bool foundEnd = false; 01370 while(powerOf2 > 0 && startSize != powerOf2) { 01371 if(powerOf2 == endSize) foundEnd = true; 01372 powerOf2 *= 2; 01373 } 01374 01375 // Didnt find a solution, the integer became negative first, must not be 01376 // a power of 2 01377 if(powerOf2 < 0) { 01378 iString message = "Camera::SetGeometricTilingHint Start size must be a power of 2"; 01379 throw iException::Message(iException::Programmer, message, _FILEINFO_); 01380 } 01381 01382 if(!foundEnd) { 01383 iString message = "Camera::SetGeometricTilingHint End size must be a power of 2 less than the start size, but greater than 2"; 01384 throw iException::Message(iException::Programmer, message, _FILEINFO_); 01385 } 01386 01387 p_geometricTilingStartSize = startSize; 01388 p_geometricTilingEndSize = endSize; 01389 } 01390 01398 void Camera::GetGeometricTilingHint(int &startSize, int &endSize) { 01399 startSize = p_geometricTilingStartSize; 01400 endSize = p_geometricTilingEndSize; 01401 } 01402 01403 01412 bool Camera::InCube() { 01413 if(Sample() < 0.5 || Line() < 0.5) { 01414 return false; 01415 } 01416 01417 if(Sample() > Samples() + 0.5 || Line() > Lines() + 0.5) { 01418 return false; 01419 } 01420 01421 return true; 01422 } 01423 } // end namespace isis