From 9800a727848ccc6ca2a6895a751b48f948efd678 Mon Sep 17 00:00:00 2001
From: Jeannie Backer
Date: Mon, 29 Aug 2016 20:03:55 +0000
Subject: [PATCH] Updated from trunk.
git-svn-id: http://subversion.wr.usgs.gov/repos/prog/isis3/branches/ipce@7094 41f8697f-d340-4b68-9986-7bafba869bb8
---
isis/src/base/apps/campt/campt.cpp | 19 +-
isis/src/base/apps/campt/campt.xml | 89 +++--
isis/src/base/apps/camstats/camstats.cpp | 21 +-
isis/src/base/apps/camstats/camstats.xml | 30 +-
isis/src/base/apps/mosrange/mosrange.cpp | 87 ++++-
isis/src/base/apps/mosrange/mosrange.xml | 13 +-
isis/src/base/apps/phocube/phocube.cpp | 8 +
isis/src/base/apps/phocube/phocube.xml | 72 +++--
.../base/apps/phocube/tsts/allbands/Makefile | 1 +
.../src/base/objs/Application/Application.cpp | 7 +
isis/src/base/objs/Application/Application.h | 2 +
isis/src/base/objs/Camera/Camera.cpp | 305 ++++++++++++++----
isis/src/base/objs/Camera/Camera.h | 25 +-
isis/src/base/objs/Camera/Camera.truth | 4 +
isis/src/base/objs/Camera/unitTest.cpp | 11 +-
.../objs/CameraPointInfo/CameraPointInfo.cpp | 249 +++++++++-----
.../objs/CameraPointInfo/CameraPointInfo.h | 22 +-
.../CameraPointInfo/CameraPointInfo.truth | 8 +
.../CameraStatistics/CameraStatistics.cpp | 74 ++++-
.../objs/CameraStatistics/CameraStatistics.h | 50 ++-
.../CameraStatistics/CameraStatistics.truth | 18 ++
isis/src/base/objs/Gui/Gui.cpp | 3 +
isis/src/base/objs/Gui/Gui.h | 4 +-
isis/src/base/objs/ProcessByTile/unitTest.cpp | 10 +-
.../objs/RadarGroundMap/RadarGroundMap.cpp | 9 +-
.../base/objs/RadarGroundMap/RadarGroundMap.h | 4 +-
.../RadarSlantRangeMap/RadarSlantRangeMap.cpp | 91 +++++-
.../RadarSlantRangeMap/RadarSlantRangeMap.h | 8 +-
.../Chandrayaan1M3Camera.h | 2 +
.../Chandrayaan1M3Camera.truth | 7 +
.../objs/Chandrayaan1M3Camera/unitTest.cpp | 24 ++
isis/src/control/apps/cnettable/cnettable.cpp | 4 +
isis/src/control/apps/cnettable/cnettable.xml | 8 +-
.../docsys/Object/build/isisDoxyDefs.doxydef | 29 +-
.../Schemas/Application/application.xsd | 4 +
.../Application/documentation/index.html | 37 ++-
.../docsys/documents/Glossary/Glossary.xml | 108 ++++++-
.../Glossary/assets/carlini_craters.png | Bin 0 -> 288282 bytes
.../documents/Glossary/assets/dufayx.png | Bin 0 -> 285610 bytes
.../documents/Glossary/assets/nadir.png | Bin 0 -> 655481 bytes
.../documents/Glossary/assets/nadir40pct.png | Bin 0 -> 174503 bytes
.../documents/Glossary/assets/oblique.png | Bin 0 -> 294780 bytes
.../Glossary/assets/oblique40pct.png | Bin 0 -> 96043 bytes
isis/src/lro/objs/MiniRF/MiniRF.h | 2 +
isis/src/lro/objs/MiniRF/MiniRF.truth | 8 +
isis/src/lro/objs/MiniRF/unitTest.cpp | 68 +++-
.../mex/apps/hrsc2isis/tsts/phobos/Makefile | 6 +
isis/src/mro/apps/hicolormos/hicolormos.xml | 97 +++---
isis/version | 4 +-
49 files changed, 1292 insertions(+), 360 deletions(-)
create mode 100644 isis/src/docsys/documents/Glossary/assets/carlini_craters.png
create mode 100644 isis/src/docsys/documents/Glossary/assets/dufayx.png
create mode 100644 isis/src/docsys/documents/Glossary/assets/nadir.png
create mode 100644 isis/src/docsys/documents/Glossary/assets/nadir40pct.png
create mode 100644 isis/src/docsys/documents/Glossary/assets/oblique.png
create mode 100644 isis/src/docsys/documents/Glossary/assets/oblique40pct.png
create mode 100644 isis/src/mex/apps/hrsc2isis/tsts/phobos/Makefile
diff --git a/isis/src/base/apps/campt/campt.cpp b/isis/src/base/apps/campt/campt.cpp
index 2d46a550c5..a442733ba7 100644
--- a/isis/src/base/apps/campt/campt.cpp
+++ b/isis/src/base/apps/campt/campt.cpp
@@ -7,10 +7,14 @@
#include "Camera.h"
#include "CameraPointInfo.h"
#include "CSVReader.h"
+#include "Distance.h"
#include "IException.h"
#include "iTime.h"
+#include "Longitude.h"
#include "Progress.h"
+#include "PvlGroup.h"
#include "SpecialPixel.h"
+#include "TProjection.h"
using namespace std;
using namespace Isis;
@@ -21,17 +25,28 @@ QList getCameraPointInfo(const UserInterface &ui,
CameraPointInfo &campt);
void writePoints(const UserInterface &ui, QList camPoints);
+
+
+
void IsisMain() {
UserInterface &ui = Application::GetUserInterface();
// Setup our input cube
CameraPointInfo campt;
+
+ QString fileFormat = ui.GetString("FORMAT");
+ if(fileFormat=="PVL")
+ campt.SetCSVOutput(false);
+ else
+ campt.SetCSVOutput(true);
+
campt.SetCube(ui.GetFileName("FROM") + "+" + ui.GetInputAttribute("FROM").toString());
// Grab the provided points (coordinates)
QList< QPair > points = getPoints(ui, ui.WasEntered("COORDLIST"));
// Get the camera point info for coordiante
+
QList camPoints = getCameraPointInfo(ui, points, campt);
writePoints(ui, camPoints);
@@ -105,7 +120,7 @@ QList getCameraPointInfo(const UserInterface &ui,
// Depending on what type is selected, set values accordingly
for (int i = 0; i < points.size(); i++) {
-
+
QPair pt = points[i];
if (type == "GROUND") {
camPoint = campt.SetGround(pt.first, pt.second, allowOutside, usePointList);
@@ -209,6 +224,8 @@ void writePoints(const UserInterface &ui, QList camPoints) {
os << endl;
}
+
+
for (int i = 0; i < (*point).keywords(); i++) {
if ((*point)[i].size() == 3) {
os << (QString)(*point)[i][0] << ","
diff --git a/isis/src/base/apps/campt/campt.xml b/isis/src/base/apps/campt/campt.xml
index 87c9d167f8..78c4e27f53 100644
--- a/isis/src/base/apps/campt/campt.xml
+++ b/isis/src/base/apps/campt/campt.xml
@@ -1,6 +1,8 @@
-
+
Computes geometric and photometric information at a given pixel location
@@ -35,8 +37,8 @@
The following is a partial list of coordinates computed in the campt application:
- Geometric Information: Latitude, Longitude, Resolution
+ Geometric Information: Latitude, Longitude, Oblique Detector Resolution,
+ Line Resolution, Oblique Line Resolution
Photometric Information: Phase,
Emission, and PixelValue = 0.0607816
- RightAscension = 65.749350916052 <DEGREE>
- Declination = -18.390093214966 <DEGREE>
- PlanetocentricLatitude = 34.444196777763 <DEGREE>
- PlanetographicLatitude = 34.760399604837 <DEGREE>
- PositiveEastLongitude = 223.84999971299 <DEGREE>
- PositiveWestLongitude = 136.15000028701 <DEGREE>
- BodyFixedCoordinate = (-2015.9595225544, -1936.6155808127, 1917.2574858384) <KM>
- LocalRadius = 3389756.4767145 <M>
- SampleResolution = 536.05556350077 <M>
- LineResolution = 536.05556350077 <M>
-
+ RightAscension = 65.749350916052
+ Declination = -18.390093214966
+ PlanetocentricLatitude = 34.444196777763
+ PlanetographicLatitude = 34.760399604837
+ PositiveEastLongitude = 223.84999971299
+ PositiveWestLongitude = 136.15000028701
+ BodyFixedCoordinate = (-2015.9595225544, -1936.6155808127, 1917.2574858384) <km>
+ LocalRadius = 3389756.4767145 <m>
+ SampleResolution = 536.05556350077 <m/pixel>
+ LineResolution = 536.05556350077 <m/pixel>
+ ObliqueDetectorResolution = 151.26661909292 <m/pixel>
+ ObliquePixelResolution = 605.06647637166 <m/pixel>
+ ObliqueLineResolution = 605.06647637166 <m/pixel>
+ ObliqueSampleResolution = 605.06647637166 <m/pixel>
# Spacecraft Information
- SpacecraftPosition = (-2025.6211429076, -2130.1417975758, 2009.318879871) <KM>
- SpacecraftAzimuth = 0.006855593033889 <DEGREE>
- SlantDistance = 214.52515878961 <KM>
- TargetCenterDistance = 3560.6189705415 <KM>
- SubSpacecraftLatitude = 34.354896748841 <DEGREE>
- SubSpacecraftLongitude = 226.44072947174 <DEGREE>
- SpacecraftAltitude = 170.83335389965 <KM>
- OffNadirAngle = 36.149255932304 <DEGREE>
- SubSpacecraftGroundAzimuth = 91.64525294858 <DEGREE>
+ SpacecraftPosition = (-2025.6211429076, -2130.1417975758, 2009.318879871) <km>
+ SpacecraftAzimuth = 0.006855593033889
+ SlantDistance = 214.52515878961 <km>
+ TargetCenterDistance = 3560.6189705415 <km>
+ SubSpacecraftLatitude = 34.354896748841
+ SubSpacecraftLongitude = 226.44072947174
+ SpacecraftAltitude = 170.83335389965 <km>
+ OffNadirAngle = 36.149255932304
+ SubSpacecraftGroundAzimuth = 91.64525294858
# Sun Information
- SunPosition = (-177337948.13839, 112957442.69098, -33704752.205292) <KM>
- SubSolarAzimuth = 172.30460990873 <DEGREE>
+ SunPosition = (-177337948.13839, 112957442.69098, -33704752.205292) <km>
+ SubSolarAzimuth = 172.30460990873
SolarDistance = 1.4234246174889 <AU>
- SubSolarLatitude = -9.1071705738361 <DEGREE>
- SubSolarLongitude = 147.50443340123 <DEGREE>
- SubSolarGroundAzimuth = 254.69139701227 <DEGREE>
+ SubSolarLatitude = -9.1071705738361
+ SubSolarLongitude = 147.50443340123
+ SubSolarGroundAzimuth = 254.69139701227
# Illumination and Other
- Phase = 120.59515694473 <DEGREE>
- Incidence = 84.106289446623 <DEGREE>
- Emission = 38.288719431206 <DEGREE>
- NorthAzimuth = 261.46910874636 <DEGREE>
+ Phase = 120.59515694473
+ Incidence = 84.106289446623
+ Emission = 38.288719431206
+ NorthAzimuth = 261.46910874636
# Time
EphemerisTime = -69382819.160519 <seconds>
UTC = 1997-10-20T10:58:37.6570806
LocalSolarTime = 17.089704420784 <hour>
- SolarLongitude = 201.83159041209 <DEGREE>
+ SolarLongitude = 201.83159041209
Error = NULL
-
- # Look Direction Unit Vectors in Body Fixed, J2000, and Camera Coordinate Systems.
- LookDirectionBodyFixed = (0.95457395414683, 0.074906840825054,
- -0.28840515124058) <DEGREE>
- LookDirectionJ2000 = (0.5482662642052, -0.25280984110143,
- -0.797177074292) <DEGREE>
- LookDirectionCamera = (0.0040987946596217, -0.6021663586021,
- 0.79836011702128) <DEGREE>
End_Group
@@ -208,11 +205,11 @@ End_Group
Updated documentation. References #1449.
-
- Added units to many of the outputs of the PVL. Fixes #3979.
-
-
- Added spacecraft look direction unit vectors in Body Fixed, J200, and Camera Coordinate Systems. Fixes #4180.
+
+ Checked in new test data, and added support for changes made to the CameraPointInfo
+ and Camera classes that incorporate new estimates for Pixel/Line/Sample/Detetctor resolution
+ and now allow a developer to control the order in which fields are output in both PVL and
+ CSV format. References #476, #4100.
diff --git a/isis/src/base/apps/camstats/camstats.cpp b/isis/src/base/apps/camstats/camstats.cpp
index a95f41c04a..dbdb39781b 100644
--- a/isis/src/base/apps/camstats/camstats.cpp
+++ b/isis/src/base/apps/camstats/camstats.cpp
@@ -112,7 +112,21 @@ void IsisMain() {
"NorthAzimuthMinimum," <<
"NorthAzimuthMaximum," <<
"NorthAzimuthAverage," <<
- "NorthAzimuthStandardDeviation," << endl;
+ "NorthAzimuthStandardDeviation," <<
+ "ObliqueResolutionMinimum," <<
+ "ObliqueResolutionMaximum," <<
+ "ObliqueResolutionAverage," <<
+ "ObliqueResolutionStandardDeviation," <<
+ "ObliqueLineResolutionMinimum," <<
+ "ObliqueLineResolutionMaximum," <<
+ "ObliqueLineResolutionAverage," <<
+ "ObliqueLineResolutionStandardDeviation," <<
+ "ObliqueSampleResolutionMinimum," <<
+ "ObliqueSampleResolutionMaximum," <<
+ "ObliqueSampleResolutionAverage," <<
+ "ObliqueSampleResolutionStandardDeviation," << endl;
+
+
}
os << FileName(from).expanded() << ",";
//call the function to write out the values for each group
@@ -128,6 +142,9 @@ void IsisMain() {
writeFlat(os, camStats.getLocalSolarTimeStat());
writeFlat(os, camStats.getLocalRaduisStat());
writeFlat(os, camStats.getNorthAzimuthStat());
+ writeFlat(os,camStats.getObliqueResStat());
+ writeFlat(os,camStats.getObliqueLineResStat());
+ writeFlat(os,camStats.getObliqueSampleResStat());
os << endl;
}
}
@@ -137,7 +154,7 @@ void IsisMain() {
QString cam_name = "CameraStatistics";
//Creates new CameraStatistics Table
- TableField fname("Name", Isis::TableField::Text, 20);
+ TableField fname("Name", Isis::TableField::Text, 45);
TableField fmin("Minimum", Isis::TableField::Double);
TableField fmax("Maximum", Isis::TableField::Double);
TableField favg("Average", Isis::TableField::Double);
diff --git a/isis/src/base/apps/camstats/camstats.xml b/isis/src/base/apps/camstats/camstats.xml
index 0286991099..9cefe31595 100644
--- a/isis/src/base/apps/camstats/camstats.xml
+++ b/isis/src/base/apps/camstats/camstats.xml
@@ -1,6 +1,7 @@
-
+
Generates and outputs camera statistics for a cube in raw camera geometry
@@ -15,17 +16,20 @@
average, and standard deviation values. The output groups are listed below:
- - Latitude
- - Longitude
- - Sample Resolution
- - Line Resolution
- - Resolution
+ - Latitude
+ - Longitude
+ - Sample Resolution
+ - Line Resolution
+ - Pixel Resolution
+ - Oblique Line Resolution
+ - Oblique Sample Resolution
+ - Oblique Pixel Resolution
- Aspect Ratio
- - Phase Angle
- - Emission Angle
- - Incidence Angle
- - Local Solar Time
- - North Azimuth
+ - Phase Angle
+ - EmissionAngle
+ - Incidence Angle
+ - Local Solar Time
+ - North Azimuth
@@ -96,6 +100,10 @@
documentation to clarify the existence and functioning of a few quirks. Addresses redmine
ticket #175.
+
+ Added statistics for ObliqueLineResolution/ObliqueSampleResolution,
+ and Oblique Pixel Resolution. References #476, #4100.
+
diff --git a/isis/src/base/apps/mosrange/mosrange.cpp b/isis/src/base/apps/mosrange/mosrange.cpp
index 9e19a5c526..9364175dd1 100644
--- a/isis/src/base/apps/mosrange/mosrange.cpp
+++ b/isis/src/base/apps/mosrange/mosrange.cpp
@@ -97,6 +97,10 @@ void IsisMain() {
prog.CheckStatus();
Statistics scaleStat;
+
+
+ Statistics obliqueScaleStat;
+
Statistics longitudeStat;
Statistics latitudeStat;
Statistics equiRadStat;
@@ -147,15 +151,51 @@ void IsisMain() {
// Get resolution
double lowres = cam->LowestImageResolution();
double hires = cam->HighestImageResolution();
- scaleStat.AddData(&lowres, 1);
+
+
+ double lowObliqueRes = cam->LowestObliqueImageResolution();
+
+
+
+ double hiObliqueRes= cam->HighestObliqueImageResolution();
+
+
scaleStat.AddData(&hires, 1);
+ scaleStat.AddData(&lowres, 1);
+
+
+ obliqueScaleStat.AddData(&hiObliqueRes,1);
+ obliqueScaleStat.AddData(&lowObliqueRes,1);
+
double pixres = (lowres + hires) / 2.0;
+
+
+ //double obliquePixRes = (lowObliqueRes+hiObliqueRes)/2.0;
+
double scale = Scale(pixres, poleRad, eqRad);
+
+
+ //double obliqueScale = Scale(obliquePixRes,poleRad,eqRad);
+
+
mapgrp.addKeyword(PvlKeyword("PixelResolution", toString(pixres)), Pvl::Replace);
+
+
+ //mapgrp.addKeyword(PvlKeyword("ObliquePixelResolution", toString(obliquePixRes)),
+ // Pvl::Replace);
+
mapgrp.addKeyword(PvlKeyword("Scale", toString(scale), "pixels/degree"), Pvl::Replace);
- mapgrp += PvlKeyword("MinPixelResolution", toString(lowres), "meters");
- mapgrp += PvlKeyword("MaxPixelResolution", toString(hires), "meters");
+
+
+ //mapgrp.addKeyword(PvlKeyword("ObliqueScale", toString(obliqueScale), "pixels/degree"),
+ // Pvl::Replace);
+ mapgrp += PvlKeyword("MinPixelResolution", toString(lowres), "meters/pixel");
+ mapgrp += PvlKeyword("MaxPixelResolution", toString(hires), "meters/pixel");
+
+
+ mapgrp += PvlKeyword("MinObliquePixelResolution", toString(lowObliqueRes), "meters/pixel");
+ mapgrp += PvlKeyword("MaxObliquePixelResolution", toString(hiObliqueRes), "meters/pixel");
// Get the universal ground range
double minlat, maxlat, minlon, maxlon;
@@ -185,12 +225,17 @@ void IsisMain() {
// Construct the output mapping group with statistics
PvlGroup mapping("Mapping");
- double avgPixRes((scaleStat.Minimum() + scaleStat.Maximum()) / 2.0);
+ double avgPixRes( (scaleStat.Minimum() + scaleStat.Maximum() ) / 2.0);
+
+
+ //double avgObliquePixRes( (obliqueScaleStat.Minimum() + obliqueScaleStat.Maximum() ) / 2.0);
+
double avgLat((latitudeStat.Minimum() + latitudeStat.Maximum()) / 2.0);
double avgLon((longitudeStat.Minimum() + longitudeStat.Maximum()) / 2.0);
double avgEqRad((equiRadStat.Minimum() + equiRadStat.Maximum()) / 2.0);
double avgPoleRad((poleRadStat.Minimum() + poleRadStat.Maximum()) / 2.0);
double scale = Scale(avgPixRes, avgPoleRad, avgEqRad);
+ //double obliqueScale = Scale(avgObliquePixRes,avgPoleRad,avgEqRad);
mapping += PvlKeyword("ProjectionName", projection);
mapping += PvlKeyword("TargetName", target);
@@ -200,15 +245,37 @@ void IsisMain() {
mapping += PvlKeyword("LongitudeDirection", londir);
mapping += PvlKeyword("LongitudeDomain", londom);
mapping += PvlKeyword("PixelResolution", toString(SetRound(avgPixRes, digits)), "meters/pixel");
+
+
+ //mapping += PvlKeyword("ObliquePixelResolution", toString(SetRound(avgObliquePixRes, digits)),
+ // "meters/pixel");
+
+
mapping += PvlKeyword("Scale", toString(SetRound(scale, digits)), "pixels/degree");
- mapping += PvlKeyword("MinPixelResolution", toString(scaleStat.Minimum()), "meters");
- mapping += PvlKeyword("MaxPixelResolution", toString(scaleStat.Maximum()), "meters");
+
+
+ //mapping += PvlKeyword("ObliqueScale", toString(SetRound(obliqueScale, digits)), "pixels/degree");
+
+
+ mapping += PvlKeyword("MinPixelResolution", toString(scaleStat.Minimum()), "meters/pixel");
+ mapping += PvlKeyword("MaxPixelResolution", toString(scaleStat.Maximum()), "meters/pixel");
+
+
+ mapping += PvlKeyword("MinObliquePixelResolution", toString(obliqueScaleStat.Minimum()),
+ "meters/pixel");
+ mapping += PvlKeyword("MaxObliquePixelResolution", toString(obliqueScaleStat.Maximum()),
+ "meters/pixel");
+
mapping += PvlKeyword("CenterLongitude", toString(SetRound(avgLon, digits)));
mapping += PvlKeyword("CenterLatitude", toString(SetRound(avgLat, digits)));
- mapping += PvlKeyword("MinimumLatitude", toString(MAX(SetFloor(latitudeStat.Minimum(), digits), -90.0)));
- mapping += PvlKeyword("MaximumLatitude", toString(MIN(SetCeil(latitudeStat.Maximum(), digits), 90.0)));
- mapping += PvlKeyword("MinimumLongitude", toString(MAX(SetFloor(longitudeStat.Minimum(), digits), -180.0)));
- mapping += PvlKeyword("MaximumLongitude", toString(MIN(SetCeil(longitudeStat.Maximum(), digits), 360.0)));
+ mapping += PvlKeyword("MinimumLatitude", toString(MAX(SetFloor(latitudeStat.Minimum(),
+ digits), -90.0)));
+ mapping += PvlKeyword("MaximumLatitude", toString(MIN(SetCeil(latitudeStat.Maximum(),
+ digits), 90.0)));
+ mapping += PvlKeyword("MinimumLongitude", toString(MAX(SetFloor(longitudeStat.Minimum(),
+ digits), -180.0)));
+ mapping += PvlKeyword("MaximumLongitude", toString(MIN(SetCeil(longitudeStat.Maximum(),
+ digits), 360.0)));
PvlKeyword clat("PreciseCenterLongitude", toString(avgLon));
clat.addComment("Actual Parameters without precision applied");
diff --git a/isis/src/base/apps/mosrange/mosrange.xml b/isis/src/base/apps/mosrange/mosrange.xml
index 046a4adfc4..6d05637f2e 100644
--- a/isis/src/base/apps/mosrange/mosrange.xml
+++ b/isis/src/base/apps/mosrange/mosrange.xml
@@ -1,6 +1,8 @@
-
+
Compute the lat/lon range of a set camera images for mosaicking
@@ -10,7 +12,8 @@
This program computes and outputs the
latitude/longitude
range of a set of images in camera space, as well as the
- pixel resolution. It creates a cam2map ready map file with
+ pixel resolution and the
+ oblique pixel resolution.. It creates a cam2map ready map file with
the extents of the latitude/longitude ranges of the image set.
@@ -47,6 +50,7 @@ Group = Mapping
LongitudeDirection = PositiveEast
LongitudeDomain = 360
PixelResolution = 505.3668 <meters/pixel>
+ ObliquePixelResolution = 791.251 <meters/pixel>
Scale = 84.2676 <pixels/degree>
MinPixelResolution = 483.45317995544 <meters>
MaxPixelResolution = 527.28051834369 <meters>
@@ -106,6 +110,11 @@ End
Updated to use new Target class. References Mantis tickets #775 and #1114.
+
+ Updated to use upated Camera/CameraPointInfo classes which include improved approximations
+ to Pixel/Detector/Line/Sample resolutions, as well as providing the ability for developers
+ to order the fields in CSV/Pvl output. References #476"
+
diff --git a/isis/src/base/apps/phocube/phocube.cpp b/isis/src/base/apps/phocube/phocube.cpp
index 5a4e691f22..8d26d05d2f 100644
--- a/isis/src/base/apps/phocube/phocube.cpp
+++ b/isis/src/base/apps/phocube/phocube.cpp
@@ -34,6 +34,7 @@ bool pixelResolution;
bool lineResolution;
bool sampleResolution;
bool detectorResolution;
+bool obliqueDetectorResolution;
bool northAzimuth;
bool sunAzimuth;
bool spacecraftAzimuth;
@@ -119,6 +120,7 @@ void IsisMain() {
lineResolution = false;
sampleResolution = false;
detectorResolution = false;
+ obliqueDetectorResolution = false;
sunAzimuth = false;
spacecraftAzimuth = false;
offnadirAngle = false;
@@ -141,6 +143,7 @@ void IsisMain() {
if ((lineResolution = ui.GetBoolean("LINERESOLUTION"))) nbands++;
if ((sampleResolution = ui.GetBoolean("SAMPLERESOLUTION"))) nbands++;
if ((detectorResolution = ui.GetBoolean("DETECTORRESOLUTION"))) nbands++;
+ if ((obliqueDetectorResolution = ui.GetBoolean("OBLIQUEDETECTORRESOLUTION"))) nbands++;
if ((sunAzimuth = ui.GetBoolean("SUNAZIMUTH"))) nbands++;
if ((spacecraftAzimuth = ui.GetBoolean("SPACECRAFTAZIMUTH"))) nbands++;
if ((offnadirAngle = ui.GetBoolean("OFFNADIRANGLE"))) nbands++;
@@ -193,6 +196,7 @@ void IsisMain() {
if (lineResolution) name += "Line Resolution";
if (sampleResolution) name += "Sample Resolution";
if (detectorResolution) name += "Detector Resolution";
+ if (obliqueDetectorResolution) name += "Oblique Detector Resolution";
if (northAzimuth) name += "North Azimuth";
if (sunAzimuth) name += "Sun Azimuth";
if (spacecraftAzimuth) name += "Spacecraft Azimuth";
@@ -365,6 +369,10 @@ void phocube(Buffer &out) {
out[index] = cam->DetectorResolution();
index += 64 * 64;
}
+ if(obliqueDetectorResolution) {
+ out[index] = cam->ObliqueDetectorResolution();
+ index += 64 * 64;
+ }
if(northAzimuth) {
out[index] = cam->NorthAzimuth();
index += 64 * 64;
diff --git a/isis/src/base/apps/phocube/phocube.xml b/isis/src/base/apps/phocube/phocube.xml
index 64bef127a6..c11aef79d3 100644
--- a/isis/src/base/apps/phocube/phocube.xml
+++ b/isis/src/base/apps/phocube/phocube.xml
@@ -1,6 +1,8 @@
-
+
Creates photometric and geometric information bands for an image cube
@@ -80,28 +82,32 @@
The following options are available for Level1 images that contain a camera model:
- - DN
- - PHASE
- - EMISSION
- - INCIDENCE
- - LOCALEMISSION
- - LOCALINCIDENCE
- - LATITUDE
- - LONGITUDE
- - PIXELRESOLUTION
- - LINERESOLUTION
- - SAMPLERESOLUTION
- - DETECTORRESOLUTION
- - NORTHAZIMUTH
- - SUNAZIMUTH
- - SPACECRAFTAZIMUTH
- - OFFNADIRANGLE
- - SUBSPACECRAFTGROUNDAZIMUTH
- - SUBSOLARGROUNDAZIMUTH
+
+ - DN
+ - EMISSION
+ - INCIDENCE
+ - PHASE
+ - OFFNADIRANGLE
+
+ - LOCALEMISSION
+ - LOCALINCIDENCE
+
+ - LATITUDE
+ - LONGITUDE
+ - DETECTORRESOLUTION
+ - OBLIQUEDETECTORRESOLUTION
+ - PIXELRESOLUTION
+ - LINERESOLUTION
+ - SAMPLERESOLUTION
+ - NORTHAZIMUTH
+ - SUNAZIMUTH
+ - SPACECRAFTAZIMUTH
+ - SUBSPACECRAFTGROUNDAZIMUTH
+ - SUBSOLARGROUNDAZIMUTH
- MORPHOLOGY
- - ALBEDO
- - RADEC
- - BODYFIXED
+ - ALBEDO
+ - RADEC (Right Ascension, Declination )
+ - BODYFIXED
The following options are available for Level2 images:
@@ -287,8 +293,13 @@
Added Ra/Dec and Body Fixed Coordinates options to help create new camera models and help
- with mission team operations. References #2277."
+ with mission team operations. References #2277.
+
+
+ Added an ObliqueDetectorResolution band. This is an improvement over the previous DetectorResolution
+ function (particularly for images taken near the limb of the target). References #476, #4100.
+
@@ -369,6 +380,7 @@
- LINERESOLUTION
- SAMPLERESOLUTION
- DETECTORRESOLUTION
+ - OBLIQUEDETECTORRESOLUTION
- SUNAZIMUTH
- SPACECRAFTAZIMUTH
- OFFNADIRANGLE
@@ -532,6 +544,20 @@
in millimeters.
+
+
+ boolean
+ - FALSE
+ Create an oblique detector resolution band
+
+ If this parameter is true, the Oblique Detector Resolution will be
+ computed for every pixel and placed in a band in the output cube. The
+ output cube labels will contain "Oblique Detector Resolution" in the BandBin
+ group, in band sequence of the output file. ObliqueDetectorResolution is
+ in millimeters.
+
+
+
boolean
- FALSE
diff --git a/isis/src/base/apps/phocube/tsts/allbands/Makefile b/isis/src/base/apps/phocube/tsts/allbands/Makefile
index 20cf96c70c..38711ba743 100644
--- a/isis/src/base/apps/phocube/tsts/allbands/Makefile
+++ b/isis/src/base/apps/phocube/tsts/allbands/Makefile
@@ -20,6 +20,7 @@ commands:
lineresolution=true \
sampleresolution=true \
detectorresolution=true \
+ obliquedetectorresolution=true \
northazimuth=true \
sunazimuth=true \
spacecraftazimuth=true \
diff --git a/isis/src/base/objs/Application/Application.cpp b/isis/src/base/objs/Application/Application.cpp
index 7913b33b4c..01c062cd37 100644
--- a/isis/src/base/objs/Application/Application.cpp
+++ b/isis/src/base/objs/Application/Application.cpp
@@ -132,6 +132,7 @@ namespace Isis {
QString xmlfile = f.expanded();
p_ui = new UserInterface(xmlfile, argc, argv);
+
if (!p_ui->IsInteractive()) {
// Get the starting wall clock time
p_datetime = DateTime(&p_startTime);
@@ -139,9 +140,15 @@ namespace Isis {
if (p_applicationForceGuiApp) {
new QApplication(argc, argv);
+ // When QApplication is initialized, it will reset the locale to the shells locale. As a result
+ // the locale needs to be reset after QApplications initialization.
+ setlocale(LC_ALL, "en_US");
}
else {
new QCoreApplication(argc, argv);
+ // When QCoreApplication is initialized, it will reset the locale to the shells locale. As a result
+ // the locale needs to be reset after QCoreApplications initialization.
+ setlocale(LC_ALL, "en_US");
}
QCoreApplication::setApplicationName(FileName(p_appName).baseName());
diff --git a/isis/src/base/objs/Application/Application.h b/isis/src/base/objs/Application/Application.h
index 3e8beadf20..5064ab4f49 100644
--- a/isis/src/base/objs/Application/Application.h
+++ b/isis/src/base/objs/Application/Application.h
@@ -108,6 +108,8 @@ namespace Isis {
* Also needed to define a compiler directive,
* USE_GUI_QAPP, to bypass a problem the Macs have
* with using QApplication. References #575.
+ * @history 2016-08-15 Adam Paquette - Reset locale after QApplication or
+ * QCoreApplication are instantiated. Fixes #3908.
*/
class Application : public Environment {
public:
diff --git a/isis/src/base/objs/Camera/Camera.cpp b/isis/src/base/objs/Camera/Camera.cpp
index c864cf3566..7b6ce249ba 100644
--- a/isis/src/base/objs/Camera/Camera.cpp
+++ b/isis/src/base/objs/Camera/Camera.cpp
@@ -22,10 +22,11 @@
*/
#include "Camera.h"
+
+#include
#include
#include
#include
-#include
#include
#include
@@ -61,10 +62,10 @@
using namespace std;
namespace Isis {
+
/**
- * Constructs the Camera object
- *
- * @param lab Pvl label used to create the Camera object
+ * @brief Constructs the Camera object.
+ * @param cube The Pvl label from the cube is used to create the Camera object.
*/
Camera::Camera(Cube &cube) : Sensor(cube) {
m_instrumentNameLong = "Unknown";
@@ -153,15 +154,13 @@ namespace Isis {
}
}
-
/**
- * Sets the sample/line values of the image to get the lat/lon values
- *
- * @param sample Sample coordinate of the cube
- * @param line Line coordinate of the cube
+ * @brief Sets the sample/line values of the image to get the lat/lon values.
*
- * @return @b bool Returns true if the image was set successfully and false if it
- * was not
+ * @param sample Sample coordinate of the cube.
+ * @param line Line coordinate of the cube.
+ * @return @b bool Returns True if the image was set successfully and Talse if it
+ * was not.
*/
bool Camera::SetImage(const double sample, const double line) {
p_childSample = sample;
@@ -275,7 +274,6 @@ namespace Isis {
return false;
}
-
/**
* Sets the lat/lon values to get the sample/line values
*
@@ -416,9 +414,10 @@ namespace Isis {
}
}
else { // ring plane
- // UniversalLongitude should return azimuth (ring longitude) in this case TODO: when we make the change
- // to real azimuths this value may need to be adjusted or code changed in the shapemodel or
- // surfacepoint class.
+ // UniversalLongitude should return azimuth (ring longitude) in this case
+ // TODO:
+ // when we make the change to real azimuths this value may need to be adjusted or
+ // code changed in the shapemodel or surfacepoint class.
if (p_projection->SetUniversalGround(LocalRadius().meters(), UniversalLongitude())) {
p_childSample = p_projection->WorldX();
p_childLine = p_projection->WorldY();
@@ -438,14 +437,14 @@ namespace Isis {
/**
- * Sets the lat/lon/radius values to get the sample/line values
+ * @brief Sets the lat/lon/radius values to get the sample/line values
*
* @param latitude Latitude coordinate of the cube
* @param longitude Longitude coordinate of the cube
* @param radius Radius coordinate of the cube
*
- * @return @b bool Returns true if the Universal Ground was set successfully
- * and false if it was not
+ * @return @b bool Returns True if the Universal Ground was set successfully
+ * and False if it was not
*/
bool Camera::SetUniversalGround(const double latitude, const double longitude,
const double radius) {
@@ -460,8 +459,114 @@ namespace Isis {
return false;
}
+
+
+ /**
+ * @description This function provides an improved estimate of the detector resolution (in meters)
+ * when the target is near the limb. It does this by calculating the determinant of an affine
+ * transformation. The area element of one pixel projected onto the surface at Nadir looks
+ * like a square with sides of length = Detector Resolution. The detector resolution is the
+ * value returned by the original function. An affine projective transformation of this
+ * area element as one would see if it was on the limb instead of looking straight down, appears
+ * like a skewed parallelogram.
+ *
+ * The determinant of the transformation matrix taking the Nadir-area element into
+ * some parallelogram near the limb of a planet measures the change in area for the
+ * transformation when we are off-Nadir. The sqare-root of the area of this parallelogram
+ * gives us the resolution.
+ *
+ *The calculation is straightforward. Any affine transformation with a strictly positive
+ *determinant that is not a similarity transformation has a unique decomposition
+ *(See Theorem 2.1 in Reference #1):
+ *
+ *
+ *
+ *
+ * @f{eqnarray*}
+ *
+ * A = \[\left[\begin{array}{cc} a & b \\
+ * c & d \end{array} \right]\] =
+ *
+ * H_{\lambda}R_1(\psi)T_tR_2(\phi) = \lambda
+ * \[ \left[\begin{array}{cc} cos(\psi) & -sin(\psi) \\
+ * sin(\psi) & cos(\psi) \end{array} \right]\]
+ * \[ \left[\begin{array}{cc} t & 0 \\
+ * 0 & 1 \end{array} \right]\]
+ * \[ \left[\begin{array}{cc} cos(\phi) & -sin(\phi) \\
+ * sin(\phi) & cos(\phi) \end{array} \right]\]
+ *
+ * @f}
+ *
+ * Where:
+ *
+ * @f$ t = \frac{1}{cos(\theta)}},\;\;\theta = \text{Emmission\;\; Angle}@f$
+ * and @f$\lambda = \text{zoom\;\;factor} = 1@f$
+ *
+ * The determinant of A is:
+ *
+ * @f[ |A| = \lambda t = \frac{\lambda}{cos(\theta)} = \frac{1}{\cos(\theta)} @f]
+ *
+ * This is because the two rotation matrices in this decomposition have determinants equal to 1.
+ *
+ * Let @f$ n = \text{Detector\;\;Resolution} @f$
+ *
+ * Then:
+ *
+ * @f[ Area = n^2 |A| =\frac{n^2}{cos(\theta)}@f]
+ *
+ * And:
+ *
+ * @f[ \text{Local\;\;Detector\;\; Resolution} = \frac{n}{\sqrt{cos(\theta)}} @f]
+ *
+ *
+ * This method returns the Local Detector Resolution if the Look Vector intersects the target
+ * and if @f$ 0 \leq \theta < \frac{\pi}{2} @f$ and -1.0 otherwise.
+ *
+ *
+ *
+ *
+ * Reference 1: J-M Morel and G. Yu, "Asift: A new framework for fully affine
+ * invariant image comparison," SIAM Journal on Imaging Sciences
+ * 2(2), pp. 438-469, 2009
+ *
+ *
+ * @return @b double
+ */
+ double Camera::ObliqueDetectorResolution(){
+
+
+ if(HasSurfaceIntersection()){
+
+
+ double thetaRad;
+ double sB[3];
+ instrumentPosition(sB);
+ double pB[3];
+ Coordinate(pB);
+ double a = sB[0] - pB[0];
+ double b = sB[1] - pB[1];
+ double c = sB[2] - pB[2];
+ double rho = sqrt(a * a + b * b + c * c) * 1000.0;
+
+ thetaRad = EmissionAngle()*DEG2RAD;
+
+ if (thetaRad < HALFPI) {
+
+ double nadirResolution = rho/(p_focalLength/p_pixelPitch);
+ return nadirResolution/sqrt(cos(thetaRad));
+
+ }
+ return Isis::Null;
+
+ }
+
+ return Isis::Null;
+
+ }
+
+
/**
- * Returns the detector resolution at the current position
+ * @brief Returns the detector resolution at the current position in meters.
*
* @return @b double The detector resolution
*/
@@ -480,17 +585,31 @@ namespace Isis {
return Isis::Null;
}
+
/**
- * Returns the sample resolution at the current position
+ * @brief Returns the sample resolution at the current position in meters.
*
* @return @b double The sample resolution
*/
double Camera::SampleResolution() {
+
return DetectorResolution() * p_detectorMap->SampleScaleFactor();
}
/**
- * Returns the line resolution at the current position
+ * @brief Returns the oblique sample resolution at the current position in m. This gives
+ * a more accurate estimate of the sample resolution at oblique angles.
+ *
+ * @return @b double The sample resolution
+ */
+ double Camera::ObliqueSampleResolution() {
+
+ return ObliqueDetectorResolution() * p_detectorMap->SampleScaleFactor();
+ }
+
+
+ /**
+ * @brief Returns the line resolution at the current position in meters.
*
* @return @b double The line resolution
*/
@@ -498,9 +617,22 @@ namespace Isis {
return DetectorResolution() * p_detectorMap->LineScaleFactor();
}
+
/**
- * Returns the pixel resolution at the current position in m/pix
+ * @brief Returns the oblique line resolution at the current position in meters. This
+ * provides a more accurate estimate of the line resolution at oblique
+ * angles.
*
+ * @return @b double The line resolution
+ */
+ double Camera::ObliqueLineResolution() {
+
+ return ObliqueDetectorResolution() * p_detectorMap->LineScaleFactor();
+ }
+
+
+ /**
+ * @brief Returns the pixel resolution at the current position in meters/pixel.
* @return @b double The pixel resolution
*/
double Camera::PixelResolution() {
@@ -511,8 +643,24 @@ namespace Isis {
return (lineRes + sampRes) / 2.0;
}
+
+ /**
+ * @brief Returns the oblique pixel resolution at the current position in meters/pixel. This
+ * provides a more accurate estimate of the pixel resolution at oblique angles.
+ *
+ * @return @b double The pixel resolution
+ */
+ double Camera::ObliquePixelResolution() {
+ double lineRes = ObliqueLineResolution();
+ double sampRes = ObliqueSampleResolution();
+ if (lineRes < 0.0) return Isis::Null;
+ if (sampRes < 0.0) return Isis::Null;
+ return (lineRes + sampRes) / 2.0;
+ }
+
+
/**
- * Returns the lowest/worst resolution in the entire image
+ * @brief Returns the lowest/worst resolution in the entire image
*
* @return @b double The lowest/worst resolution in the image
*/
@@ -521,8 +669,9 @@ namespace Isis {
return p_maxres;
}
+
/**
- * Returns the highest/best resolution in the entire image
+ * @brief Returns the highest/best resolution in the entire image
*
* @return @b double The highest/best resolution in the entire image
*/
@@ -531,8 +680,31 @@ namespace Isis {
return p_minres;
}
+
+ /**
+ * @brief Returns the lowest/worst oblique resolution in the entire image
+ *
+ * @return @b double The lowest/worst oblique resolution in the image
+ */
+ double Camera::LowestObliqueImageResolution() {
+ GroundRangeResolution();
+ return p_minobliqueres;
+ }
+
+
/**
- * Computes the ground range and min/max resolution
+ * @brief Returns the highest/best oblique resolution in the entire image
+ *
+ * @return @b double The highest/best oblique resolution in the entire image
+ */
+ double Camera::HighestObliqueImageResolution() {
+ GroundRangeResolution();
+ return p_maxobliqueres;
+ }
+
+
+ /**
+ * @brief Computes the ground range and min/max resolution
*/
void Camera::GroundRangeResolution() {
// Software adjustment is needed if we get here -- call RingRangeResolution instead
@@ -560,6 +732,8 @@ namespace Isis {
p_maxlon180 = -DBL_MAX;
p_minres = DBL_MAX;
p_maxres = -DBL_MAX;
+ p_minobliqueres = DBL_MAX;
+ p_maxobliqueres = -DBL_MAX;
// See if we have band dependence and loop for the appropriate number of bands
int eband = p_bands;
@@ -591,6 +765,13 @@ namespace Isis {
if (res < p_minres) p_minres = res;
if (res > p_maxres) p_maxres = res;
}
+ // Determine min/max oblique resolution
+ double obliqueres = ObliquePixelResolution();
+ if (obliqueres > 0.0) {
+ if (obliqueres < p_minobliqueres) p_minobliqueres = obliqueres;
+ if (obliqueres > p_maxobliqueres) p_maxobliqueres = obliqueres;
+
+ }
if ((line != 1) && (line != p_lines + 1)) break;
}
} // end loop through samples
@@ -619,6 +800,14 @@ namespace Isis {
if (res < p_minres) p_minres = res;
if (res > p_maxres) p_maxres = res;
}
+
+ // Determine min/max oblique resolution
+ double obliqueres = ObliquePixelResolution();
+ if (obliqueres > 0.0) {
+ if (obliqueres < p_minobliqueres) p_minobliqueres = obliqueres;
+ if (obliqueres > p_maxobliqueres) p_maxobliqueres = obliqueres;
+
+ }
break;
}
}
@@ -648,6 +837,13 @@ namespace Isis {
if (res < p_minres) p_minres = res;
if (res > p_maxres) p_maxres = res;
}
+
+ double obliqueres = ObliquePixelResolution();
+ if (obliqueres > 0.0) {
+ if (obliqueres < p_minobliqueres) p_minobliqueres = obliqueres;
+ if (obliqueres > p_maxobliqueres) p_maxobliqueres = obliqueres;
+
+ }
}
}
} // end valid local (subspacecraft) radius
@@ -738,7 +934,9 @@ namespace Isis {
// Checks for invalid lat/lon ranges
-// if(p_minlon == DBL_MAX || p_minlat == DBL_MAX || p_maxlon == -DBL_MAX || p_maxlat == -DBL_MAX) {
+// if(p_minlon == DBL_MAX || p_minlat == DBL_MAX || p_maxlon == -DBL_MAX
+// || p_maxlat == -DBL_MAX)
+// {
// string message = "Camera missed planet or SPICE data off.";
// throw IException(IException::Unknown, message, _FILEINFO_);
// }
@@ -746,7 +944,7 @@ namespace Isis {
/**
- * Analogous to above GroundRangeResolution method. Computes the ring range
+ * @brief Analogous to above GroundRangeResolution method. Computes the ring range
* and min/max resolution
*/
void Camera::ringRangeResolution() {
@@ -916,7 +1114,8 @@ namespace Isis {
}
// Checks for invalid radius/lon ranges
- if (p_minRingRadius == DBL_MAX || p_minRingRadius == DBL_MAX || p_minRingLongitude == DBL_MAX || p_maxRingLongitude == -DBL_MAX) {
+ if (p_minRingRadius == DBL_MAX || p_minRingRadius == DBL_MAX
+ || p_minRingLongitude == DBL_MAX || p_maxRingLongitude == -DBL_MAX) {
string message = "RingPlane ShapeModel - Camera missed plane or SPICE data off.";
throw IException(IException::Unknown, message, _FILEINFO_);
}
@@ -1152,7 +1351,8 @@ namespace Isis {
* @param pvl Pvl to write mapping group to
*/
void Camera::basicRingMapping(Pvl &pvl) {
- if (target()->shape()->name() != "Plane") { // If we get here and we don't have a plane, throw an error
+ if (target()->shape()->name() != "Plane") {
+ // If we get here and we don't have a plane, throw an error
IString msg = "A ring plane projection has been requested on an image whose shape is not a ring plane. ";
msg += "Rerun spiceinit with shape=RINGPLANE. ";
throw IException(IException::User, msg, _FILEINFO_);
@@ -1189,6 +1389,8 @@ namespace Isis {
SetPixelPitch(Spice::getDouble(key));
}
+
+
/**
* Sets the right ascension declination
*
@@ -1456,6 +1658,8 @@ namespace Isis {
// angle (in radians)
incidence = Angle(vsep_c(unitizedSurfSunVect, normal),
Angle::Radians);
+
+
}
@@ -1466,12 +1670,13 @@ namespace Isis {
* @param maxra Maximum right ascension value
* @param mindec Minimum declination value
* @param maxdec Maximum declination value
- *
* @return @b bool Returns true if the range computation was successful and false
* if it was not
*/
bool Camera::RaDecRange(double &minra, double &maxra,
double &mindec, double &maxdec) {
+
+
bool computed = p_pointComputed;
double originalSample = Sample();
double originalLine = Line();
@@ -1611,6 +1816,7 @@ namespace Isis {
* @return @b double The resutant RaDec resolution
*/
double Camera::RaDecResolution() {
+
bool computed = p_pointComputed;
double originalSample = Sample();
double originalLine = Line();
@@ -1687,7 +1893,6 @@ namespace Isis {
return ComputeAzimuth(LocalRadius(lat, lon), lat, lon);
}
-
/**
* Return the Spacecraft Azimuth
*
@@ -1701,7 +1906,6 @@ namespace Isis {
return ComputeAzimuth(LocalRadius(lat, lon), lat, lon);
}
-
/**
* Computes the image azimuth value from your current position (origin) to a point of interest
* specified by the lat/lon input to this method. (NOTE: This azimuth is different from a Ground
@@ -1952,7 +2156,6 @@ namespace Isis {
return azimuth;
}
-
/**
* Return the off nadir angle in degrees.
*
@@ -1978,7 +2181,6 @@ namespace Isis {
return c;
}
-
/**
* Computes and returns the ground azimuth between the ground point and
* another point of interest, such as the subspacecraft point or the
@@ -2106,7 +2308,6 @@ namespace Isis {
p_distortionMap = map;
}
-
/**
* Sets the Focal Plane Map. This object will take ownership of the focal plane
* map pointer.
@@ -2121,7 +2322,6 @@ namespace Isis {
p_focalPlaneMap = map;
}
-
/**
* Sets the Detector Map. This object will take ownership of the detector map
* pointer.
@@ -2136,7 +2336,6 @@ namespace Isis {
p_detectorMap = map;
}
-
/**
* Sets the Ground Map. This object will take ownership of the ground map
* pointer.
@@ -2151,7 +2350,6 @@ namespace Isis {
p_groundMap = map;
}
-
/**
* Sets the Sky Map. This object will take ownership of the sky map pointer.
*
@@ -2165,7 +2363,6 @@ namespace Isis {
p_skyMap = map;
}
-
/**
* This loads the spice cache big enough for this image. The default cache size
* is the number of lines in the cube if the ephemeris time changes in the
@@ -2261,7 +2458,6 @@ namespace Isis {
return ephemerisTimes;
}
-
/**
* This method calculates the spice cache size. This method finds the number
* of lines in the beta cube and adds 1, since we need at least 2 points for
@@ -2346,7 +2542,6 @@ namespace Isis {
p_geometricTilingEndSize = endSize;
}
-
/**
* This will get the geometric tiling hint; these values are typically used for
* ProcessRubberSheet::SetTiling(...).
@@ -2380,7 +2575,6 @@ namespace Isis {
return true;
}
-
/**
* Checks to see if the camera object has a projection
*
@@ -2389,8 +2583,7 @@ namespace Isis {
*/
bool Camera::HasProjection() {
return p_projection != 0;
- }
-
+ }
/**
* Virtual method that checks if the band is independent
@@ -2402,7 +2595,6 @@ namespace Isis {
return true;
}
-
/**
* Returns the reference band
*
@@ -2412,7 +2604,6 @@ namespace Isis {
return p_referenceBand;
}
-
/**
* Checks to see if the Camera object has a reference band
*
@@ -2423,7 +2614,6 @@ namespace Isis {
return p_referenceBand != 0;
}
-
/**
* Virtual method that sets the band number
*
@@ -2433,7 +2623,6 @@ namespace Isis {
p_childBand = band;
}
-
/**
* Returns the current sample number
*
@@ -2443,7 +2632,6 @@ namespace Isis {
return p_childSample;
}
-
/**
* Returns the current band
*
@@ -2453,7 +2641,6 @@ namespace Isis {
return p_childBand;
}
-
/**
* Returns the current line number
*
@@ -2462,8 +2649,6 @@ namespace Isis {
double Camera::Line() {
return p_childLine;
}
-
-
/**
* Returns the resolution of the camera
*
@@ -2474,6 +2659,8 @@ namespace Isis {
}
+
+
/**
* Returns the focal length
*
@@ -2483,7 +2670,6 @@ namespace Isis {
return p_focalLength;
}
-
/**
* Returns the pixel pitch
*
@@ -2493,7 +2679,6 @@ namespace Isis {
return p_pixelPitch;
}
-
/**
* Returns the pixel ifov offsets from center of pixel, which defaults to the
* (pixel pitch * summing mode ) / 2. If an instrument has a non-square ifov, it must implement
@@ -2525,7 +2710,6 @@ namespace Isis {
return p_samples;
}
-
/**
* Returns the number of lines in the image
*
@@ -2535,7 +2719,6 @@ namespace Isis {
return p_lines;
}
-
/**
* Returns the number of bands in the image
*
@@ -2545,7 +2728,6 @@ namespace Isis {
return p_bands;
}
-
/**
* Returns the number of lines in the parent alphacube
*
@@ -2555,7 +2737,6 @@ namespace Isis {
return p_alphaCube->AlphaLines();
}
-
/**
* Returns the number of samples in the parent alphacube
*
@@ -2564,8 +2745,6 @@ namespace Isis {
int Camera::ParentSamples() const {
return p_alphaCube->AlphaSamples();
}
-
-
/**
* Returns a pointer to the CameraDistortionMap object
*
@@ -2575,7 +2754,6 @@ namespace Isis {
return p_distortionMap;
}
-
/**
* Returns a pointer to the CameraFocalPlaneMap object
*
@@ -2585,7 +2763,6 @@ namespace Isis {
return p_focalPlaneMap;
}
-
/**
* Returns a pointer to the CameraDetectorMap object
*
@@ -2595,7 +2772,6 @@ namespace Isis {
return p_detectorMap;
}
-
/**
* Returns a pointer to the CameraGroundMap object
*
@@ -2605,7 +2781,6 @@ namespace Isis {
return p_groundMap;
}
-
/**
* Returns a pointer to the CameraSkyMap object
*
@@ -2794,3 +2969,5 @@ namespace Isis {
// end namespace isis
}
+
+
diff --git a/isis/src/base/objs/Camera/Camera.h b/isis/src/base/objs/Camera/Camera.h
index 4f1721c52a..1942cd7a73 100644
--- a/isis/src/base/objs/Camera/Camera.h
+++ b/isis/src/base/objs/Camera/Camera.h
@@ -213,15 +213,15 @@ namespace Isis {
* @history 2015-10-16 Ian Humphrey - Added protected members for spacecraft and instrument
* names as well as public member getters. Updated unit test.
* References #2335.
- * @history 2015-09-01 Ian Humphrey and Makayla Shepherd - Modified unit test to override
- * Sensor's pure virtual methods.
- * @history 2015-10-16 Ian Humphrey - Added protected members for spacecraft and instrument
- * names as well as public member getters. Updated unit test.
- * References #2335.
* @history 2016-06-27 Kelvin Rodriguez - Added member function to compute celestial north
* clock angle. References #2365
* @history 2016-08-01 Curtis Rose - Changed return values of resolutions from -1 to Isis::Null.
* Fixes #2065.
+ * @history 2016-08-16 Tyler Wilson - Added ObliqueDectectorResolution,ObliqueLineResolution,
+ * ObliqueSampleResolution, and ObliquePixelResolution functions
+ * which give greatly improved approximations compared to their
+ * non-oblique counterpart functions when the Look vector is pointing
+ * off nadir and near the limb. Fixes #476. References #4100.
*/
class Camera : public Sensor {
@@ -267,9 +267,17 @@ namespace Isis {
double SampleResolution();
double DetectorResolution();
+ double ObliqueDetectorResolution();
+ double ObliqueSampleResolution();
+ double ObliqueLineResolution();
+ double ObliquePixelResolution();
+
+
virtual double resolution();
double LowestImageResolution();
double HighestImageResolution();
+ double LowestObliqueImageResolution();
+ double HighestObliqueImageResolution();
void BasicMapping(Pvl &map);
void basicRingMapping(Pvl &map);
@@ -288,7 +296,6 @@ namespace Isis {
bool RaDecRange(double &minra, double &maxra,
double &mindec, double &maxdec);
-
double RaDecResolution();
CameraDistortionMap *DistortionMap();
@@ -483,6 +490,8 @@ namespace Isis {
double p_maxlon; //!< The maximum longitude
double p_minres; //!< The minimum resolution
double p_maxres; //!< The maximum resolution
+ double p_minobliqueres; //!< The minimum oblique resolution
+ double p_maxobliqueres; //!< The maximum oblique resolution
double p_minlon180; //!< The minimum longitude in the 180 domain
double p_maxlon180; //!< The maximum longitude in the 180 domain
bool p_groundRangeComputed; /**!< Flag showing if ground range
@@ -520,7 +529,7 @@ namespace Isis {
AlphaCube *p_alphaCube; //!< A pointer to the AlphaCube
double p_childSample; //!< Sample value for child
double p_childLine; //!< Line value for child
- int p_childBand; //!< Band value for child. Should be the virtual band not original band.
+ int p_childBand; //!< Band value for child
CameraDistortionMap *p_distortionMap; //!< A pointer to the DistortionMap
CameraFocalPlaneMap *p_focalPlaneMap; //!< A pointer to the FocalPlaneMap
CameraDetectorMap *p_detectorMap; //!< A pointer to the DetectorMap
@@ -540,3 +549,5 @@ namespace Isis {
};
#endif
+
+
diff --git a/isis/src/base/objs/Camera/Camera.truth b/isis/src/base/objs/Camera/Camera.truth
index e680927f06..b16d59eb45 100644
--- a/isis/src/base/objs/Camera/Camera.truth
+++ b/isis/src/base/objs/Camera/Camera.truth
@@ -47,9 +47,13 @@ Line: 962
GroundRange: 0
IntersectsLongitudeDomain: 0
PixelResolution: 628
+ObliquePixelResolution: 685
LineResolution: 628
+ObliqueLineResolution: 685
SampleResolution: 628
+ObliqueSampleResolution: 685
DetectorResolution: 157
+ObliqueDetectorResolution: 171
LowestImageResolution: 2047
HighestImageResolution: 430
Calling BasicMapping (pvl)...
diff --git a/isis/src/base/objs/Camera/unitTest.cpp b/isis/src/base/objs/Camera/unitTest.cpp
index cbfe7d5c62..cc71c20dcb 100644
--- a/isis/src/base/objs/Camera/unitTest.cpp
+++ b/isis/src/base/objs/Camera/unitTest.cpp
@@ -50,8 +50,8 @@ using namespace Isis;
* (i.e. non-DEM) shape model. References #2243.
* @history 2015-10-16 Ian Humphrey - Updated to test spacecraft and instrument name methods.
* References #2335.
- *
- *
+ * @history 2016-08-19 Tyler Wilson - Updated to test ObliquePixel/ObliqueLine/ObliqueSample
+ * and ObliqueDetector resolutions. References #476.
* testcoverage 2015-04-30 - 43.262% scope, 61.561% line, 87.5% function
*/
@@ -162,9 +162,15 @@ int main() {
}
cout << "PixelResolution: " << c->PixelResolution() << endl;
+ cout << "ObliquePixelResolution: " << c->ObliquePixelResolution() << endl;
cout << "LineResolution: " << c->LineResolution() << endl;
+ cout << "ObliqueLineResolution: " << c->ObliqueLineResolution() << endl;
cout << "SampleResolution: " << c->SampleResolution() << endl;
+ cout << "ObliqueSampleResolution: " << c->ObliqueSampleResolution() << endl;
cout << "DetectorResolution: " << c->DetectorResolution() << endl;
+ cout << "ObliqueDetectorResolution: " << c->ObliqueDetectorResolution() << endl;
+
+
cout << "LowestImageResolution: " << setprecision(4)
<< c->LowestImageResolution() << endl;
cout << "HighestImageResolution: " << setprecision(3)
@@ -628,3 +634,4 @@ int main() {
IException(e, IException::Unknown, msg, _FILEINFO_).print();
}
}
+
diff --git a/isis/src/base/objs/CameraPointInfo/CameraPointInfo.cpp b/isis/src/base/objs/CameraPointInfo/CameraPointInfo.cpp
index 6190b70f78..56394ce690 100644
--- a/isis/src/base/objs/CameraPointInfo/CameraPointInfo.cpp
+++ b/isis/src/base/objs/CameraPointInfo/CameraPointInfo.cpp
@@ -55,8 +55,14 @@ namespace Isis {
m_usedCubes->SetNumOpenCubes(50);
m_currentCube = NULL;
m_camera = NULL;
+ m_csvOutput = false;
}
+ void CameraPointInfo::SetCSVOutput(bool csvOutput) {
+
+ m_csvOutput = csvOutput;
+
+ }
/**
* Destructor, deletes CubeManager object used.
@@ -71,9 +77,9 @@ namespace Isis {
/**
- * SetCube opens the given cube in a CubeManager.
- * The CubeManager is for effeciency when working with control
- * nets where cubes are accesed multiple times.
+ * SetCube opens the given cube in a CubeManager.
+ * The CubeManager is for effeciency when working with control
+ * nets where cubes are accesed multiple times.
*
* @param cubeFileName A cube file name.
*/
@@ -90,10 +96,10 @@ namespace Isis {
* @param sample A sample coordinate in or almost in the cube.
* @param line A line coordinate in or almost in the cube.
* @param allowOutside Indicates whether to allow extrapolation.
- * @param allowErrors Indicates whether to allow the program to
+ * @param allowErrors Indicates whether to allow the program to
* throw an error if a problem occurs.
*
- * @return @b PvlGroup* The pertinent data from the Camera class on the point.
+ * @return @b PvlGroup* The pertinent data from the Camera class on the point.
* Ownership is passed to caller.
*/
PvlGroup *CameraPointInfo::SetImage(const double sample, const double line,
@@ -108,18 +114,18 @@ namespace Isis {
/**
- * SetCenter sets the image coordinates to the center of the image.
- *
+ * SetCenter sets the image coordinates to the center of the image.
+ *
* @param allowOutside Indicates whether to allow extrapolation.
- * @param allowErrors Indicates whether to allow the program to
+ * @param allowErrors Indicates whether to allow the program to
* throw an error if a problem occurs.
*
- * @return @b PvlGroup* The pertinent data from the Camera class on the point.
+ * @return @b PvlGroup* The pertinent data from the Camera class on the point.
* Ownership is passed to caller.
*/
PvlGroup *CameraPointInfo::SetCenter(const bool allowOutside, const bool allowErrors) {
if (CheckCube()) {
- bool passed = m_camera->SetImage(m_currentCube->sampleCount() / 2.0,
+ bool passed = m_camera->SetImage(m_currentCube->sampleCount() / 2.0,
m_currentCube->lineCount() / 2.0);
return GetPointInfo(passed, allowOutside, allowErrors);
}
@@ -134,14 +140,14 @@ namespace Isis {
*
* @param sample A sample coordinate in or almost in the cube.
* @param allowOutside Indicates whether to allow extrapolation.
- * @param allowErrors Indicates whether to allow the program to
+ * @param allowErrors Indicates whether to allow the program to
* throw an error if a problem occurs.
- *
- * @return @b PvlGroup* The pertinent data from the Camera class on the point.
+ *
+ * @return @b PvlGroup* The pertinent data from the Camera class on the point.
* Ownership is passed to caller.
*/
PvlGroup *CameraPointInfo::SetSample(const double sample,
- const bool allowOutside,
+ const bool allowOutside,
const bool allowErrors) {
if (CheckCube()) {
bool passed = m_camera->SetImage(sample, m_currentCube->lineCount() / 2.0);
@@ -158,10 +164,10 @@ namespace Isis {
*
* @param line A line coordinate in or almost in the cube.
* @param allowOutside Indicates whether to allow extrapolation.
- * @param allowErrors Indicates whether to allow the program to
+ * @param allowErrors Indicates whether to allow the program to
* throw an error if a problem occurs.
- *
- * @return @b PvlGroup* The pertinent data from the Camera class on the point.
+ *
+ * @return @b PvlGroup* The pertinent data from the Camera class on the point.
* Ownership is passed to caller.
*/
PvlGroup *CameraPointInfo::SetLine(const double line,
@@ -183,10 +189,10 @@ namespace Isis {
* @param latitude A latitude coordinate in or almost in the cube
* @param longitude A longitude coordinate in or almost in the cube
* @param allowOutside Indicates whether to allow extrapolation.
- * @param allowErrors Indicates whether to allow the program to
+ * @param allowErrors Indicates whether to allow the program to
* throw an error if a problem occurs.
*
- * @return @b PvlGroup* The pertinent data from the Camera class on the point.
+ * @return @b PvlGroup* The pertinent data from the Camera class on the point.
* Ownership is passed to caller.
*/
PvlGroup *CameraPointInfo::SetGround(const double latitude, const double longitude,
@@ -218,65 +224,130 @@ namespace Isis {
/**
* GetPointInfo builds the PvlGroup containing all the important
- * information derived from the Camera.
- *
+ * information derived from the Camera.
+ *
* @param passed Indicates whether the call to SetImage() was successful.
* @param allowOutside Indicates whether to allow extrapolation.
- * @param allowErrors Indicates whether to allow the program to
+ * @param allowErrors Indicates whether to allow the program to
* throw an error if a problem occurs.
*
- * @return @b PvlGroup* Data taken directly from the Camera and
+ * @return @b PvlGroup* Data taken directly from the Camera and
* derived from Camera information.
* Ownership is passed to caller.
*/
PvlGroup *CameraPointInfo::GetPointInfo(bool passed, bool allowOutside, bool allowErrors) {
PvlGroup *gp = new PvlGroup("GroundPoint");
+
+ //Outputting in PVL format
+ if(!m_csvOutput)
{
- gp->addKeyword(PvlKeyword("Filename"));
- gp->addKeyword(PvlKeyword("Sample"));
- gp->addKeyword(PvlKeyword("Line"));
- gp->addKeyword(PvlKeyword("PixelValue"));
- gp->addKeyword(PvlKeyword("RightAscension"));
- gp->addKeyword(PvlKeyword("Declination"));
- gp->addKeyword(PvlKeyword("PlanetocentricLatitude"));
- gp->addKeyword(PvlKeyword("PlanetographicLatitude"));
- gp->addKeyword(PvlKeyword("PositiveEast360Longitude"));
- gp->addKeyword(PvlKeyword("PositiveEast180Longitude"));
- gp->addKeyword(PvlKeyword("PositiveWest360Longitude"));
- gp->addKeyword(PvlKeyword("PositiveWest180Longitude"));
- gp->addKeyword(PvlKeyword("BodyFixedCoordinate"));
- gp->addKeyword(PvlKeyword("LocalRadius"));
- gp->addKeyword(PvlKeyword("SampleResolution"));
- gp->addKeyword(PvlKeyword("LineResolution"));
- gp->addKeyword(PvlKeyword("SpacecraftPosition"));
- gp->addKeyword(PvlKeyword("SpacecraftAzimuth"));
- gp->addKeyword(PvlKeyword("SlantDistance"));
- gp->addKeyword(PvlKeyword("TargetCenterDistance"));
- gp->addKeyword(PvlKeyword("SubSpacecraftLatitude"));
- gp->addKeyword(PvlKeyword("SubSpacecraftLongitude"));
- gp->addKeyword(PvlKeyword("SpacecraftAltitude"));
- gp->addKeyword(PvlKeyword("OffNadirAngle"));
- gp->addKeyword(PvlKeyword("SubSpacecraftGroundAzimuth"));
- gp->addKeyword(PvlKeyword("SunPosition"));
- gp->addKeyword(PvlKeyword("SubSolarAzimuth"));
- gp->addKeyword(PvlKeyword("SolarDistance"));
- gp->addKeyword(PvlKeyword("SubSolarLatitude"));
- gp->addKeyword(PvlKeyword("SubSolarLongitude"));
- gp->addKeyword(PvlKeyword("SubSolarGroundAzimuth"));
- gp->addKeyword(PvlKeyword("Phase"));
- gp->addKeyword(PvlKeyword("Incidence"));
- gp->addKeyword(PvlKeyword("Emission"));
- gp->addKeyword(PvlKeyword("NorthAzimuth"));
- gp->addKeyword(PvlKeyword("EphemerisTime"));
- gp->addKeyword(PvlKeyword("UTC"));
- gp->addKeyword(PvlKeyword("LocalSolarTime"));
- gp->addKeyword(PvlKeyword("SolarLongitude"));
- gp->addKeyword(PvlKeyword("LookDirectionBodyFixed"));
- gp->addKeyword(PvlKeyword("LookDirectionJ2000"));
- gp->addKeyword(PvlKeyword("LookDirectionCamera"));
- if (allowErrors) gp->addKeyword(PvlKeyword("Error"));
+ gp->addKeyword(PvlKeyword("Filename"));
+ gp->addKeyword(PvlKeyword("Sample"));
+ gp->addKeyword(PvlKeyword("Line"));
+ gp->addKeyword(PvlKeyword("PixelValue"));
+ gp->addKeyword(PvlKeyword("RightAscension"));
+ gp->addKeyword(PvlKeyword("Declination"));
+ gp->addKeyword(PvlKeyword("PlanetocentricLatitude"));
+ gp->addKeyword(PvlKeyword("PlanetographicLatitude"));
+ gp->addKeyword(PvlKeyword("PositiveEast360Longitude"));
+ gp->addKeyword(PvlKeyword("PositiveEast180Longitude"));
+ gp->addKeyword(PvlKeyword("PositiveWest360Longitude"));
+ gp->addKeyword(PvlKeyword("PositiveWest180Longitude"));
+ gp->addKeyword(PvlKeyword("BodyFixedCoordinate"));
+ gp->addKeyword(PvlKeyword("LocalRadius"));
+ gp->addKeyword(PvlKeyword("SampleResolution"));
+ gp->addKeyword(PvlKeyword("LineResolution"));
+ gp->addKeyword(PvlKeyword("ObliqueDetectorResolution"));
+ gp->addKeyword(PvlKeyword("ObliquePixelResolution"));
+ gp->addKeyword(PvlKeyword("ObliqueLineResolution"));
+ gp->addKeyword(PvlKeyword("ObliqueSampleResolution"));
+ gp->addKeyword(PvlKeyword("SpacecraftPosition"));
+ gp->addKeyword(PvlKeyword("SpacecraftAzimuth"));
+ gp->addKeyword(PvlKeyword("SlantDistance"));
+ gp->addKeyword(PvlKeyword("TargetCenterDistance"));
+ gp->addKeyword(PvlKeyword("SubSpacecraftLatitude"));
+ gp->addKeyword(PvlKeyword("SubSpacecraftLongitude"));
+ gp->addKeyword(PvlKeyword("SpacecraftAltitude"));
+ gp->addKeyword(PvlKeyword("OffNadirAngle"));
+ gp->addKeyword(PvlKeyword("SubSpacecraftGroundAzimuth"));
+ gp->addKeyword(PvlKeyword("SunPosition"));
+ gp->addKeyword(PvlKeyword("SubSolarAzimuth"));
+ gp->addKeyword(PvlKeyword("SolarDistance"));
+ gp->addKeyword(PvlKeyword("SubSolarLatitude"));
+ gp->addKeyword(PvlKeyword("SubSolarLongitude"));
+ gp->addKeyword(PvlKeyword("SubSolarGroundAzimuth"));
+ gp->addKeyword(PvlKeyword("Phase"));
+ gp->addKeyword(PvlKeyword("Incidence"));
+ gp->addKeyword(PvlKeyword("Emission"));
+ gp->addKeyword(PvlKeyword("NorthAzimuth"));
+ gp->addKeyword(PvlKeyword("EphemerisTime"));
+ gp->addKeyword(PvlKeyword("UTC"));
+ gp->addKeyword(PvlKeyword("LocalSolarTime"));
+ gp->addKeyword(PvlKeyword("SolarLongitude"));
+ gp->addKeyword(PvlKeyword("LookDirectionBodyFixed"));
+ gp->addKeyword(PvlKeyword("LookDirectionJ2000"));
+ gp->addKeyword(PvlKeyword("LookDirectionCamera"));
+
+ if (allowErrors) gp->addKeyword(PvlKeyword("Error"));
}
+ else {
+
+ gp->addKeyword(PvlKeyword("Filename"));
+ gp->addKeyword(PvlKeyword("Sample"));
+ gp->addKeyword(PvlKeyword("Line"));
+ gp->addKeyword(PvlKeyword("PixelValue"));
+ gp->addKeyword(PvlKeyword("RightAscension"));
+ gp->addKeyword(PvlKeyword("Declination"));
+ gp->addKeyword(PvlKeyword("PlanetocentricLatitude"));
+ gp->addKeyword(PvlKeyword("PlanetographicLatitude"));
+ gp->addKeyword(PvlKeyword("PositiveEast360Longitude"));
+ gp->addKeyword(PvlKeyword("PositiveEast180Longitude"));
+ gp->addKeyword(PvlKeyword("PositiveWest360Longitude"));
+ gp->addKeyword(PvlKeyword("PositiveWest180Longitude"));
+ gp->addKeyword(PvlKeyword("BodyFixedCoordinate"));
+ gp->addKeyword(PvlKeyword("LocalRadius"));
+ gp->addKeyword(PvlKeyword("SampleResolution"));
+ gp->addKeyword(PvlKeyword("LineResolution"));
+ gp->addKeyword(PvlKeyword("SpacecraftPosition"));
+ gp->addKeyword(PvlKeyword("SpacecraftAzimuth"));
+ gp->addKeyword(PvlKeyword("SlantDistance"));
+ gp->addKeyword(PvlKeyword("TargetCenterDistance"));
+ gp->addKeyword(PvlKeyword("SubSpacecraftLatitude"));
+ gp->addKeyword(PvlKeyword("SubSpacecraftLongitude"));
+ gp->addKeyword(PvlKeyword("SpacecraftAltitude"));
+ gp->addKeyword(PvlKeyword("OffNadirAngle"));
+ gp->addKeyword(PvlKeyword("SubSpacecraftGroundAzimuth"));
+ gp->addKeyword(PvlKeyword("SunPosition"));
+ gp->addKeyword(PvlKeyword("SubSolarAzimuth"));
+ gp->addKeyword(PvlKeyword("SolarDistance"));
+ gp->addKeyword(PvlKeyword("SubSolarLatitude"));
+ gp->addKeyword(PvlKeyword("SubSolarLongitude"));
+ gp->addKeyword(PvlKeyword("SubSolarGroundAzimuth"));
+ gp->addKeyword(PvlKeyword("Phase"));
+ gp->addKeyword(PvlKeyword("Incidence"));
+ gp->addKeyword(PvlKeyword("Emission"));
+ gp->addKeyword(PvlKeyword("NorthAzimuth"));
+ gp->addKeyword(PvlKeyword("EphemerisTime"));
+ gp->addKeyword(PvlKeyword("UTC"));
+ gp->addKeyword(PvlKeyword("LocalSolarTime"));
+ gp->addKeyword(PvlKeyword("SolarLongitude"));
+ gp->addKeyword(PvlKeyword("LookDirectionBodyFixed"));
+ gp->addKeyword(PvlKeyword("LookDirectionJ2000"));
+ gp->addKeyword(PvlKeyword("LookDirectionCamera"));
+ gp->addKeyword(PvlKeyword("ObliqueDetectorResolution"));
+ gp->addKeyword(PvlKeyword("ObliquePixelResolution"));
+ gp->addKeyword(PvlKeyword("ObliqueLineResolution"));
+ gp->addKeyword(PvlKeyword("ObliqueSampleResolution"));
+ if (allowErrors) gp->addKeyword(PvlKeyword("Error"));
+
+
+
+
+ }
+
+
+
bool noErrors = passed;
QString error = "";
if (!m_camera->HasSurfaceIntersection()) {
@@ -330,7 +401,7 @@ namespace Isis {
double pB[3], spB[3], sB[3];
QString utc;
double ssplat, ssplon, sslat, sslon, ocentricLat, ographicLat, pe360Lon, pw360Lon;
-
+
{
gp->findKeyword("FileName").setValue(m_currentCube->fileName());
gp->findKeyword("Sample").setValue(toString(m_camera->Sample()));
@@ -346,14 +417,14 @@ namespace Isis {
// Convert lat to planetographic
Distance radii[3];
m_camera->radii(radii);
- ographicLat = TProjection::ToPlanetographic(ocentricLat,
- radii[0].kilometers(),
+ ographicLat = TProjection::ToPlanetographic(ocentricLat,
+ radii[0].kilometers(),
radii[2].kilometers());
gp->findKeyword("PlanetographicLatitude").setValue(toString(ographicLat), "DEGREE");
-
+
pe360Lon = m_camera->UniversalLongitude();
gp->findKeyword("PositiveEast360Longitude").setValue(toString(pe360Lon), "DEGREE");
-
+
//Convert lon to -180 - 180 range
gp->findKeyword("PositiveEast180Longitude").setValue(toString(
TProjection::To180Domain(pe360Lon)), "DEGREE");
@@ -365,7 +436,7 @@ namespace Isis {
//Convert pwlon to -180 - 180 range
gp->findKeyword("PositiveWest180Longitude").setValue(
toString( TProjection::To180Domain(pw360Lon)), "DEGREE");
-
+
m_camera->Coordinate(pB);
gp->findKeyword("BodyFixedCoordinate").addValue(toString(pB[0]), "km");
gp->findKeyword("BodyFixedCoordinate").addValue(toString(pB[1]), "km");
@@ -373,19 +444,28 @@ namespace Isis {
gp->findKeyword("LocalRadius").setValue(toString(
m_camera->LocalRadius().meters()), "meters");
-
gp->findKeyword("SampleResolution").setValue(toString(
m_camera->SampleResolution()), "meters/pixel");
gp->findKeyword("LineResolution").setValue(toString(
m_camera->LineResolution()), "meters/pixel");
+ gp->findKeyword("ObliqueDetectorResolution").setValue(
+ toString(m_camera->ObliqueDetectorResolution()),"meters");
+ gp->findKeyword("ObliqueLineResolution").setValue(
+ toString(m_camera->ObliqueLineResolution()),"meters");
+ gp->findKeyword("ObliqueSampleResolution").setValue(
+ toString(m_camera->ObliqueSampleResolution()),"meters");
+ gp->findKeyword("ObliquePixelResolution").setValue(
+ toString(m_camera->ObliquePixelResolution()), "meters/pix");
+
+
//body fixed
m_camera->instrumentPosition(spB);
gp->findKeyword("SpacecraftPosition").addValue(toString(spB[0]), "km");
gp->findKeyword("SpacecraftPosition").addValue(toString(spB[1]), "km");
gp->findKeyword("SpacecraftPosition").addValue(toString(spB[2]), "km");
gp->findKeyword("SpacecraftPosition").addComment("Spacecraft Information");
-
+
double spacecraftAzi = m_camera->SpacecraftAzimuth();
if (Isis::IsValidPixel(spacecraftAzi)) {
gp->findKeyword("SpacecraftAzimuth").setValue(toString(spacecraftAzi), "DEGREE");
@@ -405,7 +485,7 @@ namespace Isis {
m_camera->SpacecraftAltitude()), "km");
gp->findKeyword("OffNadirAngle").setValue(toString(
m_camera->OffNadirAngle()), "DEGREE");
- double subspcgrdaz = m_camera->GroundAzimuth(m_camera->UniversalLatitude(),
+ double subspcgrdaz = m_camera->GroundAzimuth(m_camera->UniversalLatitude(),
m_camera->UniversalLongitude(),
ssplat, ssplon);
gp->findKeyword("SubSpacecraftGroundAzimuth").setValue(
@@ -416,7 +496,7 @@ namespace Isis {
gp->findKeyword("SunPosition").addValue(toString(sB[1]), "km");
gp->findKeyword("SunPosition").addValue(toString(sB[2]), "km");
gp->findKeyword("SunPosition").addComment("Sun Information");
-
+
double sunAzi = m_camera->SunAzimuth();
if (Isis::IsValidPixel(sunAzi)) {
gp->findKeyword("SubSolarAzimuth").setValue(toString(sunAzi), "DEGREE");
@@ -430,7 +510,7 @@ namespace Isis {
m_camera->subSolarPoint(sslat, sslon);
gp->findKeyword("SubSolarLatitude").setValue(toString(sslat), "DEGREE");
gp->findKeyword("SubSolarLongitude").setValue(toString(sslon), "DEGREE");
- double subsolgrdaz = m_camera->GroundAzimuth(m_camera->UniversalLatitude(),
+ double subsolgrdaz = m_camera->GroundAzimuth(m_camera->UniversalLatitude(),
m_camera->UniversalLongitude(),
sslat, sslon);
gp->findKeyword("SubSolarGroundAzimuth").setValue(
@@ -442,7 +522,7 @@ namespace Isis {
m_camera->IncidenceAngle()), "DEGREE");
gp->findKeyword("Emission").setValue(toString(
m_camera->EmissionAngle()), "DEGREE");
-
+
double northAzi = m_camera->NorthAzimuth();
if (Isis::IsValidPixel(northAzi)) {
gp->findKeyword("NorthAzimuth").setValue(toString(northAzi), "DEGREE");
@@ -487,22 +567,23 @@ namespace Isis {
}
- /**
+ /**
* Retrieves a pointer to the camera.
- *
- * @return @b Camera* A pointer to the Camera.
+ *
+ * @return @b Camera* A pointer to the Camera.
*/
Camera *CameraPointInfo::camera() {
return m_camera;
}
- /**
+ /**
* Retrieves a pointer to the current cube.
- *
- * @return @b Cube* A pointer to the current cube.
+ *
+ * @return @b Cube* A pointer to the current cube.
*/
Cube *CameraPointInfo::cube() {
return m_currentCube;
}
}
+
diff --git a/isis/src/base/objs/CameraPointInfo/CameraPointInfo.h b/isis/src/base/objs/CameraPointInfo/CameraPointInfo.h
index a9df9a9eaf..63a53f652d 100644
--- a/isis/src/base/objs/CameraPointInfo/CameraPointInfo.h
+++ b/isis/src/base/objs/CameraPointInfo/CameraPointInfo.h
@@ -33,12 +33,12 @@ namespace Isis {
/**
- * @brief CameraPointInfo provides quick access to the majority of information avaliable from a
+ * @brief CameraPointInfo provides quick access to the majority of information avaliable from a
* camera on a point.
*
- * CameraPointInfo provides the functionality which was a part of campt in class form. This
+ * CameraPointInfo provides the functionality which was a part of campt in class form. This
* functionality is access to the majoirty of information avaliable on any given point on an
- * image. The main difference is the use of a CubeManager within CameraPointInfo for effeciency
+ * image. The main difference is the use of a CubeManager within CameraPointInfo for effeciency
* when working with control nets and the opening of cubes several times.
*
* @author 2009-08-25 Mackenzie Boyd
@@ -77,7 +77,18 @@ namespace Isis {
* @history 2015-10-01 Jeannie Backer - Made improvements to documentation and brought code
* closer to ISIS coding standards. References #1438
* @history 2016-07-11 Curtis Rose - Added units to a few of the outputs. References #3979.
- */
+ * @history 2016-08-16 Tyler Wilson - Modified the GetPointInfo function to allow
+ * developers to specify which order CameraPointInfo fields
+ * are output for different file formats (PVL or CSV).
+ * This is managed by setting the m_csvOutput flag via
+ * the public member function SetCSVOutput. PVL is the
+ * default output format, as m_csvOuput is set to false in
+ * the constructor. The reason for this is to not to break any
+ * scripts processors might be running when outputting files in
+ * csv format. Column order is important in this case.
+ * References #476,#4100.
+ *
+ **/
class CameraPointInfo {
public:
@@ -85,6 +96,7 @@ namespace Isis {
virtual ~CameraPointInfo();
void SetCube(const QString &cubeFileName);
+ void SetCSVOutput(bool csvOutput);
PvlGroup *SetImage(const double sample, const double line,
const bool outside = false, const bool error = false);
PvlGroup *SetCenter(const bool outside = false, const bool error = false);
@@ -105,7 +117,9 @@ namespace Isis {
CubeManager *m_usedCubes;
Cube *m_currentCube;
Camera *m_camera;
+ bool m_csvOutput;
};
};
#endif
+
diff --git a/isis/src/base/objs/CameraPointInfo/CameraPointInfo.truth b/isis/src/base/objs/CameraPointInfo/CameraPointInfo.truth
index 21b2839b51..11c5dfed90 100644
--- a/isis/src/base/objs/CameraPointInfo/CameraPointInfo.truth
+++ b/isis/src/base/objs/CameraPointInfo/CameraPointInfo.truth
@@ -15,6 +15,10 @@ Group = GroundPoint
LocalRadius = 1737400.0
SampleResolution = 187.48511798825
LineResolution = 187.48511798825
+ ObliqueDetectorResolution = 187.48933248321
+ ObliquePixelResolution = 187.48933248321
+ ObliqueLineResolution = 187.48933248321
+ ObliqueSampleResolution = 187.48933248321
# Spacecraft Information
SpacecraftPosition = (216.76438021037, 54.256829538645,
@@ -73,6 +77,10 @@ Group = GroundPoint
LocalRadius = 1737400.0
SampleResolution = 187.50339379912
LineResolution = 187.50339379912
+ ObliqueDetectorResolution = 187.52061363579
+ ObliquePixelResolution = 187.52061363579
+ ObliqueLineResolution = 187.52061363579
+ ObliqueSampleResolution = 187.52061363579
# Spacecraft Information
SpacecraftPosition = (216.76438021037, 54.256829538645,
diff --git a/isis/src/base/objs/CameraStatistics/CameraStatistics.cpp b/isis/src/base/objs/CameraStatistics/CameraStatistics.cpp
index dfc288eccf..a99a427cde 100644
--- a/isis/src/base/objs/CameraStatistics/CameraStatistics.cpp
+++ b/isis/src/base/objs/CameraStatistics/CameraStatistics.cpp
@@ -93,6 +93,13 @@ namespace Isis {
m_latStat = new Statistics();
m_lonStat = new Statistics();
m_resStat = new Statistics();
+
+
+ m_obliqueResStat = new Statistics();
+ m_obliqueSampleResStat = new Statistics();
+ m_obliqueLineResStat = new Statistics();
+
+
m_sampleResStat = new Statistics();
m_lineResStat = new Statistics();
m_aspectRatioStat = new Statistics();
@@ -157,6 +164,25 @@ namespace Isis {
delete m_resStat;
m_resStat = NULL;
}
+
+
+ if (m_obliqueLineResStat != NULL) {
+ delete m_obliqueLineResStat;
+ m_obliqueLineResStat = NULL;
+
+ }
+
+ if (m_obliqueSampleResStat != NULL) {
+ delete m_obliqueSampleResStat;
+ m_obliqueSampleResStat = NULL;
+
+ }
+
+ if (m_obliqueResStat != NULL) {
+ delete m_obliqueResStat;
+ m_obliqueResStat = NULL;
+ }
+
if (m_sampleResStat != NULL) {
delete m_sampleResStat;
m_sampleResStat = NULL;
@@ -209,6 +235,14 @@ namespace Isis {
if(cam->HasSurfaceIntersection()) {
m_latStat->AddData(cam->UniversalLatitude());
m_lonStat->AddData(cam->UniversalLongitude());
+
+
+ m_obliqueResStat->AddData(cam->ObliquePixelResolution());
+ m_obliqueSampleResStat->AddData(cam->ObliqueSampleResolution());
+ m_obliqueLineResStat->AddData(cam->ObliqueLineResolution());
+
+
+
m_resStat->AddData(cam->PixelResolution());
m_sampleResStat->AddData(cam->SampleResolution());
m_lineResStat->AddData(cam->LineResolution());
@@ -219,7 +253,7 @@ namespace Isis {
m_localRaduisStat->AddData(cam->LocalRadius().meters());
// if IsValid
m_northAzimuthStat->AddData(cam->NorthAzimuth());
-
+
// if resolution not equal to -1.0
double aspectRatio = cam->LineResolution() / cam->SampleResolution();
m_aspectRatioStat->AddData(aspectRatio);
@@ -253,7 +287,7 @@ namespace Isis {
/**
* Constructs a Pvl object from the values in the various statistics objects.
* The general format will look as follows:
- *
+ *
* @code
* Group = User Parameters
* Filename (not provided for constructor w/ Camera but not filename)
@@ -344,6 +378,37 @@ namespace Isis {
pLon += constructKeyword("LongitudeAverage", m_lonStat->Average());
pLon += constructKeyword("LongitudeStandardDeviation", m_lonStat->StandardDeviation());
+ PvlGroup pObliqueSampleRes("ObliqueSampleResolution");
+ pObliqueSampleRes += constructKeyword("ObliqueSampleResolutionMinimum",
+ m_obliqueSampleResStat->Minimum(), "meters/pixel");
+ pObliqueSampleRes += constructKeyword("ObliqueSampleResolutionMaximum",
+ m_obliqueSampleResStat->Maximum(),"meters/pixel");
+ pObliqueSampleRes += constructKeyword("ObliqueSampleResolutionAverage",
+ m_obliqueSampleResStat->Average(),"meters/pixel");
+ pObliqueSampleRes += constructKeyword("ObliqueSampleResolutionStandardDeviation",
+ m_obliqueSampleResStat->StandardDeviation(), "meters/pixel");
+
+ PvlGroup pObliqueLineRes("ObliqueLineResolution");
+ pObliqueLineRes += constructKeyword("ObliqueLineResolutionMinimum", m_obliqueLineResStat->Minimum(),
+ "meters/pixel");
+ pObliqueLineRes += constructKeyword("ObliqueLineResolutionMaximum", m_obliqueLineResStat->Maximum(),
+ "meters/pixel");
+ pObliqueLineRes += constructKeyword("ObliqueLineResolutionAverage", m_obliqueLineResStat->Average(),
+ "meters/pixel");
+ pObliqueLineRes += constructKeyword("ObliqueLineResolutionStandardDeviation",
+ m_obliqueLineResStat->StandardDeviation(), "meters/pixel");
+
+ PvlGroup pObliqueResolution("ObliqueResolution");
+ pObliqueResolution += constructKeyword("ObliqueResolutionMinimum", m_obliqueResStat->Minimum(),
+ "meters/pixel");
+ pObliqueResolution += constructKeyword("ObliqueResolutionMaximum", m_obliqueResStat->Maximum(),
+ "meters/pixel");
+ pObliqueResolution += constructKeyword("ObliqueResolutionAverage", m_obliqueResStat->Average(),
+ "meters/pixel");
+ pObliqueResolution += constructKeyword("ObliqueResolutionStandardDeviation",
+ m_obliqueResStat->StandardDeviation(), "meters/pixel");
+
+
PvlGroup pSampleRes("SampleResolution");
pSampleRes += constructKeyword("SampleResolutionMinimum", m_sampleResStat->Minimum(),
"meters/pixel");
@@ -433,6 +498,11 @@ namespace Isis {
returnPvl.addGroup(pSampleRes);
returnPvl.addGroup(pLineRes);
returnPvl.addGroup(pResolution);
+
+ returnPvl.addGroup(pObliqueSampleRes);
+ returnPvl.addGroup(pObliqueLineRes);
+ returnPvl.addGroup(pObliqueResolution);
+
returnPvl.addGroup(pAspectRatio);
returnPvl.addGroup(pPhase);
returnPvl.addGroup(pEmission);
diff --git a/isis/src/base/objs/CameraStatistics/CameraStatistics.h b/isis/src/base/objs/CameraStatistics/CameraStatistics.h
index fb540d2d1a..12ff7f53d2 100644
--- a/isis/src/base/objs/CameraStatistics/CameraStatistics.h
+++ b/isis/src/base/objs/CameraStatistics/CameraStatistics.h
@@ -49,9 +49,11 @@ namespace Isis {
*
* @internal
* @history 2011-06-14 Travis Addair - Extracted logic from "camstats"
- * application to create this class.
+ * application to create this class.
+ * @history 2016-08-17 Tyler Wilson - Added Statistics objects for
+ * ObliquePixelResolution,ObliqueSampleResolution, and
+ * ObliqueLineResolution. References #476, #4100.
*/
-
class CameraStatistics {
public:
CameraStatistics(QString filename, int sinc, int linc);
@@ -87,6 +89,7 @@ namespace Isis {
};
+
/**
* Accessor method for inspecting the statistics gathered on the
* Pixel Resolutions of the input Camera.
@@ -98,6 +101,41 @@ namespace Isis {
};
+
+ /**
+ * Accessor method for inspecting the statistics gathered on the
+ * oblique pixel resolutions of the input Camera.
+ *
+ * @return Statistics * Constant pointer to oblique pixel resolution statistics
+ */
+ const Statistics * getObliqueResStat() const {
+ return m_obliqueResStat;
+ };
+
+ /**
+ * Accessor method for inspecting the statistics gathered on the
+ * oblique sample resolutions of the input Camera.
+ *
+ * @return Statistics * Constant pointer to oblique sample resolution statistics
+ */
+ const Statistics * getObliqueSampleResStat() const {
+ return m_obliqueSampleResStat;
+ };
+
+
+
+ /**
+ * Accessor method for inspecting the statistics gathered on the
+ * oblique line resolution of the input Camera.
+ *
+ * @return Statistics * Constant pointer to oblique line resolution statistics
+ */
+ const Statistics * getObliqueLineResStat() const {
+ return m_obliqueLineResStat;
+ };
+
+
+
/**
* Accessor method for inspecting the statistics gathered on the
* Sample Resolutions of the input Camera.
@@ -206,6 +244,13 @@ namespace Isis {
Statistics *m_latStat; //!< Universal latitude statistics.
Statistics *m_lonStat; //!< Universal longitude statistics.
+
+
+
+ Statistics *m_obliqueResStat; //!< Oblique pixel resolution statistics.
+ Statistics *m_obliqueSampleResStat; //!< Oblique sample resolution statistics.
+ Statistics *m_obliqueLineResStat; //!< Oblique line resolution statistics.
+
Statistics *m_resStat; //!< Pixel resolution statistics.
Statistics *m_sampleResStat; //!< Sample resolution statistics.
Statistics *m_lineResStat; //!< Line resolution statistics.
@@ -220,3 +265,4 @@ namespace Isis {
};
#endif
+
diff --git a/isis/src/base/objs/CameraStatistics/CameraStatistics.truth b/isis/src/base/objs/CameraStatistics/CameraStatistics.truth
index ac0d219fca..4136247568 100644
--- a/isis/src/base/objs/CameraStatistics/CameraStatistics.truth
+++ b/isis/src/base/objs/CameraStatistics/CameraStatistics.truth
@@ -36,6 +36,24 @@ Resolution:
ResolutionAverage = 245.015
ResolutionStandardDeviation = 0.181039
+ObliqueSampleResolution:
+ ObliqueSampleResolutionMinimum = 244.735
+ ObliqueSampleResolutionMaximum = 246.319
+ ObliqueSampleResolutionAverage = 245.205
+ ObliqueSampleResolutionStandardDeviation = 0.304432
+
+ObliqueLineResolution:
+ ObliqueLineResolutionMinimum = 244.735
+ ObliqueLineResolutionMaximum = 246.319
+ ObliqueLineResolutionAverage = 245.205
+ ObliqueLineResolutionStandardDeviation = 0.304432
+
+ObliqueResolution:
+ ObliqueResolutionMinimum = 244.735
+ ObliqueResolutionMaximum = 246.319
+ ObliqueResolutionAverage = 245.205
+ ObliqueResolutionStandardDeviation = 0.304432
+
AspectRatio:
AspectRatioMinimum = 1
AspectRatioMaximun = 1
diff --git a/isis/src/base/objs/Gui/Gui.cpp b/isis/src/base/objs/Gui/Gui.cpp
index da58ddf03c..57eb94e5e3 100644
--- a/isis/src/base/objs/Gui/Gui.cpp
+++ b/isis/src/base/objs/Gui/Gui.cpp
@@ -78,6 +78,9 @@ namespace Isis {
// Create the application
new QApplication(argc, argv);
+ // When QApplication is initialized, it will reset the locale to the shells locale. As a result
+ // the locale needs to be reset after QApplications initialization.
+ std::setlocale(LC_ALL, "en_US");
QCoreApplication::setApplicationName(FileName(argv[0]).baseName());
QApplication::setQuitOnLastWindowClosed(true);
diff --git a/isis/src/base/objs/Gui/Gui.h b/isis/src/base/objs/Gui/Gui.h
index 6a9824abce..44f38b51d1 100644
--- a/isis/src/base/objs/Gui/Gui.h
+++ b/isis/src/base/objs/Gui/Gui.h
@@ -78,7 +78,9 @@ namespace Isis {
* also update exclusions for boolean widgets. References
* #1452.
* @history 2016-06-28 Adam Paquette - Modified UpdateHistory to appropriately
- * retrieve lists from the history pvl
+ * retrieve lists from the history pvl.
+ * @history 2016-08-15 Adam Paquette - Reset locale after QApplication is
+ * instantiated. Fixes #3908.
*/
class Gui : public QMainWindow {
diff --git a/isis/src/base/objs/ProcessByTile/unitTest.cpp b/isis/src/base/objs/ProcessByTile/unitTest.cpp
index 9e076b3a42..c45f22f4b7 100644
--- a/isis/src/base/objs/ProcessByTile/unitTest.cpp
+++ b/isis/src/base/objs/ProcessByTile/unitTest.cpp
@@ -177,11 +177,11 @@ void IsisMain() {
p.EndProcess();
p.Finalize();
- //Isis::Cube cube;
- //cube.open("$temporary/isisProcessByTile_01");
- //cube.close(true);
- //cube.open("$temporary/isisProcessByTile_02");
- //cube.close(true);
+ Isis::Cube cube;
+ cube.open("$temporary/isisProcessByTile_01");
+ cube.close(true);
+ cube.open("$temporary/isisProcessByTile_02");
+ cube.close(true);
}
void inPlaceFunction(Isis::Buffer &in){
diff --git a/isis/src/base/objs/RadarGroundMap/RadarGroundMap.cpp b/isis/src/base/objs/RadarGroundMap/RadarGroundMap.cpp
index 2533bbb439..5587c882e3 100644
--- a/isis/src/base/objs/RadarGroundMap/RadarGroundMap.cpp
+++ b/isis/src/base/objs/RadarGroundMap/RadarGroundMap.cpp
@@ -328,6 +328,8 @@ namespace Isis {
if(dp < 0.0 && p_lookDirection == Radar::Right) return false;
if(dp == 0.0) return false;
+
+
// Compute body fixed look direction
std::vector lookB;
lookB.resize(3);
@@ -336,7 +338,7 @@ namespace Isis {
lookB[2] = X[2] - Xsc[2];
std::vector lookJ = bodyFrame->J2000Vector(lookB);
- SpiceRotation *cameraFrame = p_camera->instrumentRotation();
+ SpiceRotation *cameraFrame = p_camera->instrumentRotation(); //this is the pointer to the camera's SpiceRotation/instrumentatrotation object
std::vector lookC = cameraFrame->ReferenceVector(lookJ);
SpiceDouble unitLookC[3];
@@ -346,7 +348,10 @@ namespace Isis {
p_focalPlaneX = p_slantRange * 1000.0 / p_rangeSigma; // km to meters and scaled to focal plane
p_focalPlaneY = 0.0;
p_camera->target()->shape()->setSurfacePoint(surfacePoint); // Added 2-11-2013 by DAC
- return true;
+
+ // set the sensor's ground point and also makes it possible to calculate m_ra & m_dec
+
+ return p_camera->Sensor::SetGround(surfacePoint, true);
}
}
diff --git a/isis/src/base/objs/RadarGroundMap/RadarGroundMap.h b/isis/src/base/objs/RadarGroundMap/RadarGroundMap.h
index 8f95a72ee3..f7980a2538 100644
--- a/isis/src/base/objs/RadarGroundMap/RadarGroundMap.h
+++ b/isis/src/base/objs/RadarGroundMap/RadarGroundMap.h
@@ -101,7 +101,9 @@ namespace Isis {
* @history 2012-07-06 Debbie A. Cook, Updated Spice members to be more compliant with Isis
* coding standards. References #972.
* @history 2013-02-11 Debbie A. Cook, Fixed SetGround method by adding call to set the surface point
- in the ShapeModel so that photometric angles can be calculated. References #775
+ * in the ShapeModel so that photometric angles can be calculated. References #775
+ * @history 2016-07-19 Kristin Berry, Updated SetGround to call p_camera->Sensor::SetGround so that
+ * RA, DEC values will be set on level 2 images. References #2400.
*/
class RadarGroundMap : public CameraGroundMap {
public:
diff --git a/isis/src/base/objs/RadarSlantRangeMap/RadarSlantRangeMap.cpp b/isis/src/base/objs/RadarSlantRangeMap/RadarSlantRangeMap.cpp
index adc35683db..0123347775 100644
--- a/isis/src/base/objs/RadarSlantRangeMap/RadarSlantRangeMap.cpp
+++ b/isis/src/base/objs/RadarSlantRangeMap/RadarSlantRangeMap.cpp
@@ -26,6 +26,8 @@
#include "iTime.h"
#include "PvlSequence.h"
+using namespace std;
+
namespace Isis {
/** Radar ground to slant range map constructor
*
@@ -50,12 +52,13 @@ namespace Isis {
// allow for solving for coordinates that are slightly outside of
// the actual image area. Use S=-0.25*p_camera->Samples() and
// S=1.25*p_camera->Samples().
- p_initialMinGroundRangeGuess = (-0.25 * p_camera->Samples() - 1.0)
- * groundRangeResolution;
- p_initialMaxGroundRangeGuess = (1.25 * p_camera->Samples() - 1.0)
- * groundRangeResolution;
+ // The above approach works nicely for a level 1 image but the
+ // sensor model at level2 doesn't have access to the level 1
+ // number of samples. Instead, we will calculate initial guesses
+ // on the fly in SetUndistortedFocalPlane.
p_tolerance = 0.1; // Default tolerance is a tenth of a meter
p_maxIterations = 30;
+
}
/** Set the ground range and compute a slant range
@@ -85,20 +88,92 @@ namespace Isis {
if(p_et != p_camera->time().Et()) ComputeA();
- // Evaluate the ground range at the 2 extremes of the image
double slant = p_undistortedFocalPlaneX;
+ // First trap the case where no iteration is needed. Since this occurs at
+ // the first pixel of the image, it's a real possibility to encounter.
+ if (fabs(slant-p_a[0]) < p_tolerance) {
+ p_focalPlaneX = 0.0;
+ p_focalPlaneY = 0.0;
+ return true;
+ }
+ // Now calculate two guesses by the first and second iterations of
+ // Newton's method, where the zeroth iteration is at ground range = 0.
+ // The nature of the slant range function is such that, in the region
+ // of validity (including all image data) the Newton approximations are
+ // always too high, but the second one is within a few meters. We therefore
+ // add 10 m of “windage” to it to bracket the root.
+ // Performing a third Newton iteration would give a satisfactory solution in
+ // the data area but raises the problem of trapping errors outside this region
+ // where the polynomial is not so well behaved.
+ // Use the “min” variables temporarily to hold the first approximation
+ p_initialMinGroundRangeGuess = (slant - p_a[0]) / p_a[1];
double minGroundRangeGuess = slant - (p_a[0] + p_initialMinGroundRangeGuess *
- (p_a[1] + p_initialMinGroundRangeGuess * (p_a[2] +
- p_initialMinGroundRangeGuess * p_a[3])));
+ (p_a[1] + p_initialMinGroundRangeGuess * (p_a[2] + p_initialMinGroundRangeGuess * p_a[3])));
+ // Now the max is the second approximation
+ p_initialMaxGroundRangeGuess = p_initialMinGroundRangeGuess + minGroundRangeGuess /
+ (p_a[1] + p_initialMinGroundRangeGuess * (2.0 * p_a[2] + p_initialMinGroundRangeGuess *
+ 3.0 * p_a[3]));
double maxGroundRangeGuess = slant - (p_a[0] + p_initialMaxGroundRangeGuess *
(p_a[1] + p_initialMaxGroundRangeGuess * (p_a[2] +
p_initialMaxGroundRangeGuess * p_a[3])));
+ // Finally, apply the “windage” to bracket the root.
+ p_initialMinGroundRangeGuess = p_initialMaxGroundRangeGuess - 10.0;
+ minGroundRangeGuess = slant - (p_a[0] + p_initialMinGroundRangeGuess *
+ (p_a[1] + p_initialMinGroundRangeGuess * (p_a[2] + p_initialMinGroundRangeGuess * p_a[3])));
+
+ // If both guesses are on the same side of zero, we need to expand the bracket range
+ // to include a zero-crossing.
+ if ((minGroundRangeGuess < 0.0 && maxGroundRangeGuess < 0.0) ||
+ (minGroundRangeGuess > 0.0 && maxGroundRangeGuess > 0.0)) {
+ int maxBracketIters = 10;
+
+ float xMin = p_initialMinGroundRangeGuess;
+ float xMax = p_initialMaxGroundRangeGuess;
+
+ float funcMin = minGroundRangeGuess;
+ float funcMax = maxGroundRangeGuess;
+
+ for (int j=0; j= 0.0) || (funcMin >= 0.0 && funcMax <= 0.0)){
+ p_initialMinGroundRangeGuess = xMin;
+ p_initialMaxGroundRangeGuess = xMax;
+ minGroundRangeGuess = funcMin;
+ maxGroundRangeGuess = funcMax;
+ break;
+ }
+ }
+ }
+
// If the ground range guesses at the 2 extremes of the image are equal
// or they have the same sign, then the ground range cannot be solved for.
+ // The only case where they are equal should be at zero, which we already trapped.
if((minGroundRangeGuess == maxGroundRangeGuess) ||
(minGroundRangeGuess < 0.0 && maxGroundRangeGuess < 0.0) ||
- (minGroundRangeGuess > 0.0 && maxGroundRangeGuess > 0.0)) return false;
+ (minGroundRangeGuess > 0.0 && maxGroundRangeGuess > 0.0)) {
+ return false;
+ }
// Use Wijngaarden/Dekker/Brent algorithm to find a root of the function:
// g(groundRange) = slantRange - (p_a[0] + groundRange * (p_a[1] +
diff --git a/isis/src/base/objs/RadarSlantRangeMap/RadarSlantRangeMap.h b/isis/src/base/objs/RadarSlantRangeMap/RadarSlantRangeMap.h
index cab974cfc2..0844c5424a 100644
--- a/isis/src/base/objs/RadarSlantRangeMap/RadarSlantRangeMap.h
+++ b/isis/src/base/objs/RadarSlantRangeMap/RadarSlantRangeMap.h
@@ -55,7 +55,13 @@ namespace Isis {
* known range coefficients.
* @history 2012-07-06 Debbie A. Cook, Updated Spice members to be more compliant with Isis
* coding standards. References #972.
- *
+ * @history 2016-02-24 Randy Kirk and Janet Barrett - Fixed an issue that caused
+ * the sensor model for LRO and Chandrayaan's MiniRF to not be able to
+ * calculate and report lat/lon in the LXB mode. References #2400.
+ * @history 2016-08-01 Kristin Berry - Added the ability to extend the range of the initial root
+ * bracket in SetUndistortedFocalPlan if the initial range was too narrow.
+ * Also added RAs & DECs to the camera model.References #2400.
+ *
*/
class RadarSlantRangeMap : public CameraDistortionMap {
public:
diff --git a/isis/src/chandrayaan1/objs/Chandrayaan1M3Camera/Chandrayaan1M3Camera.h b/isis/src/chandrayaan1/objs/Chandrayaan1M3Camera/Chandrayaan1M3Camera.h
index ea549da040..bd0002c79d 100644
--- a/isis/src/chandrayaan1/objs/Chandrayaan1M3Camera/Chandrayaan1M3Camera.h
+++ b/isis/src/chandrayaan1/objs/Chandrayaan1M3Camera/Chandrayaan1M3Camera.h
@@ -41,6 +41,8 @@ namespace Isis {
* @history 2015-10-16 Ian Humphrey - Removed declarations of spacecraft and instrument
* members and methods and removed implementation of these methods
* since Camera now handles this. References #2335.
+ * @history 2016-08-01 Kristin Berry - Added to unitTest to test camera model performance on
+ * level 2 cubes and to test RA/DEC values. References #2400.
*/
class Chandrayaan1M3Camera : public LineScanCamera {
public:
diff --git a/isis/src/chandrayaan1/objs/Chandrayaan1M3Camera/Chandrayaan1M3Camera.truth b/isis/src/chandrayaan1/objs/Chandrayaan1M3Camera/Chandrayaan1M3Camera.truth
index 243651cc89..1f851a4ecc 100644
--- a/isis/src/chandrayaan1/objs/Chandrayaan1M3Camera/Chandrayaan1M3Camera.truth
+++ b/isis/src/chandrayaan1/objs/Chandrayaan1M3Camera/Chandrayaan1M3Camera.truth
@@ -32,3 +32,10 @@ DeltaLine = 0.000000000
For center pixel position ...
Latitude OK
Longitude OK
+RightAscension = 242.182569911
+Declination = -84.617919659
+
+Testing a Level-2 CH1 cube:
+
+For a central pixel position ...
+SetImage succeeded.
diff --git a/isis/src/chandrayaan1/objs/Chandrayaan1M3Camera/unitTest.cpp b/isis/src/chandrayaan1/objs/Chandrayaan1M3Camera/unitTest.cpp
index 892e96cf24..b02c9b5454 100644
--- a/isis/src/chandrayaan1/objs/Chandrayaan1M3Camera/unitTest.cpp
+++ b/isis/src/chandrayaan1/objs/Chandrayaan1M3Camera/unitTest.cpp
@@ -101,6 +101,30 @@ int main(void) {
else {
cout << setprecision(16) << "Longitude off by: " << cam->UniversalLongitude() - knownLon << endl;
}
+
+ cout << "RightAscension = " << cam->RightAscension() << endl;
+ cout << "Declination = " << cam->Declination() << endl;
+
+ // Test a Level-2 image
+ cout << endl << "Testing a Level-2 CH1 cube: " << endl << endl;
+
+ Cube c2("$chandrayaan1/testData/CH1_xBandLvl2.cub", "r");
+ Camera *cam2 = CameraFactory::Create(c2);
+
+ // Just test the center pixel to make sure the Camera still works on Level-2
+ // images
+
+ cout << "For a central pixel position ..." << endl;
+ samp = 2000;
+ line = 2500;
+
+ if (!cam2->SetImage(samp, line)) {
+ cout << "ERROR" << endl;
+ return 0;
+ }
+ else {
+ cout << "SetImage succeeded." << endl;
+ }
}
catch (IException &e) {
e.print();
diff --git a/isis/src/control/apps/cnettable/cnettable.cpp b/isis/src/control/apps/cnettable/cnettable.cpp
index 9c793d11b5..ff03024771 100644
--- a/isis/src/control/apps/cnettable/cnettable.cpp
+++ b/isis/src/control/apps/cnettable/cnettable.cpp
@@ -1,5 +1,6 @@
#include "Isis.h"
+
#include "CameraPointInfo.h"
#include "ControlMeasure.h"
#include "ControlMeasureLogData.h"
@@ -20,6 +21,7 @@
#include "SurfacePoint.h"
#include "TextFile.h"
#include "UserInterface.h"
+//#include "LocalPointInfo.h"
#include
#include
@@ -84,7 +86,9 @@ void IsisMain() {
}
PvlGroup * grp = NULL;
+
CameraPointInfo camPoint;
+ camPoint.SetCSVOutput(true);
outside = ui.GetBoolean("ALLOWOUTSIDE");
errors = ui.GetBoolean("ALLOWERRORS");
diff --git a/isis/src/control/apps/cnettable/cnettable.xml b/isis/src/control/apps/cnettable/cnettable.xml
index 25c2b5f65e..03717ef93d 100644
--- a/isis/src/control/apps/cnettable/cnettable.xml
+++ b/isis/src/control/apps/cnettable/cnettable.xml
@@ -1,6 +1,7 @@
-
+
Application to get Excel compatible statistics
@@ -125,6 +126,11 @@
Updated truth data due to modifications, printing NULL instead of N/A. References #1659.
+
+ Updated application truth data due to modifications in CameraPointInfo class.
+ References #476.
+
+
diff --git a/isis/src/docsys/Object/build/isisDoxyDefs.doxydef b/isis/src/docsys/Object/build/isisDoxyDefs.doxydef
index 6456f03085..2d1a824c3a 100644
--- a/isis/src/docsys/Object/build/isisDoxyDefs.doxydef
+++ b/isis/src/docsys/Object/build/isisDoxyDefs.doxydef
@@ -97,7 +97,8 @@
* @history 2008-05-19 steven lambright - Fixed Mission End Group Tag
* @history 2008-05-19 steven lambright - Fixed Bad Namespace Documentation
* @history 2013-03-27 Jeannie Backer - Added NEAR Shoemaker mission. References #1248.
- *
+ * @history 2016-08-25 Marjorie Hahn - Added OSIRIS-REx mission. References #4300.
+ *
* @todo Develop two different pages for API vs. Programmer
* documentation. 2004-11-03
* @todo Make "std" namespace invisible... probably not gonna happen
@@ -390,7 +391,6 @@
*
*/
-
// MRO
/**
* \defgroup MarsReconnaissanceOrbiter Mars Reconnaissance Orbiter
@@ -439,7 +439,6 @@
*
*/
-
// New Horizons
/**
* \defgroup NewHorizons New Horizons
@@ -447,15 +446,28 @@
* These objects provide functionality for manipulating data from the
* New Horizons mission. New Horizons is part of NASA's New Frontiers
* Program.
- * New Horizons launced January 19, 2006 and is expected to spend five months studying
+ * New Horizons launched January 19, 2006 and is expected to spend five months studying
* Pluto durring the summer of 2015.
*
* Mission site: http://www.nasa.gov/mission_pages/newhorizons/main/#.VA4QY8NuH4I
*
+ */
+
+ // OSIRIS-REx
+ /**
+ * \defgroup OSIRIS-REx OSIRIS-REx
+ *
+ * These objects provide functionality for manipulating data from the
+ * OSIRIS-REx asteroid sample return mission. The 2016 OSIRIS-REx mission's
+ * key objectives include mapping out the asteroid Bennu's surface, analyzing
+ * a sample of Bennu's regolith, documenting the sample site, calculating Bennu's
+ * orbit deviation, and comparing observations made at the asteroid to observations
+ * made on Earth.
+ *
+ * Mission site: http://www.asteroidmission.org/
*
*/
-
-
+
// VIKING
/**
* \defgroup Viking Viking
@@ -491,8 +503,6 @@
*
*/
-
-
// LUNAR ORBITER
/**
* \defgroup LunarOrbiter Lunar Orbiter
@@ -517,9 +527,6 @@
*
*/
-
-
-
/* @} end of Missions group */
diff --git a/isis/src/docsys/Schemas/Application/application.xsd b/isis/src/docsys/Schemas/Application/application.xsd
index a28ab7c826..1de901fd90 100644
--- a/isis/src/docsys/Schemas/Application/application.xsd
+++ b/isis/src/docsys/Schemas/Application/application.xsd
@@ -35,6 +35,9 @@
2016-03-29 Kristin Berry - Added missionItem_type enummeration for Rosetta.
+
+ 2016-08-25 Marjorie Hahn - Added missionItem_type enummeration for OSIRIS-REx.
+
XML file describing an Isis application
@@ -449,6 +452,7 @@
+
diff --git a/isis/src/docsys/Schemas/Application/documentation/index.html b/isis/src/docsys/Schemas/Application/documentation/index.html
index 21e830dd75..905e7f9324 100644
--- a/isis/src/docsys/Schemas/Application/documentation/index.html
+++ b/isis/src/docsys/Schemas/Application/documentation/index.html
@@ -431,7 +431,23 @@
| facets |
- | enumeration | Cassini | | enumeration | Clementine | | enumeration | Mariner | | enumeration | Galileo | | enumeration | Lunar Orbiter | | enumeration | Lunar Reconnaissance Orbiter | | enumeration | Mars Reconnaissance Orbiter | | enumeration | Mars Global Surveyor | | enumeration | Mars Odyssey | | enumeration | Mars Exploration Rover | | enumeration | Messenger | | enumeration | Small Missions for Advanced Research and Technology 1 | | enumeration | Voyager | | enumeration | Viking |
|
+
+ | enumeration | Cassini |
+ | enumeration | Clementine |
+ | enumeration | Mariner |
+ | enumeration | Galileo |
+ | enumeration | Lunar Orbiter |
+ | enumeration | Lunar Reconnaissance Orbiter |
+ | enumeration | Mars Reconnaissance Orbiter |
+ | enumeration | Mars Global Surveyor |
+ | enumeration | Mars Odyssey |
+ | enumeration | Mars Exploration Rover |
+ | enumeration | Messenger |
+ | enumeration | OSIRIS-REx |
+ | enumeration | Small Missions for Advanced Research and Technology 1 |
+ | enumeration | Voyager |
+ | enumeration | Viking |
+ |
| annotation |
@@ -3337,7 +3353,23 @@
| facets |
- | enumeration | Cassini | | enumeration | Clementine | | enumeration | Mariner | | enumeration | Galileo | | enumeration | Lunar Orbiter | | enumeration | Lunar Reconnaissance Orbiter | | enumeration | Mars Reconnaissance Orbiter | | enumeration | Mars Global Surveyor | | enumeration | Mars Odyssey | | enumeration | Mars Exploration Rover | | enumeration | Messenger | | enumeration | Small Missions for Advanced Research and Technology 1 | | enumeration | Voyager | | enumeration | Viking |
|
+
+ | enumeration | Cassini |
+ | enumeration | Clementine |
+ | enumeration | Mariner |
+ | enumeration | Galileo |
+ | enumeration | Lunar Orbiter |
+ | enumeration | Lunar Reconnaissance Orbiter |
+ | enumeration | Mars Reconnaissance Orbiter |
+ | enumeration | Mars Global Surveyor |
+ | enumeration | Mars Odyssey |
+ | enumeration | Mars Exploration Rover |
+ | enumeration | Messenger |
+ | enumeration | OSIRIS-REx |
+ | enumeration | Small Missions for Advanced Research and Technology 1 |
+ | enumeration | Voyager |
+ | enumeration | Viking |
+ |
| annotation |
@@ -3361,6 +3393,7 @@
<xs:enumeration value="Mars Odyssey"/>
<xs:enumeration value="Mars Exploration Rover"/>
<xs:enumeration value="Messenger"/>
+ <xs:enumeration value="OSIRIS-REx"/>
<xs:enumeration value="Small Missions for Advanced Research and Technology 1"/>
<xs:enumeration value="Voyager"/>
<xs:enumeration value="Viking"/>
diff --git a/isis/src/docsys/documents/Glossary/Glossary.xml b/isis/src/docsys/documents/Glossary/Glossary.xml
index 91f7967b28..b4423e5d66 100644
--- a/isis/src/docsys/documents/Glossary/Glossary.xml
+++ b/isis/src/docsys/documents/Glossary/Glossary.xml
@@ -310,7 +310,7 @@
-
+
The emission angle (EMA) is the angle between the spacecraft and a
vector drawn perpendicular to the planet's surface (surface normal).
Using SPICE, ISIS applications compute this angle from the ellipsoid.
@@ -344,24 +344,112 @@
-
+
The ground distance in meters from the left edge to the right edge
of a pixel.
-
- The ground distance in meters from the top edge to the bottom edge
- of a pixel.
+
+ The ground distance (in meters) from the left edge to the right edge
+ of a pixel. This value is based on the oblique detector resolution
+ estimate, rather than the detector resolution and is more accurate
+ (particularly for off-nadir images).
-
- The ground distance in meters from the left edge to the right edge
+
+
+
+ The ground distance (in meters) from the top edge to the bottom edge
of a pixel.
-
- The size of the detector on the focal plane for each pixel.
-
+
+ The ground distance (in meters) from the top edge to the bottom edge
+ of a pixel. This value is based on the oblique detector resolution
+ estimate, rather than the detector resolution and is more
+ accurate (particularly for off-nadir images).
+
+
+
+
+
+
+ The ground distance (in meters) from the left edge to the right edge
+ of a pixel.
+
+
+
+ The ground distance (in meters) from the left edge to the right edge
+ of a pixel. This value is based on the oblique detector resolution
+ estimate, rather than the detector resolution and is more
+ accurate (particularly for off-nadir images).
+
+
+
+
+
+ The ground distance in meters from the left edge to the right edge of a detector. If the
+ lines and samples are not being summed and averaged, this value is equal to the pixel resolution.
+ The formula for estimating this value works well if the image is taken near nadir, but
+ the accuracy falls off rapidly the farther off-nadir the image is taken. For an estimate that
+ handles off-nadir images with higher accuracy, one should use oblique detector resolution.
+
+
+
+ This provides an improved estimate to the standard detector resolution when the image is taken at an oblique
+ angle. It returns the square-root of the area of the projection of the detector onto the body of the target (in units of meters).
+ If the image is taken at nadir, this is the ground distance between the left and right edge of the detector, because the
+ detector's projection is a square. For off-nadir images, the projection has a trapezoidal shape.
+ In Figure 1A below, an image of the Dufay X crater that was taken near nadir is displayed. Figure 1B is a
+ color map showing the relative difference between the oblique detector resolution, and the original detector resolution as a function
+ of the emission angle. For small emission angles (near nadir) the relative difference between the two estimates
+ is very small. For larger emission angles (off-nadir), the relative difference between the
+ two estimates increases rapidly. Figure 2A is an image of the Carlini crater group taken at an oblique angle. Figure 2B is a color plot
+ of the relative difference between the two estimates showing a minimum value of approximately 50% between the two when the
+ emission angles off-nadir are in the range 65-75 degrees.
+
+
+
+
+
+
+
+ Fig 1A: A cropped view of Apollo image AS16-M-0025 centered on the Dufay X crater. The spacecraft
+ was very close to nadir when the image was taken.
+
+
+
+ |
+
+
+
+ Fig 2A: A cropped view of Apollo image AS15-M-1556 centered on the Carlini crater group.
+ This photo was taken at an oblique angle.
+
+
+
+ |
+
+
+
+
+
+ Fig 1B: Relative percentage difference between resolution estimates for
+ a nadir image (see Fig. 1A).
+
+
+ |
+
+
+
+ Fig 2B: Relative percentage difference between resolution estimates for
+ an oblique image (see Fig. 2A).
+
+
+ |
+
+
+
Irradiance/SolarFlux. Unit of DN values for a reference distance of
diff --git a/isis/src/docsys/documents/Glossary/assets/carlini_craters.png b/isis/src/docsys/documents/Glossary/assets/carlini_craters.png
new file mode 100644
index 0000000000000000000000000000000000000000..8fd94695029a4d91689de32cbd9eeaac60774529
GIT binary patch
literal 288282
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
z
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